Console.cpp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. /*
  2. * Copyright (c) 2020, Emanuele Torre <torreemanuele6@gmail.com>
  3. * Copyright (c) 2020-2021, Linus Groh <linusg@serenityos.org>
  4. * Copyright (c) 2021, Sam Atkins <atkinssj@serenityos.org>
  5. *
  6. * SPDX-License-Identifier: BSD-2-Clause
  7. */
  8. #include <LibJS/Console.h>
  9. #include <LibJS/Runtime/GlobalObject.h>
  10. namespace JS {
  11. Console::Console(GlobalObject& global_object)
  12. : m_global_object(global_object)
  13. {
  14. }
  15. VM& Console::vm()
  16. {
  17. return m_global_object.vm();
  18. }
  19. // 1.1.3. debug(...data), https://console.spec.whatwg.org/#debug
  20. ThrowCompletionOr<Value> Console::debug()
  21. {
  22. // 1. Perform Logger("debug", data).
  23. if (m_client) {
  24. auto data = vm_arguments();
  25. return m_client->logger(LogLevel::Debug, data);
  26. }
  27. return js_undefined();
  28. }
  29. // 1.1.4. error(...data), https://console.spec.whatwg.org/#error
  30. ThrowCompletionOr<Value> Console::error()
  31. {
  32. // 1. Perform Logger("error", data).
  33. if (m_client) {
  34. auto data = vm_arguments();
  35. return m_client->logger(LogLevel::Error, data);
  36. }
  37. return js_undefined();
  38. }
  39. // 1.1.5. info(...data), https://console.spec.whatwg.org/#info
  40. ThrowCompletionOr<Value> Console::info()
  41. {
  42. // 1. Perform Logger("info", data).
  43. if (m_client) {
  44. auto data = vm_arguments();
  45. return m_client->logger(LogLevel::Info, data);
  46. }
  47. return js_undefined();
  48. }
  49. // 1.1.6. log(...data), https://console.spec.whatwg.org/#log
  50. ThrowCompletionOr<Value> Console::log()
  51. {
  52. // 1. Perform Logger("log", data).
  53. if (m_client) {
  54. auto data = vm_arguments();
  55. return m_client->logger(LogLevel::Log, data);
  56. }
  57. return js_undefined();
  58. }
  59. // 1.1.9. warn(...data), https://console.spec.whatwg.org/#warn
  60. ThrowCompletionOr<Value> Console::warn()
  61. {
  62. // 1. Perform Logger("warn", data).
  63. if (m_client) {
  64. auto data = vm_arguments();
  65. return m_client->logger(LogLevel::Warn, data);
  66. }
  67. return js_undefined();
  68. }
  69. Value Console::clear()
  70. {
  71. if (m_client)
  72. return m_client->clear();
  73. return js_undefined();
  74. }
  75. Value Console::trace()
  76. {
  77. if (m_client)
  78. return m_client->trace();
  79. return js_undefined();
  80. }
  81. // 1.2.1. count(label), https://console.spec.whatwg.org/#count
  82. ThrowCompletionOr<Value> Console::count()
  83. {
  84. // NOTE: "default" is the default value in the IDL. https://console.spec.whatwg.org/#ref-for-count
  85. auto label = vm().argument_count() ? TRY(vm().argument(0).to_string(global_object())) : "default";
  86. // 1. Let map be the associated count map.
  87. auto& map = m_counters;
  88. // 2. If map[label] exists, set map[label] to map[label] + 1.
  89. if (auto found = map.find(label); found != map.end()) {
  90. map.set(label, found->value + 1);
  91. }
  92. // 3. Otherwise, set map[label] to 1.
  93. else {
  94. map.set(label, 1);
  95. }
  96. // 4. Let concat be the concatenation of label, U+003A (:), U+0020 SPACE, and ToString(map[label]).
  97. String concat = String::formatted("{}: {}", label, map.get(label).value());
  98. // 5. Perform Logger("count", « concat »).
  99. Vector<Value> concat_as_vector { js_string(vm(), concat) };
  100. if (m_client)
  101. TRY(m_client->logger(LogLevel::Count, concat_as_vector));
  102. return js_undefined();
  103. }
  104. // 1.2.2. countReset(label), https://console.spec.whatwg.org/#countreset
  105. ThrowCompletionOr<Value> Console::count_reset()
  106. {
  107. // NOTE: "default" is the default value in the IDL. https://console.spec.whatwg.org/#ref-for-countreset
  108. auto label = vm().argument_count() ? TRY(vm().argument(0).to_string(global_object())) : "default";
  109. // 1. Let map be the associated count map.
  110. auto& map = m_counters;
  111. // 2. If map[label] exists, set map[label] to 0.
  112. if (auto found = map.find(label); found != map.end()) {
  113. map.set(label, 0);
  114. }
  115. // 3. Otherwise:
  116. else {
  117. // 1. Let message be a string without any formatting specifiers indicating generically
  118. // that the given label does not have an associated count.
  119. auto message = String::formatted("\"{}\" doesn't have a count", label);
  120. // 2. Perform Logger("countReset", « message »);
  121. Vector<Value> message_as_vector { js_string(vm(), message) };
  122. if (m_client)
  123. TRY(m_client->logger(LogLevel::CountReset, message_as_vector));
  124. }
  125. return js_undefined();
  126. }
  127. Value Console::assert_()
  128. {
  129. if (m_client)
  130. return m_client->assert_();
  131. return js_undefined();
  132. }
  133. Vector<Value> Console::vm_arguments()
  134. {
  135. Vector<Value> arguments;
  136. arguments.ensure_capacity(vm().argument_count());
  137. for (size_t i = 0; i < vm().argument_count(); ++i) {
  138. arguments.append(vm().argument(i));
  139. }
  140. return arguments;
  141. }
  142. void Console::output_debug_message([[maybe_unused]] LogLevel log_level, [[maybe_unused]] String output) const
  143. {
  144. #ifdef __serenity__
  145. switch (log_level) {
  146. case JS::Console::LogLevel::Debug:
  147. dbgln("\033[32;1m(js debug)\033[0m {}", output);
  148. break;
  149. case JS::Console::LogLevel::Error:
  150. dbgln("\033[32;1m(js error)\033[0m {}", output);
  151. break;
  152. case JS::Console::LogLevel::Info:
  153. dbgln("\033[32;1m(js info)\033[0m {}", output);
  154. break;
  155. case JS::Console::LogLevel::Log:
  156. dbgln("\033[32;1m(js log)\033[0m {}", output);
  157. break;
  158. case JS::Console::LogLevel::Warn:
  159. dbgln("\033[32;1m(js warn)\033[0m {}", output);
  160. break;
  161. default:
  162. dbgln("\033[32;1m(js)\033[0m {}", output);
  163. break;
  164. }
  165. #endif
  166. }
  167. VM& ConsoleClient::vm()
  168. {
  169. return global_object().vm();
  170. }
  171. Vector<String> ConsoleClient::get_trace() const
  172. {
  173. Vector<String> trace;
  174. auto& execution_context_stack = m_console.global_object().vm().execution_context_stack();
  175. // NOTE: -2 to skip the console.trace() execution context
  176. for (ssize_t i = execution_context_stack.size() - 2; i >= 0; --i)
  177. trace.append(execution_context_stack[i]->function_name);
  178. return trace;
  179. }
  180. // 2.1. Logger(logLevel, args), https://console.spec.whatwg.org/#logger
  181. ThrowCompletionOr<Value> ConsoleClient::logger(Console::LogLevel log_level, Vector<Value>& args)
  182. {
  183. auto& global_object = this->global_object();
  184. // 1. If args is empty, return.
  185. if (args.is_empty())
  186. return js_undefined();
  187. // 2. Let first be args[0].
  188. auto first = args[0];
  189. // 3. Let rest be all elements following first in args.
  190. size_t rest_size = args.size() - 1;
  191. // 4. If rest is empty, perform Printer(logLevel, « first ») and return.
  192. if (rest_size == 0) {
  193. auto first_as_vector = Vector { first };
  194. return printer(log_level, first_as_vector);
  195. }
  196. // 5. If first does not contain any format specifiers, perform Printer(logLevel, args).
  197. if (!TRY(first.to_string(global_object)).contains('%')) {
  198. TRY(printer(log_level, args));
  199. } else {
  200. // 6. Otherwise, perform Printer(logLevel, Formatter(args)).
  201. auto formatted = TRY(formatter(args));
  202. TRY(printer(log_level, formatted));
  203. }
  204. // 7. Return undefined.
  205. return js_undefined();
  206. }
  207. // 2.2. Formatter(args), https://console.spec.whatwg.org/#formatter
  208. ThrowCompletionOr<Vector<Value>> ConsoleClient::formatter(Vector<Value>& args)
  209. {
  210. // TODO: Actually implement formatting
  211. return args;
  212. }
  213. }