blob: d06266d65f560bdb0e28817f40463e1707d6d083 [file] [log] [blame]
// Copyright (c) 2021, 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 'dart:convert';
import 'exceptions.dart';
/// A base class for (spec-generated) classes that represent the `body` of a an
/// event.
abstract class EventBody {
static bool canParse(Object? obj) => obj is Map<String, Object?>?;
}
/// A generic event body class that just supplies an object directly.
///
/// Used to support custom events sent by the debug adapter such as 'dart.log'.
///
/// The supplied [body] must be convertible to JSON.
class RawEventBody extends EventBody {
final Object body;
RawEventBody(this.body)
: assert(() {
try {
jsonEncode(body);
return true;
} catch (e) {
return false;
}
}(), 'body should be JSON encodable');
Object toJson() => body;
}
/// A generic arguments class that just supplies the arguments map directly.
///
/// Used to support custom requests that may be provided by other implementing
/// adapters that are not known at compile time by DDS/base DAP.
class RawRequestArguments extends RequestArguments {
final Map<String, Object?> args;
RawRequestArguments.fromMap(this.args);
static RawRequestArguments fromJson(Map<String, Object?> obj) =>
RawRequestArguments.fromMap(obj);
}
/// A base class for (spec-generated) classes that represent the `arguments` of
/// a request.
abstract class RequestArguments {
static bool canParse(Object? obj) => obj is Map<String, Object?>?;
}
/// A helper for reading arguments for DAP requests from the client.
class DebugAdapterArgumentReader {
final String request;
DebugAdapterArgumentReader(this.request);
/// Reads a value of type [T] from [field] in [obj].
T read<T>(
Map<String, Object?> obj,
String field,
) {
final value = obj[field];
if (value is! T) {
throw DebugAdapterInvalidArgumentException(
requestName: request,
argumentName: field,
expectedType: T,
actualType: value.runtimeType,
actualValue: value,
);
}
return obj[field] as T;
}
/// Reads a List of values of type [T] from [field] in [obj].
List<T> readList<T>(
Map<String, Object?> obj,
String field,
) {
final value = obj[field];
if (value is! List || !value.every((element) => element is T)) {
throw DebugAdapterInvalidArgumentException(
requestName: request,
argumentName: field,
expectedType: List<T>,
actualType: value.runtimeType,
actualValue: value,
);
}
return (obj[field] as List<Object?>).cast<T>();
}
/// Reads an optional List of values of type [T] from [field] in [obj].
List<T>? readOptionalList<T>(
Map<String, Object?> obj,
String field,
) {
return obj.containsKey(field) ? readList<T>(obj, field) : null;
}
/// Reads an optional Map of types [K],[V] from [field] in [obj].
Map<K, V>? readOptionalMap<K, V>(
Map<String, Object?> obj,
String field,
) {
return obj.containsKey(field) ? readMap<K, V>(obj, field) : null;
}
/// Reads a Map of types [K],[V] from [field] in [obj].
Map<K, V> readMap<K, V>(
Map<String, Object?> obj,
String field,
) {
final value = obj[field];
if (value is! Map ||
!value.entries.every((entry) => entry.key is K && entry.value is V)) {
throw DebugAdapterInvalidArgumentException(
requestName: request,
argumentName: field,
expectedType: Map<K, V>,
actualType: value.runtimeType,
actualValue: value,
);
}
return (obj[field] as Map<Object?, Object?>).cast<K, V>();
}
}