diff --git a/packages/react-native/ReactCommon/jsinspector-modern/ForwardingConsoleMethods.def b/packages/react-native/ReactCommon/jsinspector-modern/ForwardingConsoleMethods.def new file mode 100644 index 00000000000..b86df81e28a --- /dev/null +++ b/packages/react-native/ReactCommon/jsinspector-modern/ForwardingConsoleMethods.def @@ -0,0 +1,38 @@ +/* + * 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. + */ + +/** + * `console` methods that have no behaviour other than emitting a + * Runtime.consoleAPICalled message. + */ + +// console.clear +FORWARDING_CONSOLE_METHOD(clear, ConsoleAPIType::kClear) +// console.debug +FORWARDING_CONSOLE_METHOD(debug, ConsoleAPIType::kDebug) +// console.dir +FORWARDING_CONSOLE_METHOD(dir, ConsoleAPIType::kDir) +// console.dirxml +FORWARDING_CONSOLE_METHOD(dirxml, ConsoleAPIType::kDirXML) +// console.error +FORWARDING_CONSOLE_METHOD(error, ConsoleAPIType::kError) +// console.group +FORWARDING_CONSOLE_METHOD(group, ConsoleAPIType::kStartGroup) +// console.groupCollapsed +FORWARDING_CONSOLE_METHOD(groupCollapsed, ConsoleAPIType::kStartGroupCollapsed) +// console.groupEnd +FORWARDING_CONSOLE_METHOD(groupEnd, ConsoleAPIType::kEndGroup) +// console.info +FORWARDING_CONSOLE_METHOD(info, ConsoleAPIType::kInfo) +// console.log +FORWARDING_CONSOLE_METHOD(log, ConsoleAPIType::kLog) +// console.table +FORWARDING_CONSOLE_METHOD(table, ConsoleAPIType::kTable) +// console.trace +FORWARDING_CONSOLE_METHOD(trace, ConsoleAPIType::kTrace) +// console.warn +FORWARDING_CONSOLE_METHOD(warn, ConsoleAPIType::kWarning) diff --git a/packages/react-native/ReactCommon/jsinspector-modern/React-jsinspector.podspec b/packages/react-native/ReactCommon/jsinspector-modern/React-jsinspector.podspec index 0a88f2362f4..86783dcfd9b 100644 --- a/packages/react-native/ReactCommon/jsinspector-modern/React-jsinspector.podspec +++ b/packages/react-native/ReactCommon/jsinspector-modern/React-jsinspector.podspec @@ -33,7 +33,7 @@ Pod::Spec.new do |s| s.author = "Meta Platforms, Inc. and its affiliates" s.platforms = min_supported_versions s.source = source - s.source_files = "*.{cpp,h}" + s.source_files = "*.{cpp,h,def}" s.header_dir = 'jsinspector-modern' s.compiler_flags = folly_compiler_flags s.pod_target_xcconfig = { diff --git a/packages/react-native/ReactCommon/jsinspector-modern/RuntimeTargetConsole.cpp b/packages/react-native/ReactCommon/jsinspector-modern/RuntimeTargetConsole.cpp index e8572910d9b..f0479e9de46 100644 --- a/packages/react-native/ReactCommon/jsinspector-modern/RuntimeTargetConsole.cpp +++ b/packages/react-native/ReactCommon/jsinspector-modern/RuntimeTargetConsole.cpp @@ -37,27 +37,6 @@ struct ConsoleState { ~ConsoleState() = default; }; -/** - * `console` methods that have no behaviour other than emitting a - * Runtime.consoleAPICalled message. - */ -constexpr const std::pair - kForwardingConsoleMethods[] = { - {"clear", ConsoleAPIType::kClear}, - {"debug", ConsoleAPIType::kDebug}, - {"dir", ConsoleAPIType::kDir}, - {"dirxml", ConsoleAPIType::kDirXML}, - {"error", ConsoleAPIType::kError}, - {"group", ConsoleAPIType::kStartGroup}, - {"groupCollapsed", ConsoleAPIType::kStartGroupCollapsed}, - {"groupEnd", ConsoleAPIType::kEndGroup}, - {"info", ConsoleAPIType::kInfo}, - {"log", ConsoleAPIType::kLog}, - {"table", ConsoleAPIType::kTable}, - {"trace", ConsoleAPIType::kTrace}, - {"warn", ConsoleAPIType::kWarning}, -}; - /** * JS `Object.create()` */ @@ -119,6 +98,232 @@ concept CallableAsHostFunction = std::invocable< const jsi::Value* /*args*/, size_t /*count*/>; +void consoleCount( + jsi::Runtime& runtime, + const jsi::Value* args, + size_t count, + RuntimeTargetDelegate& runtimeTargetDelegate, + ConsoleState& state, + double timestampMs, + std::unique_ptr stackTrace) { + std::string label = "default"; + if (count > 0 && !args[0].isUndefined()) { + label = args[0].toString(runtime).utf8(runtime); + } + auto it = state.countMap.find(label); + if (it == state.countMap.end()) { + it = state.countMap.insert({label, 1}).first; + } else { + it->second++; + } + std::vector vec; + vec.emplace_back(jsi::String::createFromUtf8( + runtime, label + ": "s + std::to_string(it->second))); + runtimeTargetDelegate.addConsoleMessage( + runtime, + {timestampMs, + ConsoleAPIType::kCount, + std::move(vec), + std::move(stackTrace)}); +} + +void consoleCountReset( + jsi::Runtime& runtime, + const jsi::Value* args, + size_t count, + RuntimeTargetDelegate& runtimeTargetDelegate, + ConsoleState& state, + double timestampMs, + std::unique_ptr stackTrace) { + std::string label = "default"; + if (count > 0 && !args[0].isUndefined()) { + label = args[0].toString(runtime).utf8(runtime); + } + auto it = state.countMap.find(label); + if (it == state.countMap.end()) { + std::vector vec; + vec.emplace_back(jsi::String::createFromUtf8( + runtime, "Count for '"s + label + "' does not exist")); + runtimeTargetDelegate.addConsoleMessage( + runtime, + {timestampMs, + ConsoleAPIType::kWarning, + std::move(vec), + std::move(stackTrace)}); + } else { + it->second = 0; + } +} + +void consoleTime( + jsi::Runtime& runtime, + const jsi::Value* args, + size_t count, + RuntimeTargetDelegate& runtimeTargetDelegate, + ConsoleState& state, + double timestampMs, + std::unique_ptr stackTrace) { + std::string label = "default"; + if (count > 0 && !args[0].isUndefined()) { + label = args[0].toString(runtime).utf8(runtime); + } + auto it = state.timerTable.find(label); + if (it == state.timerTable.end()) { + state.timerTable.insert({label, timestampMs}); + } else { + std::vector vec; + vec.emplace_back(jsi::String::createFromUtf8( + runtime, "Timer '"s + label + "' already exists")); + runtimeTargetDelegate.addConsoleMessage( + runtime, + {timestampMs, + ConsoleAPIType::kWarning, + std::move(vec), + std::move(stackTrace)}); + } +} + +void consoleTimeEnd( + jsi::Runtime& runtime, + const jsi::Value* args, + size_t count, + RuntimeTargetDelegate& runtimeTargetDelegate, + ConsoleState& state, + double timestampMs, + std::unique_ptr stackTrace) { + std::string label = "default"; + if (count > 0 && !args[0].isUndefined()) { + label = args[0].toString(runtime).utf8(runtime); + } + auto it = state.timerTable.find(label); + if (it == state.timerTable.end()) { + std::vector vec; + vec.emplace_back(jsi::String::createFromUtf8( + runtime, "Timer '"s + label + "' does not exist")); + runtimeTargetDelegate.addConsoleMessage( + runtime, + {timestampMs, + ConsoleAPIType::kWarning, + std::move(vec), + std::move(stackTrace)}); + } else { + std::vector vec; + vec.emplace_back(jsi::String::createFromUtf8( + runtime, + label + ": "s + std::to_string(timestampMs - it->second) + " ms")); + state.timerTable.erase(it); + runtimeTargetDelegate.addConsoleMessage( + runtime, + {timestampMs, + ConsoleAPIType::kTimeEnd, + std::move(vec), + std::move(stackTrace)}); + } +} + +void consoleTimeLog( + jsi::Runtime& runtime, + const jsi::Value* args, + size_t count, + RuntimeTargetDelegate& runtimeTargetDelegate, + ConsoleState& state, + double timestampMs, + std::unique_ptr stackTrace) { + std::string label = "default"; + if (count > 0 && !args[0].isUndefined()) { + label = args[0].toString(runtime).utf8(runtime); + } + auto it = state.timerTable.find(label); + if (it == state.timerTable.end()) { + std::vector vec; + vec.emplace_back(jsi::String::createFromUtf8( + runtime, "Timer '"s + label + "' does not exist")); + runtimeTargetDelegate.addConsoleMessage( + runtime, + {timestampMs, + ConsoleAPIType::kWarning, + std::move(vec), + std::move(stackTrace)}); + } else { + std::vector vec; + vec.emplace_back(jsi::String::createFromUtf8( + runtime, + label + ": "s + std::to_string(timestampMs - it->second) + " ms")); + if (count > 1) { + for (size_t i = 1; i != count; ++i) { + vec.emplace_back(runtime, args[i]); + } + } + runtimeTargetDelegate.addConsoleMessage( + runtime, + {timestampMs, + ConsoleAPIType::kLog, + std::move(vec), + std::move(stackTrace)}); + } +} + +void consoleAssert( + jsi::Runtime& runtime, + const jsi::Value* args, + size_t count, + RuntimeTargetDelegate& runtimeTargetDelegate, + ConsoleState& /*state*/, + double timestampMs, + std::unique_ptr stackTrace) { + if (count >= 1 && toBoolean(runtime, args[0])) { + return; + } + std::deque data; + + if (count > 1) { + for (size_t i = 1; i != count; ++i) { + data.emplace_back(runtime, args[i]); + } + } + if (data.empty()) { + data.emplace_back(jsi::String::createFromUtf8(runtime, "Assertion failed")); + } else if (data.front().isString()) { + data.front() = jsi::String::createFromUtf8( + runtime, + "Assertion failed: "s + data.front().asString(runtime).utf8(runtime)); + } else { + data.emplace_front( + jsi::String::createFromUtf8(runtime, "Assertion failed")); + } + runtimeTargetDelegate.addConsoleMessage( + runtime, + {timestampMs, + ConsoleAPIType::kAssert, + std::vector( + make_move_iterator(data.begin()), make_move_iterator(data.end())), + std::move(stackTrace)}); +} + +/** + * `console` methods that have no behaviour other than emitting a + * Runtime.consoleAPICalled message. + */ +#define FORWARDING_CONSOLE_METHOD(name, type) \ + void console_##name( \ + jsi::Runtime& runtime, \ + const jsi::Value* args, \ + size_t count, \ + RuntimeTargetDelegate& runtimeTargetDelegate, \ + ConsoleState& state, \ + double timestampMs, \ + std::unique_ptr stackTrace) { \ + std::vector argsVec; \ + for (size_t i = 0; i != count; ++i) { \ + argsVec.emplace_back(runtime, args[i]); \ + } \ + runtimeTargetDelegate.addConsoleMessage( \ + runtime, \ + {timestampMs, type, std::move(argsVec), std::move(stackTrace)}); \ + } +#include "ForwardingConsoleMethods.def" +#undef FORWARDING_CONSOLE_METHOD + } // namespace void RuntimeTarget::installConsoleHandler() { @@ -234,254 +439,38 @@ void RuntimeTarget::installConsoleHandler() { /** * console.count */ - installConsoleMethod( - "count", - [](jsi::Runtime& runtime, - const jsi::Value* args, - size_t count, - RuntimeTargetDelegate& runtimeTargetDelegate, - ConsoleState& state, - auto timestampMs, - std::unique_ptr stackTrace) { - std::string label = "default"; - if (count > 0 && !args[0].isUndefined()) { - label = args[0].toString(runtime).utf8(runtime); - } - auto it = state.countMap.find(label); - if (it == state.countMap.end()) { - it = state.countMap.insert({label, 1}).first; - } else { - it->second++; - } - std::vector vec; - vec.emplace_back(jsi::String::createFromUtf8( - runtime, label + ": "s + std::to_string(it->second))); - runtimeTargetDelegate.addConsoleMessage( - runtime, - {timestampMs, - ConsoleAPIType::kCount, - std::move(vec), - std::move(stackTrace)}); - }); + installConsoleMethod("count", consoleCount); /** * console.countReset */ - installConsoleMethod( - "countReset", - [](jsi::Runtime& runtime, - const jsi::Value* args, - size_t count, - RuntimeTargetDelegate& runtimeTargetDelegate, - ConsoleState& state, - auto timestampMs, - std::unique_ptr stackTrace) { - std::string label = "default"; - if (count > 0 && !args[0].isUndefined()) { - label = args[0].toString(runtime).utf8(runtime); - } - auto it = state.countMap.find(label); - if (it == state.countMap.end()) { - std::vector vec; - vec.emplace_back(jsi::String::createFromUtf8( - runtime, "Count for '"s + label + "' does not exist")); - runtimeTargetDelegate.addConsoleMessage( - runtime, - {timestampMs, - ConsoleAPIType::kWarning, - std::move(vec), - std::move(stackTrace)}); - } else { - it->second = 0; - } - }); + installConsoleMethod("countReset", consoleCountReset); /** * console.time */ - installConsoleMethod( - "time", - [](jsi::Runtime& runtime, - const jsi::Value* args, - size_t count, - RuntimeTargetDelegate& runtimeTargetDelegate, - ConsoleState& state, - auto timestampMs, - std::unique_ptr stackTrace) { - std::string label = "default"; - if (count > 0 && !args[0].isUndefined()) { - label = args[0].toString(runtime).utf8(runtime); - } - auto it = state.timerTable.find(label); - if (it == state.timerTable.end()) { - state.timerTable.insert({label, timestampMs}); - } else { - std::vector vec; - vec.emplace_back(jsi::String::createFromUtf8( - runtime, "Timer '"s + label + "' already exists")); - runtimeTargetDelegate.addConsoleMessage( - runtime, - {timestampMs, - ConsoleAPIType::kWarning, - std::move(vec), - std::move(stackTrace)}); - } - }); + installConsoleMethod("time", consoleTime); /** * console.timeEnd */ - installConsoleMethod( - "timeEnd", - [](jsi::Runtime& runtime, - const jsi::Value* args, - size_t count, - RuntimeTargetDelegate& runtimeTargetDelegate, - ConsoleState& state, - auto timestampMs, - std::unique_ptr stackTrace) { - std::string label = "default"; - if (count > 0 && !args[0].isUndefined()) { - label = args[0].toString(runtime).utf8(runtime); - } - auto it = state.timerTable.find(label); - if (it == state.timerTable.end()) { - std::vector vec; - vec.emplace_back(jsi::String::createFromUtf8( - runtime, "Timer '"s + label + "' does not exist")); - runtimeTargetDelegate.addConsoleMessage( - runtime, - {timestampMs, - ConsoleAPIType::kWarning, - std::move(vec), - std::move(stackTrace)}); - } else { - std::vector vec; - vec.emplace_back(jsi::String::createFromUtf8( - runtime, - label + ": "s + std::to_string(timestampMs - it->second) + - " ms")); - state.timerTable.erase(it); - runtimeTargetDelegate.addConsoleMessage( - runtime, - {timestampMs, - ConsoleAPIType::kTimeEnd, - std::move(vec), - std::move(stackTrace)}); - } - }); + installConsoleMethod("timeEnd", consoleTimeEnd); /** * console.timeLog */ - installConsoleMethod( - "timeLog", - [](jsi::Runtime& runtime, - const jsi::Value* args, - size_t count, - RuntimeTargetDelegate& runtimeTargetDelegate, - ConsoleState& state, - auto timestampMs, - std::unique_ptr stackTrace) { - std::string label = "default"; - if (count > 0 && !args[0].isUndefined()) { - label = args[0].toString(runtime).utf8(runtime); - } - auto it = state.timerTable.find(label); - if (it == state.timerTable.end()) { - std::vector vec; - vec.emplace_back(jsi::String::createFromUtf8( - runtime, "Timer '"s + label + "' does not exist")); - runtimeTargetDelegate.addConsoleMessage( - runtime, - {timestampMs, - ConsoleAPIType::kWarning, - std::move(vec), - std::move(stackTrace)}); - } else { - std::vector vec; - vec.emplace_back(jsi::String::createFromUtf8( - runtime, - label + ": "s + std::to_string(timestampMs - it->second) + - " ms")); - if (count > 1) { - for (size_t i = 1; i != count; ++i) { - vec.emplace_back(runtime, args[i]); - } - } - runtimeTargetDelegate.addConsoleMessage( - runtime, - {timestampMs, - ConsoleAPIType::kLog, - std::move(vec), - std::move(stackTrace)}); - } - }); + installConsoleMethod("timeLog", consoleTimeLog); /** * console.assert */ - installConsoleMethod( - "assert", - [](jsi::Runtime& runtime, - const jsi::Value* args, - size_t count, - RuntimeTargetDelegate& runtimeTargetDelegate, - ConsoleState& /*state*/, - auto timestampMs, - std::unique_ptr stackTrace) { - if (count >= 1 && toBoolean(runtime, args[0])) { - return; - } - std::deque data; + installConsoleMethod("assert", consoleAssert); - if (count > 1) { - for (size_t i = 1; i != count; ++i) { - data.emplace_back(runtime, args[i]); - } - } - if (data.empty()) { - data.emplace_back( - jsi::String::createFromUtf8(runtime, "Assertion failed")); - } else if (data.front().isString()) { - data.front() = jsi::String::createFromUtf8( - runtime, - "Assertion failed: "s + - data.front().asString(runtime).utf8(runtime)); - } else { - data.emplace_front( - jsi::String::createFromUtf8(runtime, "Assertion failed")); - } - runtimeTargetDelegate.addConsoleMessage( - runtime, - {timestampMs, - ConsoleAPIType::kAssert, - std::vector( - make_move_iterator(data.begin()), - make_move_iterator(data.end())), - std::move(stackTrace)}); - }); - - for (auto& [name, type] : kForwardingConsoleMethods) { - installConsoleMethod( - name, - [type = type]( - jsi::Runtime& runtime, - const jsi::Value* args, - size_t count, - RuntimeTargetDelegate& runtimeTargetDelegate, - ConsoleState& /*state*/, - auto timestampMs, - std::unique_ptr stackTrace) { - std::vector argsVec; - for (size_t i = 0; i != count; ++i) { - argsVec.emplace_back(runtime, args[i]); - } - runtimeTargetDelegate.addConsoleMessage( - runtime, - {timestampMs, type, std::move(argsVec), std::move(stackTrace)}); - }); - } + // Install forwarding console methods. +#define FORWARDING_CONSOLE_METHOD(name, type) \ + installConsoleMethod(#name, console_##name); +#include "ForwardingConsoleMethods.def" +#undef FORWARDING_CONSOLE_METHOD runtime.global().setProperty(runtime, "console", console); if (delegateSupportsConsole) {