You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ReactUtils.m 5.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. /*
  2. * Copyright @ 2019-present 8x8, Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #import <React/RCTAssert.h>
  17. #import <React/RCTLog.h>
  18. #import "LogUtils.h"
  19. #import "ReactUtils.h"
  20. #pragma mark - Utility functions
  21. /**
  22. * Merges 2 sets of props into a single one.
  23. */
  24. NSMutableDictionary* mergeProps(NSDictionary *a, NSDictionary *b) {
  25. if (a == nil) {
  26. return [NSMutableDictionary dictionaryWithDictionary:b == nil ? @{} : b];
  27. }
  28. if (b == nil) {
  29. return [NSMutableDictionary dictionaryWithDictionary:a];
  30. }
  31. // Both have values, let's merge them, the strategy is to take the value from a first,
  32. // then override it with the one from b. If the value is a dictionary, merge them
  33. // recursively. Same goes for arrays.
  34. NSMutableDictionary *result = [NSMutableDictionary dictionaryWithDictionary:a];
  35. for (NSString *key in b) {
  36. id value = b[key];
  37. id aValue = result[key];
  38. if (aValue == nil) {
  39. result[key] = value;
  40. continue;
  41. }
  42. if ([value isKindOfClass:NSArray.class]) {
  43. result[key] = [aValue arrayByAddingObjectsFromArray:value];
  44. } else if ([value isKindOfClass:NSDictionary.class]) {
  45. result[key] = mergeProps(aValue, value);
  46. } else {
  47. result[key] = value;
  48. }
  49. }
  50. return result;
  51. }
  52. /**
  53. * A `RCTFatalHandler` implementation which swallows JavaScript errors. In the
  54. * Release configuration, React Native will (intentionally) raise an unhandled
  55. * `NSException` for an unhandled JavaScript error. This will effectively kill
  56. * the application. `_RCTFatal` is suitable to be in accord with the Web i.e.
  57. * not kill the application.
  58. */
  59. RCTFatalHandler _RCTFatal = ^(NSError *error) {
  60. id jsStackTrace = error.userInfo[RCTJSStackTraceKey];
  61. NSString *name
  62. = [NSString stringWithFormat:@"%@: %@", RCTFatalExceptionName, error.localizedDescription];
  63. NSString *message
  64. = RCTFormatError(error.localizedDescription, jsStackTrace, -1);
  65. DDLogError(@"FATAL ERROR: %@\n%@", name, message);
  66. };
  67. /**
  68. * Helper function to register a fatal error handler for React. Our handler
  69. * won't kill the process, it will swallow JS errors and print stack traces
  70. * instead.
  71. */
  72. void registerReactFatalErrorHandler() {
  73. #if !DEBUG
  74. // In the Release configuration, React Native will (intentionally) raise an
  75. // unhandled `NSException` for an unhandled JavaScript error. This will
  76. // effectively kill the application. In accord with the Web, do not kill the
  77. // application.
  78. if (!RCTGetFatalHandler()) {
  79. RCTSetFatalHandler(_RCTFatal);
  80. }
  81. #endif
  82. }
  83. /**
  84. * A `RTCLogFunction` implementation which uses CocoaLumberjack.
  85. */
  86. RCTLogFunction _RCTLog
  87. = ^(RCTLogLevel level, __unused RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message)
  88. {
  89. // Convert RN log levels into Lumberjack's log flags.
  90. //
  91. DDLogFlag logFlag;
  92. switch (level) {
  93. case RCTLogLevelTrace:
  94. logFlag = DDLogFlagDebug;
  95. break;
  96. case RCTLogLevelInfo:
  97. logFlag = DDLogFlagInfo;
  98. break;
  99. case RCTLogLevelWarning:
  100. logFlag = DDLogFlagWarning;
  101. break;
  102. case RCTLogLevelError:
  103. logFlag = DDLogFlagError;
  104. break;
  105. case RCTLogLevelFatal:
  106. logFlag = DDLogFlagError;
  107. break;
  108. default:
  109. // Just in case more are added in the future.
  110. logFlag = DDLogFlagInfo;
  111. break;
  112. }
  113. // Build the message object we want to log.
  114. //
  115. DDLogMessage *logMessage
  116. = [[DDLogMessage alloc] initWithMessage:message
  117. level:LOG_LEVEL_DEF
  118. flag:logFlag
  119. context:0
  120. file:fileName
  121. function:nil
  122. line:[lineNumber integerValue]
  123. tag:nil
  124. options:0
  125. timestamp:nil];
  126. // Log the message. Errors are logged synchronously, and other async, as the Lumberjack defaults.
  127. //
  128. [DDLog log:logFlag != DDLogFlagError
  129. message:logMessage];
  130. };
  131. /**
  132. * Helper function which registers a React Native log handler.
  133. */
  134. void registerReactLogHandler() {
  135. RCTSetLogFunction(_RCTLog);
  136. RCTSetLogThreshold(RCTLogLevelInfo);
  137. }