• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include "console.h"
16 #include "log.h"
17 
18 namespace OHOS::JsSysModule {
19 using namespace Commonlibrary::Concurrent::Common;
20 
21 thread_local std::map<std::string, int64_t> Console::timerMap;
22 thread_local std::map<std::string, uint32_t> Console::counterMap;
23 thread_local std::string Console::groupIndent;
24 constexpr size_t GROUPINDETATIONWIDTH = 2; // 2 : indentation
25 constexpr uint32_t SECOND = 1000;
26 constexpr uint32_t MINUTE = 60 * SECOND;
27 constexpr uint32_t HOUR = 60 * MINUTE;
28 
29 std::map<std::string, std::string> tableChars = {
30     {"middleMiddle", "─"},
31     {"rowMiddle", "┼"},
32     {"topRight", "┐"},
33     {"topLeft", "┌"},
34     {"leftMiddle", "├"},
35     {"topMiddle", "┬"},
36     {"bottomRight", "┘"},
37     {"bottomLeft", "└"},
38     {"bottomMiddle", "┴"},
39     {"rightMiddle", "┤"},
40     {"left", "│ "},
41     {"right", " │"},
42     {"middle", " │ "},
43 };
44 
LogPrint(LogLevel level,const char * content)45 void Console::LogPrint(LogLevel level, const char* content)
46 {
47     switch (level) {
48         case LogLevel::DEBUG:
49             HILOG_DEBUG("%{public}s", content);
50             break;
51         case LogLevel::INFO:
52             HILOG_INFO("%{public}s", content);
53             break;
54         case LogLevel::WARN:
55             HILOG_WARN("%{public}s", content);
56             break;
57         case LogLevel::ERROR:
58             HILOG_ERROR("%{public}s", content);
59             break;
60         case LogLevel::FATAL:
61             HILOG_FATAL("%{public}s", content);
62             break;
63         default:
64             HILOG_FATAL("Console::LogPrint: this branch is unreachable");
65     }
66 }
67 
ParseLogContent(const std::vector<std::string> & params)68 std::string Console::ParseLogContent(const std::vector<std::string>& params)
69 {
70     std::string ret;
71     if (params.empty()) {
72         return ret;
73     }
74     std::string formatStr = params[0];
75     size_t size = params.size();
76     size_t len = formatStr.size();
77     size_t pos = 0;
78     size_t count = 1;
79     for (; pos < len; ++pos) {
80         if (count >= size) {
81             break;
82         }
83         if (formatStr[pos] == '%') {
84             if (pos + 1 >= len) {
85                 break;
86             }
87             switch (formatStr[pos + 1]) {
88                 case 's':
89                 case 'j':
90                 case 'd':
91                 case 'O':
92                 case 'o':
93                 case 'i':
94                 case 'f':
95                 case 'c':
96                     ret += params[count++];
97                     ++pos;
98                     break;
99                 case '%':
100                     ret += formatStr[pos];
101                     ++pos;
102                     break;
103                 default:
104                     ret += formatStr[pos];
105                     break;
106             }
107         } else {
108             ret += formatStr[pos];
109         }
110     }
111     if (pos < len) {
112         ret += formatStr.substr(pos, len - pos);
113     }
114     for (; count < size; ++count) {
115         ret += " ";
116         ret += params[count];
117     }
118     return ret;
119 }
120 
MakeLogContent(napi_env env,napi_callback_info info,size_t & argc,size_t startIdx,bool format)121 std::string Console::MakeLogContent(napi_env env, napi_callback_info info, size_t& argc, size_t startIdx, bool format)
122 {
123     std::vector<std::string> content;
124     content.reserve(argc);
125     // get argv
126     napi_value* argv = new napi_value[argc];
127     Helper::ObjectScope<napi_value> scope(argv, true);
128     napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
129 
130     for (size_t i = startIdx; i < argc; i++) {
131         if (!Helper::NapiHelper::IsString(env, argv[i])) {
132             napi_value buffer;
133             napi_status status = napi_coerce_to_string(env, argv[i], &buffer);
134             if (status != napi_ok) {
135                 HILOG_ERROR("Console log failed to convert to string object");
136                 continue;
137             }
138             argv[i] = buffer;
139         }
140         std::string stringValue = Helper::NapiHelper::GetPrintString(env, argv[i]);
141         if (stringValue.empty()) {
142             continue;
143         }
144         content.emplace_back(stringValue);
145     }
146     if (format) {
147         return ParseLogContent(content);
148     } else {
149         std::string ret;
150         size_t size = content.size();
151         for (size_t i = 0; i < size; ++i) {
152             ret += " ";
153             ret += content[i];
154         }
155         return ret;
156     }
157 }
158 
StringRepeat(size_t number,const std::string & tableChars)159 std::string Console::StringRepeat(size_t number, const std::string& tableChars)
160 {
161     std::string divider;
162     size_t length = number;
163     for (size_t i = 0; i < length; i++) {
164         divider += tableChars;
165     }
166     return divider;
167 }
168 
169 
170 template<LogLevel LEVEL>
ConsoleLog(napi_env env,napi_callback_info info)171 napi_value Console::ConsoleLog(napi_env env, napi_callback_info info)
172 {
173     size_t argc = Helper::NapiHelper::GetCallbackInfoArgc(env, info);
174     if (argc < 1) {
175         return Helper::NapiHelper::GetUndefinedValue(env);
176     }
177     std::string content;
178     content += groupIndent;
179     content += MakeLogContent(env, info, argc, 0); // startInx = 0
180     LogPrint(LEVEL, content.c_str());
181     return Helper::NapiHelper::GetUndefinedValue(env);
182 }
183 
GetTimerOrCounterName(napi_env env,napi_callback_info info,size_t argc)184 std::string Console::GetTimerOrCounterName(napi_env env, napi_callback_info info, size_t argc)
185 {
186     if (argc < 1) {
187         return "default";
188     }
189     napi_value* argv = new napi_value[argc];
190     Helper::ObjectScope<napi_value> scope(argv, true);
191     napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
192     if (!Helper::NapiHelper::IsString(env, argv[0])) {
193         napi_value buffer = nullptr;
194         napi_status status = napi_coerce_to_string(env, argv[0], &buffer);
195         if (status != napi_ok) {
196             Helper::ErrorHelper::ThrowError(env, Helper::ErrorHelper::TYPE_ERROR,
197                 "the type of Timer or Counter name must be string.");
198             return "";
199         }
200         argv[0] = buffer;
201     }
202     std::string name = Helper::NapiHelper::GetPrintString(env, argv[0]);
203     if (name.empty()) {
204         Helper::ErrorHelper::ThrowError(env, Helper::ErrorHelper::TYPE_ERROR,
205                                         "Timer or Counter name must be not null.");
206         return "";
207     }
208     return name;
209 }
210 
Count(napi_env env,napi_callback_info info)211 napi_value Console::Count(napi_env env, napi_callback_info info)
212 {
213     size_t argc = Helper::NapiHelper::GetCallbackInfoArgc(env, info);
214     std::string counterName = GetTimerOrCounterName(env, info, argc);
215     counterMap[counterName]++;
216     HILOG_INFO("%{public}s%{public}s: %{public}d",
217                groupIndent.c_str(), counterName.c_str(), counterMap[counterName]);
218     return Helper::NapiHelper::GetUndefinedValue(env);
219 }
220 
CountReset(napi_env env,napi_callback_info info)221 napi_value Console::CountReset(napi_env env, napi_callback_info info)
222 {
223     size_t argc = Helper::NapiHelper::GetCallbackInfoArgc(env, info);
224     std::string counterName = GetTimerOrCounterName(env, info, argc);
225     if (counterMap.find(counterName) == counterMap.end()) {
226         HILOG_WARN("%{public}sCounter %{public}s doesn't exists, please check Counter Name.",
227                    groupIndent.c_str(), counterName.c_str());
228         return Helper::NapiHelper::GetUndefinedValue(env);
229     }
230     counterMap.erase(counterName);
231     return Helper::NapiHelper::GetUndefinedValue(env);
232 }
233 
Dir(napi_env env,napi_callback_info info)234 napi_value Console::Dir(napi_env env, napi_callback_info info)
235 {
236     size_t argc = Helper::NapiHelper::GetCallbackInfoArgc(env, info);
237     if (argc < 1) {
238         HILOG_INFO("%{public}sundefined", groupIndent.c_str());
239         return Helper::NapiHelper::GetUndefinedValue(env);
240     }
241     napi_value* argv = new napi_value[argc];
242     Helper::ObjectScope<napi_value> scope(argv, true);
243     napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
244     std::string ctorVal = Helper::NapiHelper::GetConstructorName(env, argv[0]);
245     // JSON.stringify()
246     napi_value globalValue = nullptr;
247     napi_get_global(env, &globalValue);
248     napi_value jsonValue;
249     napi_get_named_property(env, globalValue, "JSON", &jsonValue);
250     napi_value stringifyValue = nullptr;
251     napi_get_named_property(env, jsonValue, "stringify", &stringifyValue);
252     napi_value transValue = nullptr;
253     napi_call_function(env, jsonValue, stringifyValue, 1, &argv[0], &transValue);
254     if (transValue == nullptr) {
255         Helper::ErrorHelper::ThrowError(env, Helper::ErrorHelper::TYPE_ERROR, "Dir content must not be null.");
256         return Helper::NapiHelper::GetUndefinedValue(env);
257     }
258     std::string content = Helper::NapiHelper::GetPrintString(env, transValue);
259     bool functionFlag = Helper::NapiHelper::IsFunction(env, argv[0]);
260     if (!ctorVal.empty() && !functionFlag) {
261         HILOG_INFO("%{public}s%{public}s: %{public}s", groupIndent.c_str(), ctorVal.c_str(), content.c_str());
262     } else if (!ctorVal.empty() && functionFlag) {
263         HILOG_INFO("%{public}s[Function %{public}s]", groupIndent.c_str(), ctorVal.c_str());
264     } else {
265         HILOG_INFO("%{public}s%{public}s", groupIndent.c_str(), content.c_str());
266     }
267     return Helper::NapiHelper::GetUndefinedValue(env);
268 }
269 
Group(napi_env env,napi_callback_info info)270 napi_value Console::Group(napi_env env, napi_callback_info info)
271 {
272     size_t argc = Helper::NapiHelper::GetCallbackInfoArgc(env, info);
273     if (argc > 0) {
274         ConsoleLog<LogLevel::INFO>(env, info);
275     }
276     groupIndent += StringRepeat(GROUPINDETATIONWIDTH, " ");
277     return Helper::NapiHelper::GetUndefinedValue(env);
278 }
279 
GroupEnd(napi_env env,napi_callback_info info)280 napi_value Console::GroupEnd(napi_env env, napi_callback_info info)
281 {
282     size_t length = groupIndent.size();
283     if (length >= GROUPINDETATIONWIDTH) {
284         groupIndent = groupIndent.substr(0, length - GROUPINDETATIONWIDTH);
285     }
286     return Helper::NapiHelper::GetUndefinedValue(env);
287 }
288 
ArrayJoin(std::vector<std::string> rowDivider,const std::string & tableChars)289 std::string Console::ArrayJoin(std::vector<std::string> rowDivider, const std::string& tableChars)
290 {
291     size_t size = rowDivider.size();
292     if (size == 0) {
293         return "no rowDivider";
294     }
295     std::string result = rowDivider[0];
296     for (size_t i = 1; i < size; i++) {
297         result += tableChars;
298         result += rowDivider[i];
299     }
300     return result;
301 }
302 
RenderHead(napi_env env,napi_value head,std::vector<size_t> columnWidths)303 std::string Console::RenderHead(napi_env env, napi_value head, std::vector<size_t> columnWidths)
304 {
305     std::string result = tableChars["left"];
306     size_t length = columnWidths.size();
307     for (size_t i = 0; i < length; i++) {
308         napi_value element = nullptr;
309         napi_get_element(env, head, i, &element);
310         napi_value string = nullptr;
311         napi_status status = napi_coerce_to_string(env, element, &string);
312         if (status != napi_ok) {
313             Helper::ErrorHelper::ThrowError(env, Helper::ErrorHelper::TYPE_ERROR,
314                                             "Table elements can't convert to string.");
315             return "";
316         }
317         std::string elemStr = Helper::NapiHelper::GetPrintString(env, string);
318         size_t stringLen = elemStr.size();
319         size_t left = (columnWidths[i] - stringLen) / 2; // 2: half
320         size_t right = columnWidths[i] - stringLen - left;
321         result += StringRepeat(left, " ") + elemStr + StringRepeat(right, " ");
322         if (i != length - 1) {
323             result += tableChars["middle"];
324         }
325     }
326     result += tableChars["right"];
327     return result;
328 }
329 
GetStringAndStringWidth(napi_env env,napi_value element,size_t & stringLen)330 std::string Console::GetStringAndStringWidth(napi_env env, napi_value element, size_t& stringLen)
331 {
332     napi_value string = nullptr;
333     napi_status status = napi_coerce_to_string(env, element, &string);
334     if (status != napi_ok) {
335         Helper::ErrorHelper::ThrowError(env, Helper::ErrorHelper::TYPE_ERROR,
336                                         "GetStringAndStringWidth: can't convert to string.");
337         return "";
338     }
339     std::string result = Helper::NapiHelper::GetPrintString(env, string);
340     napi_valuetype valuetype;
341     napi_typeof(env, element, &valuetype);
342     if (valuetype != napi_undefined) {
343         stringLen = result.size();  // If element type is undefined, length is 0.
344     }
345     return result;
346 }
347 
PrintRows(napi_env env,napi_value Rows,std::vector<size_t> columnWidths,size_t indexNum)348 void Console::PrintRows(napi_env env, napi_value Rows, std::vector<size_t> columnWidths, size_t indexNum)
349 {
350     size_t length = columnWidths.size();
351     for (size_t i = 0; i < indexNum; i++) {
352         std::string result = tableChars["left"];
353         for (size_t j = 0; j < length; j++) {
354             napi_value element = nullptr;
355             napi_get_element(env, Rows, j * indexNum + i, &element);
356             size_t stringLen = 0;
357             std::string stringVal = GetStringAndStringWidth(env, element, stringLen);
358             if (stringLen > 0) {
359                 size_t left = (columnWidths[j] - stringLen) / 2; // 2: half
360                 size_t right = columnWidths[j] - stringLen - left;
361                 result += StringRepeat(left, " ") + stringVal + StringRepeat(right, " ");
362             } else {
363                 result += StringRepeat(columnWidths[j], " ");
364             }
365             if (j != length - 1) {
366                 result += tableChars["middle"];
367             }
368         }
369         result += tableChars["right"];
370         HILOG_INFO("%{public}s%{public}s", groupIndent.c_str(), result.c_str());
371     }
372 }
373 
GraphTable(napi_env env,napi_value head,napi_value columns,const size_t & length)374 void Console::GraphTable(napi_env env, napi_value head, napi_value columns, const size_t& length)
375 {
376     uint32_t columnLen = 0;
377     napi_get_array_length(env, head, &columnLen);
378     std::vector<size_t> columnWidths(columnLen);
379     std::vector<std::string> rowDivider(columnLen);
380     // get maxColumnWidths and get rowDivider(------)
381     // get key string length
382     for (size_t i = 0; i < columnLen; i++) {
383         napi_value element = nullptr;
384         napi_get_element(env, head, i, &element);
385         size_t stringLen = 0;
386         GetStringAndStringWidth(env, element, stringLen);
387         columnWidths[i] = stringLen;
388     }
389     // compare key/value string and get max length
390     for (size_t i = 0; i < columnLen; i++) {
391         for (size_t j = 0; j < length; j++) {
392             napi_value element = nullptr;
393             napi_get_element(env, columns, i * length + j, &element);
394             size_t stringLen = 0;
395             GetStringAndStringWidth(env, element, stringLen);
396             columnWidths[i] = columnWidths[i] > stringLen ? columnWidths[i] :  stringLen;
397         }
398         rowDivider[i] = StringRepeat(columnWidths[i] + 2, tableChars["middleMiddle"]); // 2: two space
399     }
400     // print head row
401     std::string indexRow1 = tableChars["topLeft"] +
402                             ArrayJoin(rowDivider, tableChars["topMiddle"]) +
403                             tableChars["topRight"];
404     std::string indexRow2 = RenderHead(env, head, columnWidths);
405     std::string indexRow3 = tableChars["leftMiddle"] +
406                             ArrayJoin(rowDivider, tableChars["rowMiddle"]) +
407                             tableChars["rightMiddle"];
408     HILOG_INFO("%{public}s%{public}s", groupIndent.c_str(), indexRow1.c_str());
409     HILOG_INFO("%{public}s%{public}s", groupIndent.c_str(), indexRow2.c_str());
410     HILOG_INFO("%{public}s%{public}s", groupIndent.c_str(), indexRow3.c_str());
411     // print value row
412     PrintRows(env, columns, columnWidths, length);
413     // print end row
414     std::string endRow = tableChars["bottomLeft"] +
415                          ArrayJoin(rowDivider, tableChars["bottomMiddle"]) +
416                          tableChars["bottomRight"];
417     HILOG_INFO("%{public}s%{public}s", groupIndent.c_str(), endRow.c_str());
418 }
419 
GetKeyArray(napi_env env,napi_value map)420 napi_value GetKeyArray(napi_env env, napi_value map)
421 {
422     napi_value mapKeys = nullptr;
423     napi_object_get_keys(env, map, &mapKeys);
424     uint32_t maplen = 0;
425     napi_get_array_length(env, mapKeys, &maplen);
426 
427     size_t keyLength = maplen + 1;
428     napi_value outputKeysArray = nullptr;
429     napi_create_array_with_length(env, keyLength, &outputKeysArray);
430     // set (index) to array
431     napi_value result = nullptr;
432     napi_create_string_utf8(env, "(index)", NAPI_AUTO_LENGTH, &result);
433     napi_set_element(env, outputKeysArray, 0, result);
434 
435     // set Keys to array
436     for (size_t j = 0; j < maplen ; ++j) {
437         napi_value keyNumber = nullptr;
438         napi_get_element(env, mapKeys, j, &keyNumber);
439         napi_set_element(env, outputKeysArray, j + 1, keyNumber); // startkeyIdx = 1
440     }
441     return outputKeysArray;
442 }
443 
GetValueArray(napi_env env,napi_value map,const size_t & length,napi_value keyArray)444 napi_value GetValueArray(napi_env env, napi_value map, const size_t& length, napi_value keyArray)
445 {
446     napi_value mapKeys = nullptr;
447     napi_object_get_keys(env, map, &mapKeys);
448     uint32_t maplen = 0;
449     napi_get_array_length(env, mapKeys, &maplen);
450     size_t keyLength = maplen + 1;
451 
452     size_t valueLength = keyLength * length;
453     napi_value outputValuesArray = nullptr;
454     napi_create_array_with_length(env, valueLength, &outputValuesArray);
455     // set indexKeyValue
456     size_t valueIdx = 0;
457     for (size_t j = 0; j < length ; ++j) {
458         napi_value keyNumber = nullptr;
459         napi_get_element(env, keyArray, j, &keyNumber);
460         napi_set_element(env, outputValuesArray, valueIdx++, keyNumber);
461     }
462     for (size_t i = 0; i < maplen ; ++i) {
463         napi_value keyNumber = nullptr;
464         napi_get_element(env, mapKeys, i, &keyNumber);
465         char* innerKey = Helper::NapiHelper::GetChars(env, keyNumber);
466         if (innerKey == nullptr) {
467             Helper::ErrorHelper::ThrowError(env, Helper::ErrorHelper::TYPE_ERROR,
468                                             "property key must not be null.");
469             return Helper::NapiHelper::GetUndefinedValue(env);
470         }
471         napi_value valueNumber = nullptr;
472         napi_get_named_property(env, map, innerKey, &valueNumber);
473         Helper::CloseHelp::DeletePointer(innerKey, true);
474         for (size_t j = 0; j < length ; ++j) {
475             napi_value value = nullptr;
476             napi_get_element(env, valueNumber, j, &value);
477             napi_set_element(env, outputValuesArray, valueIdx++, value);
478         }
479     }
480     return outputValuesArray;
481 }
482 
SetPrimitive(napi_env env,napi_value map,const size_t & length,napi_value valuesKeyArray,napi_value outputKeysArray,napi_value outputValuesArray)483 void SetPrimitive(napi_env env, napi_value map, const size_t& length, napi_value valuesKeyArray,
484                   napi_value outputKeysArray, napi_value outputValuesArray)
485 {
486     napi_value mapKeys = nullptr;
487     napi_object_get_keys(env, map, &mapKeys);
488     uint32_t maplen = 0;
489     napi_get_array_length(env, mapKeys, &maplen);
490     napi_value result = nullptr;
491     napi_create_string_utf8(env, "Values", NAPI_AUTO_LENGTH, &result);
492     napi_set_element(env, outputKeysArray, maplen + 1, result);
493     uint32_t valuesLen = 0;
494     napi_get_array_length(env, valuesKeyArray, &valuesLen);
495     size_t startVal = (maplen + 1) * length;
496     for (size_t j = 0; j < length ; ++j) {
497         napi_value value = nullptr;
498         napi_get_element(env, valuesKeyArray, j, &value);
499         napi_set_element(env, outputValuesArray, startVal + j, value);
500     }
501 }
502 
ProcessNestedObject(napi_env env,napi_value item,napi_value & map,std::map<std::string,bool> & initialMap,size_t index)503 void ProcessNestedObject(napi_env env, napi_value item, napi_value& map, std::map<std::string, bool>& initialMap,
504                          size_t index)
505 {
506     napi_value keys = nullptr;
507     napi_object_get_keys(env, item, &keys);
508     uint32_t innerLength = 0;
509     napi_get_array_length(env, keys, &innerLength);
510     for (size_t j = 0; j < innerLength; ++j) {
511         napi_value keyNumber = nullptr;
512         napi_get_element(env, keys, j, &keyNumber);
513         char* innerKey = Helper::NapiHelper::GetChars(env, keyNumber);
514         if (innerKey == nullptr) {
515             Helper::ErrorHelper::ThrowError(env, Helper::ErrorHelper::TYPE_ERROR,
516                                             "property key must not be null.");
517             return;
518         }
519         napi_value innerItem = nullptr;
520         napi_get_named_property(env, item, innerKey, &innerItem);
521         if (initialMap.find(std::string(innerKey)) == initialMap.end()) {
522             napi_value mapArray = nullptr;
523             napi_create_array_with_length(env, innerLength, &mapArray);
524             napi_set_element(env, mapArray, index, innerItem);
525             napi_set_named_property(env, map, innerKey, mapArray);
526             initialMap[innerKey] = true;
527         } else {
528             napi_value mapArray = nullptr;
529             napi_get_named_property(env, map, innerKey, &mapArray);
530             napi_set_element(env, mapArray, index, innerItem);
531             napi_set_named_property(env, map, innerKey, mapArray);
532         }
533         Helper::CloseHelp::DeletePointer(innerKey, true);
534     }
535 }
536 
InitializeValuesKeyArray(napi_env env,napi_value valuesKeyArray,uint32_t length)537 void InitializeValuesKeyArray(napi_env env, napi_value valuesKeyArray, uint32_t length)
538 {
539     for (size_t j = 0; j < length ; ++j) {
540         napi_value result = nullptr;
541         napi_create_string_utf8(env, "", NAPI_AUTO_LENGTH, &result);
542         napi_set_element(env, valuesKeyArray, j, result);
543     }
544 }
545 
ProcessTabularData(napi_env env,napi_value tabularData)546 napi_value Console::ProcessTabularData(napi_env env, napi_value tabularData)
547 {
548     napi_value keyArray = nullptr;
549     napi_object_get_keys(env, tabularData, &keyArray);
550     uint32_t length = 0;
551     napi_get_array_length(env, keyArray, &length);
552     napi_value valuesKeyArray = nullptr;
553     napi_create_array_with_length(env, length, &valuesKeyArray);
554 
555     napi_value map = nullptr;
556     napi_create_object(env, &map);
557     bool hasPrimitive = false;
558     bool primitiveInit = false;
559     std::map<std::string, bool> initialMap;
560 
561     for (size_t i = 0; i < length; i++) {
562         napi_value keyItem = nullptr;
563         napi_get_element(env, keyArray, i, &keyItem);
564         char* key = Helper::NapiHelper::GetChars(env, keyItem);
565         if (key == nullptr) {
566             Helper::ErrorHelper::ThrowError(env, Helper::ErrorHelper::TYPE_ERROR,
567                                             "property key must not be null.");
568             return Helper::NapiHelper::GetUndefinedValue(env);
569         }
570         napi_value item = nullptr;
571         napi_get_named_property(env, tabularData, key, &item);
572         Helper::CloseHelp::DeletePointer(key, true);
573         bool isPrimitive = ((item == nullptr) ||
574                             (!Helper::NapiHelper::IsObject(env, item) && !Helper::NapiHelper::IsFunction(env, item)));
575         if (isPrimitive) {
576             if (!primitiveInit) {
577                 InitializeValuesKeyArray(env, valuesKeyArray, length);
578                 primitiveInit = true;
579             }
580             hasPrimitive = true;
581             napi_set_element(env, valuesKeyArray, i, item);
582         } else {
583             ProcessNestedObject(env, item, map, initialMap, i);
584         }
585     }
586     // set outputKeysArray
587     napi_value outputKeysArray = GetKeyArray(env, map);
588     // set outputValuesArray
589     napi_value outputValuesArray = GetValueArray(env, map, length, keyArray);
590     // if has Primitive, add new colomn Values
591     if (hasPrimitive) {
592         SetPrimitive(env, map, length, valuesKeyArray, outputKeysArray, outputValuesArray);
593     }
594     GraphTable(env, outputKeysArray, outputValuesArray, length);
595     return Helper::NapiHelper::GetUndefinedValue(env);
596 }
597 
Table(napi_env env,napi_callback_info info)598 napi_value Console::Table(napi_env env, napi_callback_info info)
599 {
600     size_t argc = Helper::NapiHelper::GetCallbackInfoArgc(env, info);
601     if (argc < 1) {
602         return Helper::NapiHelper::GetUndefinedValue(env);
603     }
604     napi_value* argv = new napi_value[argc];
605     Helper::ObjectScope<napi_value> scope(argv, true);
606     napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
607     if (!Helper::NapiHelper::IsObject(env, argv[0])) {
608         ConsoleLog<LogLevel::INFO>(env, info);
609     }
610     napi_value tabularData = argv[0];
611     return ProcessTabularData(env, tabularData);
612 }
613 
PrintTime(std::string timerName,double time,const std::string & log)614 void Console::PrintTime(std::string timerName, double time, const std::string& log)
615 {
616     uint32_t hours = 0;
617     uint32_t minutes = 0;
618     uint32_t seconds = 0;
619     uint32_t ms = time;
620     if (ms >= SECOND) {
621         if (ms >= MINUTE) {
622             if (ms >= HOUR) {
623                 hours = ms / HOUR;
624                 ms = ms - HOUR * hours;
625             }
626             minutes = ms / MINUTE;
627             ms = ms - MINUTE * minutes;
628         }
629         seconds = ms / SECOND;
630         ms = ms - SECOND * seconds;
631     }
632     if (hours != 0) {
633         HILOG_INFO("%{public}s%{public}s: %{public}d:%{public}.2d:%{public}.2d.%{public}.3d(h:m:s.mm) %{public}s",
634             groupIndent.c_str(), timerName.c_str(), hours, minutes, seconds, ms, log.c_str());
635         return;
636     }
637     if (minutes != 0) {
638         HILOG_INFO("%{public}s%{public}s: %{public}d:%{public}.2d.%{public}.3d(m:s.mm) %{public}s",
639             groupIndent.c_str(), timerName.c_str(), minutes, seconds, ms, log.c_str());
640         return;
641     }
642     if (seconds != 0) {
643         HILOG_INFO("%{public}s%{public}s: %{public}d.%{public}.3ds %{public}s",
644             groupIndent.c_str(), timerName.c_str(), seconds, ms, log.c_str());
645         return;
646     }
647     HILOG_INFO("%{public}s%{public}s: %{public}.3fms %{public}s",
648         groupIndent.c_str(), timerName.c_str(), time, log.c_str());
649 }
650 
Time(napi_env env,napi_callback_info info)651 napi_value Console::Time(napi_env env, napi_callback_info info)
652 {
653     size_t argc = Helper::NapiHelper::GetCallbackInfoArgc(env, info);
654     std::string timerName = GetTimerOrCounterName(env, info, argc);
655     if (timerMap.find(timerName) == timerMap.end()) {
656         timerMap[timerName] = std::chrono::duration_cast<std::chrono::microseconds>
657                               (std::chrono::high_resolution_clock::now().time_since_epoch()).count();
658     } else {
659         HILOG_WARN("Timer %{public}s already exists,  please check Timer Name", timerName.c_str());
660     }
661     return Helper::NapiHelper::GetUndefinedValue(env);
662 }
663 
TimeLog(napi_env env,napi_callback_info info)664 napi_value Console::TimeLog(napi_env env, napi_callback_info info)
665 {
666     size_t argc = Helper::NapiHelper::GetCallbackInfoArgc(env, info);
667     std::string timerName = GetTimerOrCounterName(env, info, argc);
668     if (timerMap.find(timerName) != timerMap.end()) {
669         // get time in ms
670         int64_t endTime = std::chrono::duration_cast<std::chrono::microseconds>
671                           (std::chrono::high_resolution_clock::now().time_since_epoch()).count();
672         double ms = static_cast<uint64_t>(endTime - timerMap[timerName]) / 1000.0;
673         std::string content = MakeLogContent(env, info, argc, 1, false); // startInx = 1, format = false;
674         PrintTime(timerName, ms, content);
675     } else {
676         HILOG_WARN("%{public}sTimer %{public}s doesn't exists, please check Timer Name.",
677                    groupIndent.c_str(), timerName.c_str());
678     }
679     return Helper::NapiHelper::GetUndefinedValue(env);
680 }
681 
TimeEnd(napi_env env,napi_callback_info info)682 napi_value Console::TimeEnd(napi_env env, napi_callback_info info)
683 {
684     size_t argc = Helper::NapiHelper::GetCallbackInfoArgc(env, info);
685     std::string timerName = GetTimerOrCounterName(env, info, argc);
686     if (timerMap.find(timerName) != timerMap.end()) {
687         // get time in ms
688         int64_t endTime = std::chrono::duration_cast<std::chrono::microseconds>
689                           (std::chrono::high_resolution_clock::now().time_since_epoch()).count();
690         double ms = static_cast<uint64_t>(endTime - timerMap[timerName]) / 1000.0;
691         PrintTime(timerName, ms, "");
692         timerMap.erase(timerName);
693     } else {
694         HILOG_WARN("%{public}sTimer %{public}s doesn't exists, please check Timer Name.",
695                    groupIndent.c_str(), timerName.c_str());
696     }
697     return Helper::NapiHelper::GetUndefinedValue(env);
698 }
699 
Trace(napi_env env,napi_callback_info info)700 napi_value Console::Trace(napi_env env, napi_callback_info info)
701 {
702     size_t argc = Helper::NapiHelper::GetCallbackInfoArgc(env, info);
703     std::string content;
704     if (argc > 0) {
705         content = MakeLogContent(env, info, argc, 0); // startInx = 0
706     }
707     HILOG_INFO("%{public}sTrace: %{public}s", groupIndent.c_str(), content.c_str());
708     std::string stack;
709     napi_get_stack_trace(env, stack);
710     std::string tempStr = "";
711     for (size_t i = 0; i < stack.length(); i++) {
712         if (stack[i] == '\n') {
713             HILOG_INFO("%{public}s%{public}s", groupIndent.c_str(), tempStr.c_str());
714             tempStr = "";
715         } else {
716             tempStr += stack[i];
717         }
718     }
719     return Helper::NapiHelper::GetUndefinedValue(env);
720 }
721 
TraceHybridStack(napi_env env,napi_callback_info info)722 napi_value Console::TraceHybridStack(napi_env env, napi_callback_info info)
723 {
724     std::string stack;
725     napi_get_hybrid_stack_trace(env, stack);
726     HILOG_INFO("%{public}sTraceHybridStack: ", groupIndent.c_str());
727     std::string tempStr = "";
728     for (size_t i = 0; i < stack.length(); i++) {
729         if (stack[i] == '\n') {
730             HILOG_INFO("%{public}s%{public}s", groupIndent.c_str(), tempStr.c_str());
731             tempStr = "";
732         } else {
733             tempStr += stack[i];
734         }
735     }
736     return Helper::NapiHelper::GetUndefinedValue(env);
737 }
738 
Assert(napi_env env,napi_callback_info info)739 napi_value Console::Assert(napi_env env, napi_callback_info info)
740 {
741     // 1. check args
742     size_t argc = Helper::NapiHelper::GetCallbackInfoArgc(env, info);
743     if (argc < 1) {
744         HILOG_ERROR("%{public}sAssertion failed", groupIndent.c_str());
745         return Helper::NapiHelper::GetUndefinedValue(env);
746     }
747     napi_value* argv = new napi_value[argc];
748     Helper::ObjectScope<napi_value> scope(argv, true);
749     napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
750 
751     if (Helper::NapiHelper::GetBooleanValue(env, argv[0])) {
752         return Helper::NapiHelper::GetUndefinedValue(env);
753     }
754     std::string content = "Assertion failed";
755     if (argc > 1) {
756         content += ":";
757         content += MakeLogContent(env, info, argc, 1); // startIndex = 1
758     }
759     HILOG_ERROR("%{public}s%{public}s", groupIndent.c_str(), content.c_str());
760     return Helper::NapiHelper::GetUndefinedValue(env);
761 }
762 
InitConsoleModule(napi_env env)763 void Console::InitConsoleModule(napi_env env)
764 {
765     napi_property_descriptor properties[] = {
766         DECLARE_NAPI_DEFAULT_PROPERTY_FUNCTION("log", ConsoleLog<LogLevel::INFO>),
767         DECLARE_NAPI_DEFAULT_PROPERTY_FUNCTION("debug", ConsoleLog<LogLevel::DEBUG>),
768         DECLARE_NAPI_DEFAULT_PROPERTY_FUNCTION("info", ConsoleLog<LogLevel::INFO>),
769         DECLARE_NAPI_DEFAULT_PROPERTY_FUNCTION("warn", ConsoleLog<LogLevel::WARN>),
770         DECLARE_NAPI_DEFAULT_PROPERTY_FUNCTION("error", ConsoleLog<LogLevel::ERROR>),
771         DECLARE_NAPI_DEFAULT_PROPERTY_FUNCTION("fatal", ConsoleLog<LogLevel::FATAL>),
772         DECLARE_NAPI_DEFAULT_PROPERTY_FUNCTION("group", Group),
773         DECLARE_NAPI_DEFAULT_PROPERTY_FUNCTION("groupCollapsed", Group),
774         DECLARE_NAPI_DEFAULT_PROPERTY_FUNCTION("groupEnd", GroupEnd),
775         DECLARE_NAPI_DEFAULT_PROPERTY_FUNCTION("table", Table),
776         DECLARE_NAPI_DEFAULT_PROPERTY_FUNCTION("time", Time),
777         DECLARE_NAPI_DEFAULT_PROPERTY_FUNCTION("timeLog", TimeLog),
778         DECLARE_NAPI_DEFAULT_PROPERTY_FUNCTION("timeEnd", TimeEnd),
779         DECLARE_NAPI_DEFAULT_PROPERTY_FUNCTION("trace", Trace),
780         DECLARE_NAPI_DEFAULT_PROPERTY_FUNCTION("traceHybridStack", TraceHybridStack),
781         DECLARE_NAPI_DEFAULT_PROPERTY_FUNCTION("assert", Assert),
782         DECLARE_NAPI_DEFAULT_PROPERTY_FUNCTION("count", Count),
783         DECLARE_NAPI_DEFAULT_PROPERTY_FUNCTION("countReset", CountReset),
784         DECLARE_NAPI_DEFAULT_PROPERTY_FUNCTION("dir", Dir),
785         DECLARE_NAPI_DEFAULT_PROPERTY_FUNCTION("dirxml", ConsoleLog<LogLevel::INFO>)
786     };
787     napi_value globalObj = Helper::NapiHelper::GetGlobalObject(env);
788     napi_value console = nullptr;
789     napi_create_object(env, &console);
790     napi_define_properties(env, console, sizeof(properties) / sizeof(properties[0]), properties);
791     napi_set_named_property(env, globalObj, "console", console);
792 }
793 } // namespace Commonlibrary::JsSysModule