diff --git a/React/Base/RCTConvert.h b/React/Base/RCTConvert.h index 2c1c84ee8..0fbc8a845 100644 --- a/React/Base/RCTConvert.h +++ b/React/Base/RCTConvert.h @@ -7,6 +7,8 @@ * of patent rights can be found in the PATENTS file in the same directory. */ +#import + #import #import @@ -172,6 +174,8 @@ RCT_CUSTOM_CONVERTER(type, name, [json getter]) #define RCT_NUMBER_CONVERTER(type, getter) \ RCT_CUSTOM_CONVERTER(type, type, [[self NSNumber:json] getter]) +NSNumber *RCTEnumConverterImpl(const char *typeName, NSDictionary *values, NSNumber *defaultValue, id json); + /** * This macro is used for creating converters for enum types. */ @@ -183,25 +187,8 @@ RCT_CUSTOM_CONVERTER(type, type, [[self NSNumber:json] getter]) dispatch_once(&onceToken, ^{ \ mapping = values; \ }); \ - if (!json || json == [NSNull null]) { \ - return default; \ - } \ - if ([json isKindOfClass:[NSNumber class]]) { \ - if ([[mapping allValues] containsObject:json] || [json getter] == default) { \ - return [json getter]; \ - } \ - RCTLogError(@"Invalid %s '%@'. should be one of: %@", #type, json, [mapping allValues]); \ - return default; \ - } \ - if (![json isKindOfClass:[NSString class]]) { \ - RCTLogError(@"Expected NSNumber or NSString for %s, received %@: %@", \ - #type, [json classForCoder], json); \ - } \ - id value = mapping[json]; \ - if(!value && [json description].length > 0) { \ - RCTLogError(@"Invalid %s '%@'. should be one of: %@", #type, json, [mapping allKeys]); \ - } \ - return value ? [value getter] : default; \ + NSNumber *converted = RCTEnumConverterImpl(#type, mapping, @(default), json); \ + return ((type(*)(id, SEL))objc_msgSend)(converted, @selector(getter)); \ } /** diff --git a/React/Base/RCTConvert.m b/React/Base/RCTConvert.m index 6fa1c2227..cb9cc7ec6 100644 --- a/React/Base/RCTConvert.m +++ b/React/Base/RCTConvert.m @@ -115,6 +115,36 @@ RCT_CUSTOM_CONVERTER(NSTimeInterval, NSTimeInterval, [self double:json] / 1000.0 // JS standard for time zones is minutes. RCT_CUSTOM_CONVERTER(NSTimeZone *, NSTimeZone, [NSTimeZone timeZoneForSecondsFromGMT:[self double:json] * 60.0]) +static void logInvalidJSONObjectError(const char *typeName, id json, NSArray *expectedValues) +{ + RCTLogError(@"Invalid %s '%@'. should be one of: %@", typeName, json, expectedValues); +} + +NSNumber *RCTEnumConverterImpl(const char *typeName, NSDictionary *mapping, NSNumber *defaultValue, id json) +{ + if (!json || json == (id)kCFNull) { + return defaultValue; + } + if ([json isKindOfClass:[NSNumber class]]) { + NSArray *allValues = [mapping allValues]; + if ([[mapping allValues] containsObject:json] || [json isEqual:defaultValue]) { + return json; + } + logInvalidJSONObjectError(typeName, json, allValues); + return defaultValue; + } + + if (![json isKindOfClass:[NSString class]]) { + RCTLogError(@"Expected NSNumber or NSString for %s, received %@: %@", + typeName, [json classForCoder], json); + } + id value = mapping[json]; + if (!value && [json description].length > 0) { + logInvalidJSONObjectError(typeName, json, [mapping allKeys]); + } + return value ?: defaultValue; +} + RCT_ENUM_CONVERTER(NSTextAlignment, (@{ @"auto": @(NSTextAlignmentNatural), @"left": @(NSTextAlignmentLeft),