mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Add helpers for formatting JSON CDP responses (#43340)
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/43340 Adds convenience methods `jsonResult`, `jsonError` and `jsonNotification` for more ergonomic construction of CDP JSON responses. Note that CDP is *loosely* based on [JSON-RPC 2.0](https://www.jsonrpc.org/specification), but differs for example in the omission of `"jsonrpc": "2.0"`. Before: ``` frontendChannel_(folly::toJson(folly::dynamic::object("id", req.id)( "error", folly::dynamic::object("code", -32602)( "message", "executionContextName is mutually exclusive with executionContextId")))); ``` After: ``` frontendChannel_(cdp::jsonError( req.id, cdp::ErrorCode::InvalidParams, "executionContextName is mutually exclusive with executionContextId")); ``` Changelog: [Internal] Reviewed By: motiz88 Differential Revision: D54202854 fbshipit-source-id: 76a407ae39ff9c2ec79bcaddb6cd4d494afb7693
This commit is contained in:
committed by
Facebook GitHub Bot
parent
9426d249cb
commit
3ed0ff34b3
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#include "CdpJson.h"
|
||||
|
||||
#include <folly/dynamic.h>
|
||||
#include <folly/json.h>
|
||||
|
||||
namespace facebook::react::jsinspector_modern::cdp {
|
||||
|
||||
PreparsedRequest preparse(std::string_view message) {
|
||||
folly::dynamic parsed = folly::parseJson(message);
|
||||
return PreparsedRequest{
|
||||
.id = parsed["id"].getInt(),
|
||||
.method = parsed["method"].getString(),
|
||||
.params = parsed.count("params") != 0u ? parsed["params"] : nullptr};
|
||||
}
|
||||
|
||||
std::string PreparsedRequest::toJson() const {
|
||||
folly::dynamic obj = folly::dynamic::object;
|
||||
obj["id"] = id;
|
||||
obj["method"] = method;
|
||||
if (params != nullptr) {
|
||||
obj["params"] = params;
|
||||
}
|
||||
return folly::toJson(obj);
|
||||
}
|
||||
|
||||
std::string jsonError(
|
||||
std::optional<RequestId> id,
|
||||
ErrorCode code,
|
||||
std::optional<std::string> message) {
|
||||
auto dynamicError = folly::dynamic::object("code", static_cast<int>(code));
|
||||
if (message) {
|
||||
dynamicError("message", *message);
|
||||
}
|
||||
return folly::toJson(
|
||||
(id ? folly::dynamic::object("id", *id)
|
||||
: folly::dynamic::object(
|
||||
"id", nullptr))("error", std::move(dynamicError)));
|
||||
}
|
||||
|
||||
std::string jsonResult(RequestId id, const folly::dynamic& result) {
|
||||
return folly::toJson(folly::dynamic::object("id", id)("result", result));
|
||||
}
|
||||
|
||||
std::string jsonNotification(
|
||||
std::string_view method,
|
||||
std::optional<folly::dynamic> params) {
|
||||
auto dynamicNotification = folly::dynamic::object("method", method);
|
||||
if (params) {
|
||||
dynamicNotification("params", *params);
|
||||
}
|
||||
return folly::toJson(std::move(dynamicNotification));
|
||||
}
|
||||
|
||||
} // namespace facebook::react::jsinspector_modern::cdp
|
||||
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <folly/dynamic.h>
|
||||
#include <folly/json.h>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
namespace facebook::react::jsinspector_modern::cdp {
|
||||
|
||||
using RequestId = long long;
|
||||
|
||||
/**
|
||||
* Error codes to be used in CDP responses.
|
||||
* https://www.jsonrpc.org/specification#error_object
|
||||
*/
|
||||
enum class ErrorCode {
|
||||
ParseError = -32700,
|
||||
InvalidRequest = -32600,
|
||||
MethodNotFound = -32601,
|
||||
InvalidParams = -32602,
|
||||
InternalError = -32603
|
||||
/* -32000 to -32099: Implementation-defined server errors. */
|
||||
};
|
||||
|
||||
/**
|
||||
* An incoming CDP request that has been parsed into a more usable form.
|
||||
*/
|
||||
struct PreparsedRequest {
|
||||
public:
|
||||
/**
|
||||
* The ID of the request.
|
||||
*/
|
||||
RequestId id{};
|
||||
|
||||
/**
|
||||
* The name of the method being invoked.
|
||||
*/
|
||||
std::string method;
|
||||
|
||||
/**
|
||||
* The parameters passed to the method, if any.
|
||||
*/
|
||||
folly::dynamic params;
|
||||
|
||||
/**
|
||||
* Equality operator, useful for unit tests
|
||||
*/
|
||||
inline bool operator==(const PreparsedRequest& rhs) const {
|
||||
return id == rhs.id && method == rhs.method && params == rhs.params;
|
||||
}
|
||||
|
||||
std::string toJson() const;
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse a JSON-encoded CDP request into its constituent parts.
|
||||
* \throws ParseError If the input cannot be parsed.
|
||||
* \throws TypeError If the input does not conform to the expected format.
|
||||
*/
|
||||
PreparsedRequest preparse(std::string_view message);
|
||||
|
||||
/**
|
||||
* A type error that may be thrown while preparsing a request, or while
|
||||
* accessing dynamic params on a request.
|
||||
*/
|
||||
using TypeError = folly::TypeError;
|
||||
|
||||
/**
|
||||
* A parse error that may be thrown while preparsing a request.
|
||||
*/
|
||||
using ParseError = folly::json::parse_error;
|
||||
|
||||
/**
|
||||
* Helper functions for creating CDP (loosely JSON-RPC) messages of various
|
||||
* types, returning a JSON string ready for sending over the wire.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns a JSON-formatted string representing an error.
|
||||
*
|
||||
* {"id": <id>, "error": { "code": <code>, "message": <message> }}
|
||||
*
|
||||
* \param id Request ID. Mandatory, null only if the request omitted it or
|
||||
* could not be parsed.
|
||||
* \param code Integer code from cdp::ErrorCode.
|
||||
* \param message Optional, brief human-readable error message.
|
||||
*/
|
||||
std::string jsonError(
|
||||
std::optional<RequestId> id,
|
||||
ErrorCode code,
|
||||
std::optional<std::string> message = std::nullopt);
|
||||
|
||||
/**
|
||||
* Returns a JSON-formatted string representing a successful response.
|
||||
*
|
||||
* {"id": <id>, "result": <result>}
|
||||
*
|
||||
* \param id The id of the request that this response corresponds to.
|
||||
* \param result Result payload, defaulting to {}.
|
||||
*/
|
||||
std::string jsonResult(
|
||||
RequestId id,
|
||||
const folly::dynamic& result = folly::dynamic::object());
|
||||
|
||||
/**
|
||||
* Returns a JSON-formatted string representing a unilateral notifcation.
|
||||
*
|
||||
* {"method": <method>, "params": <params>}
|
||||
*
|
||||
* \param method Notification (aka "event") method.
|
||||
* \param params Optional payload pbject.
|
||||
*/
|
||||
std::string jsonNotification(
|
||||
std::string_view method,
|
||||
std::optional<folly::dynamic> params = std::nullopt);
|
||||
|
||||
} // namespace facebook::react::jsinspector_modern::cdp
|
||||
+9
-10
@@ -54,17 +54,16 @@ void FallbackRuntimeAgentDelegate::sendFallbackRuntimeWarning() {
|
||||
}
|
||||
|
||||
void FallbackRuntimeAgentDelegate::sendWarningLogEntry(std::string_view text) {
|
||||
frontendChannel_(
|
||||
folly::toJson(folly::dynamic::object("method", "Log.entryAdded")(
|
||||
"params",
|
||||
frontendChannel_(cdp::jsonNotification(
|
||||
"Log.entryAdded",
|
||||
folly::dynamic::object(
|
||||
"entry",
|
||||
folly::dynamic::object(
|
||||
"entry",
|
||||
folly::dynamic::object(
|
||||
"timestamp",
|
||||
duration_cast<milliseconds>(
|
||||
system_clock::now().time_since_epoch())
|
||||
.count())("source", "other")(
|
||||
"level", "warning")("text", text)))));
|
||||
"timestamp",
|
||||
duration_cast<milliseconds>(
|
||||
system_clock::now().time_since_epoch())
|
||||
.count())("source", "other")(
|
||||
"level", "warning")("text", text))));
|
||||
}
|
||||
|
||||
} // namespace facebook::react::jsinspector_modern
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#include "CdpJson.h"
|
||||
|
||||
#include <folly/dynamic.h>
|
||||
#include <folly/json.h>
|
||||
#include <jsinspector-modern/HostAgent.h>
|
||||
@@ -98,33 +100,27 @@ void HostAgent::handleRequest(const cdp::PreparsedRequest& req) {
|
||||
}
|
||||
|
||||
if (shouldSendOKResponse) {
|
||||
folly::dynamic res = folly::dynamic::object("id", req.id)(
|
||||
"result", folly::dynamic::object());
|
||||
std::string json = folly::toJson(res);
|
||||
frontendChannel_(json);
|
||||
frontendChannel_(cdp::jsonResult(req.id));
|
||||
return;
|
||||
}
|
||||
|
||||
folly::dynamic res = folly::dynamic::object("id", req.id)(
|
||||
"error",
|
||||
folly::dynamic::object("code", -32601)(
|
||||
"message", req.method + " not implemented yet"));
|
||||
std::string json = folly::toJson(res);
|
||||
frontendChannel_(json);
|
||||
frontendChannel_(cdp::jsonError(
|
||||
req.id,
|
||||
cdp::ErrorCode::MethodNotFound,
|
||||
req.method + " not implemented yet"));
|
||||
}
|
||||
|
||||
void HostAgent::sendInfoLogEntry(std::string_view text) {
|
||||
frontendChannel_(
|
||||
folly::toJson(folly::dynamic::object("method", "Log.entryAdded")(
|
||||
"params",
|
||||
frontendChannel_(cdp::jsonNotification(
|
||||
"Log.entryAdded",
|
||||
folly::dynamic::object(
|
||||
"entry",
|
||||
folly::dynamic::object(
|
||||
"entry",
|
||||
folly::dynamic::object(
|
||||
"timestamp",
|
||||
duration_cast<milliseconds>(
|
||||
system_clock::now().time_since_epoch())
|
||||
.count())("source", "other")(
|
||||
"level", "info")("text", text)))));
|
||||
"timestamp",
|
||||
duration_cast<milliseconds>(
|
||||
system_clock::now().time_since_epoch())
|
||||
.count())("source", "other")(
|
||||
"level", "info")("text", text))));
|
||||
}
|
||||
|
||||
void HostAgent::setCurrentInstanceAgent(
|
||||
@@ -140,9 +136,7 @@ void HostAgent::setCurrentInstanceAgent(
|
||||
|
||||
// Because we can only have a single instance, we can report all contexts
|
||||
// as cleared.
|
||||
folly::dynamic contextsCleared =
|
||||
folly::dynamic::object("method", "Runtime.executionContextsCleared");
|
||||
frontendChannel_(folly::toJson(contextsCleared));
|
||||
frontendChannel_(cdp::jsonNotification("Runtime.executionContextsCleared"));
|
||||
}
|
||||
if (instanceAgent_) {
|
||||
// TODO: Send Runtime.executionContextCreated here - at the moment we expect
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
|
||||
#include <jsinspector-modern/InspectorInterfaces.h>
|
||||
#include <jsinspector-modern/InstanceAgent.h>
|
||||
#include <jsinspector-modern/Parsing.h>
|
||||
|
||||
#include <functional>
|
||||
#include <string_view>
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
*/
|
||||
|
||||
#include "HostTarget.h"
|
||||
#include "CdpJson.h"
|
||||
#include "HostAgent.h"
|
||||
#include "InspectorInterfaces.h"
|
||||
#include "InspectorUtilities.h"
|
||||
#include "InstanceTarget.h"
|
||||
#include "Parsing.h"
|
||||
#include "SessionState.h"
|
||||
|
||||
#include <folly/dynamic.h>
|
||||
@@ -53,14 +53,12 @@ class HostTargetSession {
|
||||
try {
|
||||
request = cdp::preparse(message);
|
||||
} catch (const cdp::ParseError& e) {
|
||||
frontendChannel_(folly::toJson(folly::dynamic::object("id", nullptr)(
|
||||
"error",
|
||||
folly::dynamic::object("code", -32700)("message", e.what()))));
|
||||
frontendChannel_(
|
||||
cdp::jsonError(std::nullopt, cdp::ErrorCode::ParseError, e.what()));
|
||||
return;
|
||||
} catch (const cdp::TypeError& e) {
|
||||
frontendChannel_(folly::toJson(folly::dynamic::object("id", nullptr)(
|
||||
"error",
|
||||
folly::dynamic::object("code", -32600)("message", e.what()))));
|
||||
frontendChannel_(cdp::jsonError(
|
||||
std::nullopt, cdp::ErrorCode::InvalidRequest, e.what()));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -69,9 +67,8 @@ class HostTargetSession {
|
||||
try {
|
||||
hostAgent_.handleRequest(request);
|
||||
} catch (const cdp::TypeError& e) {
|
||||
frontendChannel_(folly::toJson(folly::dynamic::object("id", request.id)(
|
||||
"error",
|
||||
folly::dynamic::object("code", -32600)("message", e.what()))));
|
||||
frontendChannel_(
|
||||
cdp::jsonError(request.id, cdp::ErrorCode::InvalidRequest, e.what()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
#include <jsinspector-modern/InstanceAgent.h>
|
||||
#include "CdpJson.h"
|
||||
#include "RuntimeTarget.h"
|
||||
|
||||
namespace facebook::react::jsinspector_modern {
|
||||
@@ -49,9 +50,8 @@ void InstanceAgent::setCurrentRuntime(RuntimeTarget* runtimeTarget) {
|
||||
if (previousContext.uniqueId.has_value()) {
|
||||
params["executionContextUniqueId"] = *previousContext.uniqueId;
|
||||
}
|
||||
folly::dynamic contextDestroyed = folly::dynamic::object(
|
||||
"method", "Runtime.executionContextDestroyed")("params", params);
|
||||
frontendChannel_(folly::toJson(contextDestroyed));
|
||||
frontendChannel_(
|
||||
cdp::jsonNotification("Runtime.executionContextDestroyed", params));
|
||||
}
|
||||
maybeSendExecutionContextCreatedNotification();
|
||||
}
|
||||
@@ -66,9 +66,8 @@ void InstanceAgent::maybeSendExecutionContextCreatedNotification() {
|
||||
if (newContext.uniqueId.has_value()) {
|
||||
params["uniqueId"] = *newContext.uniqueId;
|
||||
}
|
||||
folly::dynamic contextCreated = folly::dynamic::object(
|
||||
"method", "Runtime.executionContextCreated")("params", params);
|
||||
frontendChannel_(folly::toJson(contextCreated));
|
||||
frontendChannel_(
|
||||
cdp::jsonNotification("Runtime.executionContextCreated", params));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,11 +7,11 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CdpJson.h"
|
||||
#include "RuntimeTarget.h"
|
||||
#include "SessionState.h"
|
||||
|
||||
#include <jsinspector-modern/InspectorInterfaces.h>
|
||||
#include <jsinspector-modern/Parsing.h>
|
||||
#include <jsinspector-modern/RuntimeAgent.h>
|
||||
|
||||
#include <functional>
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#include <folly/dynamic.h>
|
||||
#include <folly/json.h>
|
||||
#include <jsinspector-modern/Parsing.h>
|
||||
|
||||
namespace facebook::react::jsinspector_modern::cdp {
|
||||
|
||||
PreparsedRequest preparse(std::string_view message) {
|
||||
folly::dynamic parsed = folly::parseJson(message);
|
||||
return PreparsedRequest{
|
||||
.id = parsed["id"].getInt(),
|
||||
.method = parsed["method"].getString(),
|
||||
.params = parsed.count("params") ? parsed["params"] : nullptr};
|
||||
}
|
||||
|
||||
std::string PreparsedRequest::toJson() const {
|
||||
folly::dynamic obj = folly::dynamic::object;
|
||||
obj["id"] = id;
|
||||
obj["method"] = method;
|
||||
if (params != nullptr) {
|
||||
obj["params"] = params;
|
||||
}
|
||||
return folly::toJson(obj);
|
||||
}
|
||||
|
||||
} // namespace facebook::react::jsinspector_modern::cdp
|
||||
@@ -1,69 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <folly/dynamic.h>
|
||||
#include <folly/json.h>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
namespace facebook::react::jsinspector_modern {
|
||||
|
||||
namespace cdp {
|
||||
using RequestId = long long;
|
||||
|
||||
/**
|
||||
* An incoming CDP request that has been parsed into a more usable form.
|
||||
*/
|
||||
struct PreparsedRequest {
|
||||
public:
|
||||
/**
|
||||
* The ID of the request.
|
||||
*/
|
||||
RequestId id;
|
||||
|
||||
/**
|
||||
* The name of the method being invoked.
|
||||
*/
|
||||
std::string method;
|
||||
|
||||
/**
|
||||
* The parameters passed to the method, if any.
|
||||
*/
|
||||
folly::dynamic params;
|
||||
|
||||
/**
|
||||
* Equality operator, useful for unit tests
|
||||
*/
|
||||
inline bool operator==(const PreparsedRequest& rhs) const {
|
||||
return id == rhs.id && method == rhs.method && params == rhs.params;
|
||||
}
|
||||
|
||||
std::string toJson() const;
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse a JSON-encoded CDP request into its constituent parts.
|
||||
* \throws ParseError If the input cannot be parsed.
|
||||
* \throws TypeError If the input does not conform to the expected format.
|
||||
*/
|
||||
PreparsedRequest preparse(std::string_view message);
|
||||
|
||||
/**
|
||||
* A type error that may be thrown while preparsing a request, or while
|
||||
* accessing dynamic params on a request.
|
||||
*/
|
||||
using TypeError = folly::TypeError;
|
||||
|
||||
/**
|
||||
* A parse error that may be thrown while preparsing a request.
|
||||
*/
|
||||
using ParseError = folly::json::parse_error;
|
||||
} // namespace cdp
|
||||
|
||||
} // namespace facebook::react::jsinspector_modern
|
||||
@@ -42,21 +42,20 @@ bool RuntimeAgent::handleRequest(const cdp::PreparsedRequest& req) {
|
||||
auto executionContextId = req.params["executionContextId"].getInt();
|
||||
if (executionContextId < (int64_t)std::numeric_limits<int32_t>::min() ||
|
||||
executionContextId > (int64_t)std::numeric_limits<int32_t>::max()) {
|
||||
frontendChannel_(folly::toJson(folly::dynamic::object("id", req.id)(
|
||||
"error",
|
||||
folly::dynamic::object("code", -32602)(
|
||||
"message", "Invalid execution context id"))));
|
||||
frontendChannel_(cdp::jsonError(
|
||||
req.id,
|
||||
cdp::ErrorCode::InvalidParams,
|
||||
"Invalid execution context id"));
|
||||
return true;
|
||||
}
|
||||
contextSelector =
|
||||
ExecutionContextSelector::byId((int32_t)executionContextId);
|
||||
|
||||
if (req.params.count("executionContextName")) {
|
||||
frontendChannel_(folly::toJson(folly::dynamic::object("id", req.id)(
|
||||
"error",
|
||||
folly::dynamic::object("code", -32602)(
|
||||
"message",
|
||||
"executionContextName is mutually exclusive with executionContextId"))));
|
||||
frontendChannel_(cdp::jsonError(
|
||||
req.id,
|
||||
cdp::ErrorCode::InvalidParams,
|
||||
"executionContextName is mutually exclusive with executionContextId"));
|
||||
return true;
|
||||
}
|
||||
} else if (req.params.count("executionContextName")) {
|
||||
@@ -68,10 +67,7 @@ bool RuntimeAgent::handleRequest(const cdp::PreparsedRequest& req) {
|
||||
}
|
||||
sessionState_.subscribedBindings[bindingName].insert(contextSelector);
|
||||
|
||||
folly::dynamic res = folly::dynamic::object("id", req.id)(
|
||||
"result", folly::dynamic::object());
|
||||
std::string json = folly::toJson(res);
|
||||
frontendChannel_(json);
|
||||
frontendChannel_(cdp::jsonResult(req.id));
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -83,10 +79,7 @@ bool RuntimeAgent::handleRequest(const cdp::PreparsedRequest& req) {
|
||||
// if the subscription is targeted by context name.
|
||||
sessionState_.subscribedBindings.erase(req.params["name"].getString());
|
||||
|
||||
folly::dynamic res = folly::dynamic::object("id", req.id)(
|
||||
"result", folly::dynamic::object());
|
||||
std::string json = folly::toJson(res);
|
||||
frontendChannel_(json);
|
||||
frontendChannel_(cdp::jsonResult(req.id));
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -113,12 +106,11 @@ void RuntimeAgent::notifyBindingCalled(
|
||||
return;
|
||||
}
|
||||
|
||||
frontendChannel_(
|
||||
folly::toJson(folly::dynamic::object("method", "Runtime.bindingCalled")(
|
||||
"params",
|
||||
folly::dynamic::object(
|
||||
"executionContextId", executionContextDescription_.id)(
|
||||
"name", bindingName)("payload", payload))));
|
||||
frontendChannel_(cdp::jsonNotification(
|
||||
"Runtime.bindingCalled",
|
||||
folly::dynamic::object(
|
||||
"executionContextId", executionContextDescription_.id)(
|
||||
"name", bindingName)("payload", payload)));
|
||||
}
|
||||
|
||||
RuntimeAgent::ExportedState RuntimeAgent::getExportedState() {
|
||||
|
||||
@@ -7,12 +7,11 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CdpJson.h"
|
||||
#include "InspectorInterfaces.h"
|
||||
#include "RuntimeAgentDelegate.h"
|
||||
#include "RuntimeTarget.h"
|
||||
|
||||
#include <jsinspector-modern/Parsing.h>
|
||||
|
||||
namespace facebook::react::jsinspector_modern {
|
||||
|
||||
class RuntimeTargetController;
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <jsinspector-modern/Parsing.h>
|
||||
#include "CdpJson.h"
|
||||
|
||||
namespace facebook::react::jsinspector_modern {
|
||||
|
||||
|
||||
Reference in New Issue
Block a user