blob: 1fe0dada637f54dd92e4cfee50c0b61ac53d027a [file]
// Copyright (c) 2025, 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:analysis_server/src/session_logger/entry_keys.dart' as key;
import 'package:analysis_server/src/session_logger/entry_kind.dart';
import 'package:analysis_server/src/session_logger/process_id.dart';
import 'package:language_server_protocol/protocol_special.dart' show Either2;
/// A representation of an entry in a log.
///
/// Every entry has a time and a [kind]. Other properties are dependent on the
/// [kind]. See [EntryKind] for a description of the properties associated with
/// each [kind].
extension type LogEntry(JsonMap map) {
/// Returns the command-line arguments used to start the server.
List<String> get argList =>
(map[key.argList] as List<dynamic>).cast<String>();
/// Whether this entry is a command line entry.
bool get isCommandLine => kind == EntryKind.commandLine;
/// Whether this entry is a message entry.
bool get isMessage => kind == EntryKind.message;
/// Returns the kind of this log entry.
EntryKind get kind => EntryKind.forName(map[key.kind] as String);
/// Returns the message for this log entry.
Message get message => Message(map[key.message] as JsonMap);
/// Returns the receiver of the message.
ProcessId get receiver => ProcessId.forName(map[key.receiver] as String);
/// Returns the sender of the message.
ProcessId get sender => ProcessId.forName(map[key.sender] as String);
}
/// A representation of a message sent from one process to another.
extension type Message(JsonMap map) {
/// The ID of the message. All request messages have IDs, but notifications
/// do not.
Either2<int, String>? get id {
// The id in the JSON could be either an int or String (LSP is JSON-RPC 2
// which allows either).
return switch (map['id']) {
int i => Either2<int, String>.t1(i),
String s => Either2<int, String>.t2(s),
null => null,
_ => throw Exception(
'Message ID was unexpected type ${map['id'].runtimeType}',
),
};
}
/// Whether this message is a notification that a file has changed.
bool get isDidChange => method == 'textDocument/didChange';
/// Whether this message is a notification that a file has been closed.
bool get isDidClose => method == 'textDocument/didClose';
/// Whether this message is a notification that a file has been opened.
bool get isDidOpen => method == 'textDocument/didOpen';
/// Whether this message is a request for the server to exit.
bool get isExit => method == 'exit';
/// Whether this message is a notification to the server indicating that the
/// client is initialized.
bool get isInitialized => method == 'initialized';
/// Whether this message is a request for the server to initialize itself.
bool get isInitializeRequest => method == 'initialize';
/// Whether this message is a request from the server to log a message.
bool get isLogMessage => method == 'window/logMessage';
/// Whether this message is a request for the server to connect with DTD.
bool get isRequestToConnectWithDtd => method == 'dart/connectToDtd';
/// Whether this is a response to a request.
bool get isResponse => method == null;
/// Whether this message is a request from the server to show a document to
/// the user.
bool get isShowDocument => method == 'window/showDocument';
/// Whether this message is a request from the server to show a message to the
/// user.
bool get isShowMessage => method == 'window/showMessage';
/// Whether this message is a request from the server to show a message to the
/// user.
bool get isShowMessageRequest => method == 'window/showMessageRequest';
/// Whether this message is a request for the server to shut down.
bool get isShutdown => method == 'shutdown';
/// Whether this message is a request for the server to set the configuration
/// of the workspace.
bool get isWorkspaceConfiguration => method == 'workspace/configuration';
/// The method being sent in this message, or `null` if this message isn't an
/// LSP request
String? get method => map['method'] as String?;
/// Only present if [method] is non-null, and still optional in that case.
JsonMap? get params => map['params'] as Map<String, Object?>?;
/// If [method] is null, this should be non-null.
///
/// Could be any valid type for a result, which is dependent on the [method].
Object? get result => map['result'];
/// The URI of the text document associated with this message.
///
/// Return `null` if this message is not associated with a text document.
String? get textDocument =>
(params?['textDocument'] as Map<String, Object?>?)?['uri'] as String?;
/// Whether this message is a response to the request with the [requestId].
bool isResponseTo(Either2<int, String> requestId) =>
isResponse && id == requestId;
}