| // 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>(); |
| } |
| } |