101 lines
3.2 KiB
Objective-C
101 lines
3.2 KiB
Objective-C
/*
|
|
* Copyright @ 2019-present 8x8, Inc.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#import <React/RCTAssert.h>
|
|
|
|
#import "ReactUtils.h"
|
|
|
|
#pragma mark - Utility functions
|
|
|
|
/**
|
|
* Merges 2 sets of props into a single one.
|
|
*/
|
|
NSMutableDictionary* mergeProps(NSDictionary *a, NSDictionary *b) {
|
|
if (a == nil) {
|
|
return [NSMutableDictionary dictionaryWithDictionary:b == nil ? @{} : b];
|
|
}
|
|
|
|
if (b == nil) {
|
|
return [NSMutableDictionary dictionaryWithDictionary:a];
|
|
}
|
|
|
|
// Both have values, let's merge them, the strategy is to take the value from a first,
|
|
// then override it with the one from b. If the value is a dictionary, merge them
|
|
// recursively. Same goes for arrays.
|
|
NSMutableDictionary *result = [NSMutableDictionary dictionaryWithDictionary:a];
|
|
|
|
for (NSString *key in b) {
|
|
id value = b[key];
|
|
id aValue = result[key];
|
|
|
|
if (aValue == nil) {
|
|
result[key] = value;
|
|
continue;
|
|
}
|
|
|
|
if ([value isKindOfClass:NSArray.class]) {
|
|
result[key] = [aValue arrayByAddingObjectsFromArray:value];
|
|
} else if ([value isKindOfClass:NSDictionary.class]) {
|
|
result[key] = mergeProps(aValue, value);
|
|
} else {
|
|
result[key] = value;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* A `RCTFatalHandler` implementation which swallows JavaScript errors. In the
|
|
* Release configuration, React Native will (intentionally) raise an unhandled
|
|
* `NSException` for an unhandled JavaScript error. This will effectively kill
|
|
* the application. `_RCTFatal` is suitable to be in accord with the Web i.e.
|
|
* not kill the application.
|
|
*/
|
|
RCTFatalHandler _RCTFatal = ^(NSError *error) {
|
|
id jsStackTrace = error.userInfo[RCTJSStackTraceKey];
|
|
@try {
|
|
NSString *name
|
|
= [NSString stringWithFormat:@"%@: %@",
|
|
RCTFatalExceptionName,
|
|
error.localizedDescription];
|
|
NSString *message
|
|
= RCTFormatError(error.localizedDescription, jsStackTrace, 75);
|
|
[NSException raise:name format:@"%@", message];
|
|
} @catch (NSException *e) {
|
|
if (!jsStackTrace) {
|
|
@throw;
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Helper function to register a fatal error handler for React. Our handler
|
|
* won't kill the process, it will swallow JS errors and print stack traces
|
|
* instead.
|
|
*/
|
|
void registerReactFatalErrorHandler() {
|
|
#if !DEBUG
|
|
// In the Release configuration, React Native will (intentionally) raise an
|
|
// unhandled `NSException` for an unhandled JavaScript error. This will
|
|
// effectively kill the application. In accord with the Web, do not kill the
|
|
// application.
|
|
if (!RCTGetFatalHandler()) {
|
|
RCTSetFatalHandler(_RCTFatal);
|
|
}
|
|
#endif
|
|
}
|