blob: 0d84d2ffafdab8711e4a22f215f4845d948d320d [file] [log] [blame]
// Copyright 2019 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_TORQUE_LS_MESSAGE_H_
#define V8_TORQUE_LS_MESSAGE_H_
#include "src/base/logging.h"
#include "src/torque/ls/json.h"
#include "src/torque/ls/message-macros.h"
#include "src/torque/source-positions.h"
namespace v8 {
namespace internal {
namespace torque {
namespace ls {
// Base class for Messages and Objects that are backed by either a
// JsonValue or a reference to a JsonObject.
// Helper methods are used by macros to implement typed accessors.
class BaseJsonAccessor {
public:
template <class T>
T GetObject(const std::string& property) {
return T(GetObjectProperty(property));
}
bool HasProperty(const std::string& property) const {
return object().count(property) > 0;
}
void SetNull(const std::string& property) {
object()[property] = JsonValue::JsonNull();
}
bool IsNull(const std::string& property) const {
return HasProperty(property) &&
object().at(property).tag == JsonValue::IS_NULL;
}
protected:
virtual const JsonObject& object() const = 0;
virtual JsonObject& object() = 0;
JsonObject& GetObjectProperty(const std::string& property) {
if (!object()[property].IsObject()) {
object()[property] = JsonValue::From(JsonObject{});
}
return object()[property].ToObject();
}
JsonArray& GetArrayProperty(const std::string& property) {
if (!object()[property].IsArray()) {
object()[property] = JsonValue::From(JsonArray{});
}
return object()[property].ToArray();
}
JsonObject& AddObjectElementToArrayProperty(const std::string& property) {
JsonArray& array = GetArrayProperty(property);
array.push_back(JsonValue::From(JsonObject{}));
return array.back().ToObject();
}
};
// Base class for Requests, Responses and Notifications.
// In contrast to "BaseObject", a Message owns the backing JsonValue of the
// whole object tree; i.e. value_ serves as root.
class Message : public BaseJsonAccessor {
public:
Message() {
value_ = JsonValue::From(JsonObject{});
set_jsonrpc("2.0");
}
explicit Message(JsonValue value) : value_(std::move(value)) {
CHECK(value_.tag == JsonValue::OBJECT);
}
JsonValue& GetJsonValue() { return value_; }
JSON_STRING_ACCESSORS(jsonrpc)
protected:
const JsonObject& object() const { return value_.ToObject(); }
JsonObject& object() { return value_.ToObject(); }
private:
JsonValue value_;
};
// Base class for complex type that might be part of a Message.
// Instead of creating theses directly, use the accessors on the
// root Message or a parent object.
class NestedJsonAccessor : public BaseJsonAccessor {
public:
explicit NestedJsonAccessor(JsonObject& object) : object_(object) {}
const JsonObject& object() const { return object_; }
JsonObject& object() { return object_; }
private:
JsonObject& object_;
};
class ResponseError : public NestedJsonAccessor {
public:
using NestedJsonAccessor::NestedJsonAccessor;
JSON_INT_ACCESSORS(code)
JSON_STRING_ACCESSORS(message)
};
class InitializeParams : public NestedJsonAccessor {
public:
using NestedJsonAccessor::NestedJsonAccessor;
JSON_INT_ACCESSORS(processId)
JSON_STRING_ACCESSORS(rootPath)
JSON_STRING_ACCESSORS(rootUri)
JSON_STRING_ACCESSORS(trace)
};
class FileListParams : public NestedJsonAccessor {
public:
using NestedJsonAccessor::NestedJsonAccessor;
// TODO(szuend): Implement read accessor for string
// arrays. "files" is managed directly.
};
class FileSystemWatcher : public NestedJsonAccessor {
public:
using NestedJsonAccessor::NestedJsonAccessor;
JSON_STRING_ACCESSORS(globPattern)
JSON_INT_ACCESSORS(kind)
enum WatchKind {
kCreate = 1,
kChange = 2,
kDelete = 4,
kAll = kCreate | kChange | kDelete,
};
};
class DidChangeWatchedFilesRegistrationOptions : public NestedJsonAccessor {
public:
using NestedJsonAccessor::NestedJsonAccessor;
JSON_ARRAY_OBJECT_ACCESSORS(FileSystemWatcher, watchers)
};
class FileEvent : public NestedJsonAccessor {
public:
using NestedJsonAccessor::NestedJsonAccessor;
JSON_STRING_ACCESSORS(uri)
JSON_INT_ACCESSORS(type)
};
class DidChangeWatchedFilesParams : public NestedJsonAccessor {
public:
using NestedJsonAccessor::NestedJsonAccessor;
JSON_ARRAY_OBJECT_ACCESSORS(FileEvent, changes)
};
class SaveOptions : public NestedJsonAccessor {
public:
using NestedJsonAccessor::NestedJsonAccessor;
JSON_BOOL_ACCESSORS(includeText)
};
class TextDocumentSyncOptions : public NestedJsonAccessor {
public:
using NestedJsonAccessor::NestedJsonAccessor;
JSON_BOOL_ACCESSORS(openClose)
JSON_INT_ACCESSORS(change)
JSON_BOOL_ACCESSORS(willSave)
JSON_BOOL_ACCESSORS(willSaveWaitUntil)
JSON_OBJECT_ACCESSORS(SaveOptions, save)
};
class ServerCapabilities : public NestedJsonAccessor {
public:
using NestedJsonAccessor::NestedJsonAccessor;
JSON_OBJECT_ACCESSORS(TextDocumentSyncOptions, textDocumentSync)
JSON_BOOL_ACCESSORS(definitionProvider)
JSON_BOOL_ACCESSORS(documentSymbolProvider)
};
class InitializeResult : public NestedJsonAccessor {
public:
using NestedJsonAccessor::NestedJsonAccessor;
JSON_OBJECT_ACCESSORS(ServerCapabilities, capabilities)
};
class Registration : public NestedJsonAccessor {
public:
using NestedJsonAccessor::NestedJsonAccessor;
JSON_STRING_ACCESSORS(id)
JSON_STRING_ACCESSORS(method)
JSON_DYNAMIC_OBJECT_ACCESSORS(registerOptions)
};
class RegistrationParams : public NestedJsonAccessor {
public:
using NestedJsonAccessor::NestedJsonAccessor;
JSON_ARRAY_OBJECT_ACCESSORS(Registration, registrations)
};
class JsonPosition : public NestedJsonAccessor {
public:
using NestedJsonAccessor::NestedJsonAccessor;
JSON_INT_ACCESSORS(line)
JSON_INT_ACCESSORS(character)
};
class Range : public NestedJsonAccessor {
public:
using NestedJsonAccessor::NestedJsonAccessor;
JSON_OBJECT_ACCESSORS(JsonPosition, start)
JSON_OBJECT_ACCESSORS(JsonPosition, end)
};
class Location : public NestedJsonAccessor {
public:
using NestedJsonAccessor::NestedJsonAccessor;
JSON_STRING_ACCESSORS(uri)
JSON_OBJECT_ACCESSORS(Range, range)
void SetTo(SourcePosition position) {
set_uri(SourceFileMap::AbsolutePath(position.source));
range().start().set_line(position.start.line);
range().start().set_character(position.start.column);
range().end().set_line(position.end.line);
range().end().set_character(position.end.column);
}
};
class TextDocumentIdentifier : public NestedJsonAccessor {
public:
using NestedJsonAccessor::NestedJsonAccessor;
JSON_STRING_ACCESSORS(uri)
};
class TextDocumentPositionParams : public NestedJsonAccessor {
public:
using NestedJsonAccessor::NestedJsonAccessor;
JSON_OBJECT_ACCESSORS(TextDocumentIdentifier, textDocument)
JSON_OBJECT_ACCESSORS(JsonPosition, position)
};
class Diagnostic : public NestedJsonAccessor {
public:
using NestedJsonAccessor::NestedJsonAccessor;
enum DiagnosticSeverity {
kError = 1,
kWarning = 2,
kInformation = 3,
kHint = 4
};
JSON_OBJECT_ACCESSORS(Range, range)
JSON_INT_ACCESSORS(severity)
JSON_STRING_ACCESSORS(source)
JSON_STRING_ACCESSORS(message)
};
class PublishDiagnosticsParams : public NestedJsonAccessor {
public:
using NestedJsonAccessor::NestedJsonAccessor;
JSON_STRING_ACCESSORS(uri)
JSON_ARRAY_OBJECT_ACCESSORS(Diagnostic, diagnostics)
};
enum SymbolKind {
kFile = 1,
kNamespace = 3,
kClass = 5,
kMethod = 6,
kProperty = 7,
kField = 8,
kConstructor = 9,
kFunction = 12,
kVariable = 13,
kConstant = 14,
kStruct = 23,
};
class DocumentSymbolParams : public NestedJsonAccessor {
public:
using NestedJsonAccessor::NestedJsonAccessor;
JSON_OBJECT_ACCESSORS(TextDocumentIdentifier, textDocument)
};
class SymbolInformation : public NestedJsonAccessor {
public:
using NestedJsonAccessor::NestedJsonAccessor;
JSON_STRING_ACCESSORS(name)
JSON_INT_ACCESSORS(kind)
JSON_OBJECT_ACCESSORS(Location, location)
JSON_STRING_ACCESSORS(containerName)
};
template <class T>
class Request : public Message {
public:
explicit Request(JsonValue value) : Message(std::move(value)) {}
Request() : Message() {}
JSON_INT_ACCESSORS(id)
JSON_STRING_ACCESSORS(method)
JSON_OBJECT_ACCESSORS(T, params)
};
using InitializeRequest = Request<InitializeParams>;
using RegistrationRequest = Request<RegistrationParams>;
using TorqueFileListNotification = Request<FileListParams>;
using GotoDefinitionRequest = Request<TextDocumentPositionParams>;
using DidChangeWatchedFilesNotification = Request<DidChangeWatchedFilesParams>;
using PublishDiagnosticsNotification = Request<PublishDiagnosticsParams>;
using DocumentSymbolRequest = Request<DocumentSymbolParams>;
template <class T>
class Response : public Message {
public:
explicit Response(JsonValue value) : Message(std::move(value)) {}
Response() : Message() {}
JSON_INT_ACCESSORS(id)
JSON_OBJECT_ACCESSORS(ResponseError, error)
JSON_OBJECT_ACCESSORS(T, result)
};
using InitializeResponse = Response<InitializeResult>;
using GotoDefinitionResponse = Response<Location>;
// Same as "Response" but the result is T[] instead of T.
template <class T>
class ResponseArrayResult : public Message {
public:
explicit ResponseArrayResult(JsonValue value) : Message(std::move(value)) {}
ResponseArrayResult() : Message() {}
JSON_INT_ACCESSORS(id)
JSON_OBJECT_ACCESSORS(ResponseError, error)
JSON_ARRAY_OBJECT_ACCESSORS(T, result)
};
using DocumentSymbolResponse = ResponseArrayResult<SymbolInformation>;
} // namespace ls
} // namespace torque
} // namespace internal
} // namespace v8
#endif // V8_TORQUE_LS_MESSAGE_H_