// Copyright (c) 2023, 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?; } /// 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 args; RawRequestArguments.fromMap(this.args); static RawRequestArguments fromJson(Map 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?; } /// 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( Map 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 readList( Map 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, actualType: value.runtimeType, actualValue: value, ); } return (obj[field] as List).cast(); } /// Reads an optional List of values of type [T] from [field] in [obj]. List? readOptionalList( Map obj, String field, ) { return obj.containsKey(field) ? readList(obj, field) : null; } /// Reads an optional Map of types [K],[V] from [field] in [obj]. Map? readOptionalMap( Map obj, String field, ) { return obj.containsKey(field) ? readMap(obj, field) : null; } /// Reads a Map of types [K],[V] from [field] in [obj]. Map readMap( Map 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, actualType: value.runtimeType, actualValue: value, ); } return (obj[field] as Map).cast(); } }