Introduce TypeUtils (#42122)

Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/42122

This diff introduces the `TypeUtils` directory where we can put platform-specific, context-independent type transformations.

Changelog: [Internal]

Reviewed By: cipolleschi

Differential Revision: D52291837

fbshipit-source-id: 561b9c494aab5bfee3b3c668d3346bbd320e5266
This commit is contained in:
Dmitry Rykun
2024-01-03 08:58:30 -08:00
committed by Facebook GitHub Bot
parent 327df8a719
commit 82f8cf1836
9 changed files with 187 additions and 135 deletions
@@ -15,6 +15,10 @@ import type {ConstantsStruct, StructTypeAnnotation} from '../StructCollector';
import type {StructSerilizationOutput} from './serializeStruct';
const {unwrapNullable} = require('../../../../parsers/parsers-commons');
const {wrapOptional: wrapCxxOptional} = require('../../../TypeUtils/Cxx');
const {
wrapOptional: wrapObjCOptional,
} = require('../../../TypeUtils/Objective-C');
const {capitalize} = require('../../../Utils');
const {getNamespacedStructName, getSafePropertyName} = require('../Utils');
@@ -78,15 +82,12 @@ function toObjCType(
): string {
const [typeAnnotation, nullable] = unwrapNullable(nullableTypeAnnotation);
const isRequired = !nullable && !isOptional;
const wrapOptional = (type: string) => {
return isRequired ? type : `std::optional<${type}>`;
};
switch (typeAnnotation.type) {
case 'ReservedTypeAnnotation':
switch (typeAnnotation.name) {
case 'RootTag':
return wrapOptional('double');
return wrapCxxOptional('double', isRequired);
default:
(typeAnnotation.name: empty);
throw new Error(`Unknown prop type, found: ${typeAnnotation.name}"`);
@@ -94,19 +95,19 @@ function toObjCType(
case 'StringTypeAnnotation':
return 'NSString *';
case 'NumberTypeAnnotation':
return wrapOptional('double');
return wrapCxxOptional('double', isRequired);
case 'FloatTypeAnnotation':
return wrapOptional('double');
return wrapCxxOptional('double', isRequired);
case 'Int32TypeAnnotation':
return wrapOptional('double');
return wrapCxxOptional('double', isRequired);
case 'DoubleTypeAnnotation':
return wrapOptional('double');
return wrapCxxOptional('double', isRequired);
case 'BooleanTypeAnnotation':
return wrapOptional('bool');
return wrapCxxOptional('bool', isRequired);
case 'EnumDeclaration':
switch (typeAnnotation.memberType) {
case 'NumberTypeAnnotation':
return wrapOptional('double');
return wrapCxxOptional('double', isRequired);
case 'StringTypeAnnotation':
return 'NSString *';
default:
@@ -115,17 +116,18 @@ function toObjCType(
);
}
case 'GenericObjectTypeAnnotation':
return isRequired ? 'id<NSObject> ' : 'id<NSObject> _Nullable ';
return wrapObjCOptional('id<NSObject>', isRequired);
case 'ArrayTypeAnnotation':
if (typeAnnotation.elementType == null) {
return isRequired ? 'id<NSObject> ' : 'id<NSObject> _Nullable ';
return wrapObjCOptional('id<NSObject>', isRequired);
}
return wrapOptional(
return wrapCxxOptional(
`std::vector<${toObjCType(
hasteModuleName,
typeAnnotation.elementType,
)}>`,
isRequired,
);
case 'TypeAliasTypeAnnotation':
const structName = capitalize(typeAnnotation.name);
@@ -133,7 +135,7 @@ function toObjCType(
hasteModuleName,
structName,
);
return wrapOptional(`${namespacedStructName}::Builder`);
return wrapCxxOptional(`${namespacedStructName}::Builder`, isRequired);
default:
(typeAnnotation.type: empty);
throw new Error(
@@ -15,6 +15,10 @@ import type {RegularStruct, StructTypeAnnotation} from '../StructCollector';
import type {StructSerilizationOutput} from './serializeStruct';
const {unwrapNullable} = require('../../../../parsers/parsers-commons');
const {wrapOptional: wrapCxxOptional} = require('../../../TypeUtils/Cxx');
const {
wrapOptional: wrapObjCOptional,
} = require('../../../TypeUtils/Objective-C');
const {capitalize} = require('../../../Utils');
const {getNamespacedStructName, getSafePropertyName} = require('../Utils');
@@ -69,15 +73,12 @@ function toObjCType(
): string {
const [typeAnnotation, nullable] = unwrapNullable(nullableTypeAnnotation);
const isRequired = !nullable && !isOptional;
const wrapOptional = (type: string) => {
return isRequired ? type : `std::optional<${type}>`;
};
switch (typeAnnotation.type) {
case 'ReservedTypeAnnotation':
switch (typeAnnotation.name) {
case 'RootTag':
return wrapOptional('double');
return wrapCxxOptional('double', isRequired);
default:
(typeAnnotation.name: empty);
throw new Error(`Unknown prop type, found: ${typeAnnotation.name}"`);
@@ -85,19 +86,19 @@ function toObjCType(
case 'StringTypeAnnotation':
return 'NSString *';
case 'NumberTypeAnnotation':
return wrapOptional('double');
return wrapCxxOptional('double', isRequired);
case 'FloatTypeAnnotation':
return wrapOptional('double');
return wrapCxxOptional('double', isRequired);
case 'Int32TypeAnnotation':
return wrapOptional('double');
return wrapCxxOptional('double', isRequired);
case 'DoubleTypeAnnotation':
return wrapOptional('double');
return wrapCxxOptional('double', isRequired);
case 'BooleanTypeAnnotation':
return wrapOptional('bool');
return wrapCxxOptional('bool', isRequired);
case 'EnumDeclaration':
switch (typeAnnotation.memberType) {
case 'NumberTypeAnnotation':
return wrapOptional('double');
return wrapCxxOptional('double', isRequired);
case 'StringTypeAnnotation':
return 'NSString *';
default:
@@ -106,16 +107,17 @@ function toObjCType(
);
}
case 'GenericObjectTypeAnnotation':
return isRequired ? 'id<NSObject> ' : 'id<NSObject> _Nullable';
return wrapObjCOptional('id<NSObject>', isRequired);
case 'ArrayTypeAnnotation':
if (typeAnnotation.elementType == null) {
return isRequired ? 'id<NSObject> ' : 'id<NSObject> _Nullable';
return wrapObjCOptional('id<NSObject>', isRequired);
}
return wrapOptional(
return wrapCxxOptional(
`facebook::react::LazyVector<${toObjCType(
hasteModuleName,
typeAnnotation.elementType,
)}>`,
isRequired,
);
case 'TypeAliasTypeAnnotation':
const structName = capitalize(typeAnnotation.name);
@@ -123,7 +125,7 @@ function toObjCType(
hasteModuleName,
structName,
);
return wrapOptional(namespacedStructName);
return wrapCxxOptional(namespacedStructName, isRequired);
default:
(typeAnnotation.type: empty);
throw new Error(
@@ -24,6 +24,7 @@ const {
unwrapNullable,
wrapNullable,
} = require('../../../parsers/parsers-commons');
const {wrapOptional} = require('../../TypeUtils/Objective-C');
const {capitalize} = require('../../Utils');
const {getNamespacedStructName} = require('./Utils');
const invariant = require('invariant');
@@ -188,11 +189,7 @@ function getParamObjCType(
): $ReadOnly<{objCType: string, isStruct: boolean}> {
const {name: paramName, typeAnnotation: nullableTypeAnnotation} = param;
const [typeAnnotation, nullable] = unwrapNullable(nullableTypeAnnotation);
const notRequired = param.optional || nullable;
function wrapIntoNullableIfNeeded(generatedType: string) {
return nullable ? `${generatedType} _Nullable` : generatedType;
}
const isRequired = !param.optional && !nullable;
const isStruct = (objCType: string) => ({
isStruct: true,
@@ -220,7 +217,7 @@ function getParamObjCType(
* type Animal = {};
* Array<Animal> => NSArray<JS::NativeSampleTurboModule::Animal *>, etc.
*/
return notStruct(wrapIntoNullableIfNeeded('NSArray *'));
return notStruct(wrapOptional('NSArray *', !nullable));
}
}
@@ -251,7 +248,7 @@ function getParamObjCType(
case 'ReservedTypeAnnotation':
switch (structTypeAnnotation.name) {
case 'RootTag':
return notStruct(notRequired ? 'NSNumber *' : 'double');
return notStruct(isRequired ? 'double' : 'NSNumber *');
default:
(structTypeAnnotation.name: empty);
throw new Error(
@@ -259,30 +256,30 @@ function getParamObjCType(
);
}
case 'StringTypeAnnotation':
return notStruct(wrapIntoNullableIfNeeded('NSString *'));
return notStruct(wrapOptional('NSString *', !nullable));
case 'NumberTypeAnnotation':
return notStruct(notRequired ? 'NSNumber *' : 'double');
return notStruct(isRequired ? 'double' : 'NSNumber *');
case 'FloatTypeAnnotation':
return notStruct(notRequired ? 'NSNumber *' : 'double');
return notStruct(isRequired ? 'double' : 'NSNumber *');
case 'DoubleTypeAnnotation':
return notStruct(notRequired ? 'NSNumber *' : 'double');
return notStruct(isRequired ? 'double' : 'NSNumber *');
case 'Int32TypeAnnotation':
return notStruct(notRequired ? 'NSNumber *' : 'double');
return notStruct(isRequired ? 'double' : 'NSNumber *');
case 'BooleanTypeAnnotation':
return notStruct(notRequired ? 'NSNumber *' : 'BOOL');
return notStruct(isRequired ? 'BOOL' : 'NSNumber *');
case 'EnumDeclaration':
switch (typeAnnotation.memberType) {
case 'NumberTypeAnnotation':
return notStruct(notRequired ? 'NSNumber *' : 'double');
return notStruct(isRequired ? 'double' : 'NSNumber *');
case 'StringTypeAnnotation':
return notStruct(wrapIntoNullableIfNeeded('NSString *'));
return notStruct(wrapOptional('NSString *', !nullable));
default:
throw new Error(
`Unsupported enum type for param "${paramName}" in ${methodName}. Found: ${typeAnnotation.type}`,
);
}
case 'GenericObjectTypeAnnotation':
return notStruct(wrapIntoNullableIfNeeded('NSDictionary *'));
return notStruct(wrapOptional('NSDictionary *', !nullable));
default:
(structTypeAnnotation.type: empty);
throw new Error(
@@ -296,10 +293,7 @@ function getReturnObjCType(
nullableTypeAnnotation: Nullable<NativeModuleReturnTypeAnnotation>,
): string {
const [typeAnnotation, nullable] = unwrapNullable(nullableTypeAnnotation);
function wrapIntoNullableIfNeeded(generatedType: string) {
return nullable ? `${generatedType} _Nullable` : generatedType;
}
const isRequired = !nullable;
switch (typeAnnotation.type) {
case 'VoidTypeAnnotation':
@@ -307,24 +301,25 @@ function getReturnObjCType(
case 'PromiseTypeAnnotation':
return 'void';
case 'ObjectTypeAnnotation':
return wrapIntoNullableIfNeeded('NSDictionary *');
return wrapOptional('NSDictionary *', isRequired);
case 'TypeAliasTypeAnnotation':
return wrapIntoNullableIfNeeded('NSDictionary *');
return wrapOptional('NSDictionary *', isRequired);
case 'ArrayTypeAnnotation':
if (typeAnnotation.elementType == null) {
return wrapIntoNullableIfNeeded('NSArray<id<NSObject>> *');
return wrapOptional('NSArray<id<NSObject>> *', isRequired);
}
return wrapIntoNullableIfNeeded(
return wrapOptional(
`NSArray<${getReturnObjCType(
methodName,
typeAnnotation.elementType,
)}> *`,
isRequired,
);
case 'ReservedTypeAnnotation':
switch (typeAnnotation.name) {
case 'RootTag':
return wrapIntoNullableIfNeeded('NSNumber *');
return wrapOptional('NSNumber *', isRequired);
default:
(typeAnnotation.name: empty);
throw new Error(
@@ -334,23 +329,23 @@ function getReturnObjCType(
case 'StringTypeAnnotation':
// TODO: Can NSString * returns not be _Nullable?
// In the legacy codegen, we don't surround NSSTring * with _Nullable
return wrapIntoNullableIfNeeded('NSString *');
return wrapOptional('NSString *', isRequired);
case 'NumberTypeAnnotation':
return wrapIntoNullableIfNeeded('NSNumber *');
return wrapOptional('NSNumber *', isRequired);
case 'FloatTypeAnnotation':
return wrapIntoNullableIfNeeded('NSNumber *');
return wrapOptional('NSNumber *', isRequired);
case 'DoubleTypeAnnotation':
return wrapIntoNullableIfNeeded('NSNumber *');
return wrapOptional('NSNumber *', isRequired);
case 'Int32TypeAnnotation':
return wrapIntoNullableIfNeeded('NSNumber *');
return wrapOptional('NSNumber *', isRequired);
case 'BooleanTypeAnnotation':
return wrapIntoNullableIfNeeded('NSNumber *');
return wrapOptional('NSNumber *', isRequired);
case 'EnumDeclaration':
switch (typeAnnotation.memberType) {
case 'NumberTypeAnnotation':
return wrapIntoNullableIfNeeded('NSNumber *');
return wrapOptional('NSNumber *', isRequired);
case 'StringTypeAnnotation':
return wrapIntoNullableIfNeeded('NSString *');
return wrapOptional('NSString *', isRequired);
default:
throw new Error(
`Unsupported enum return type for ${methodName}. Found: ${typeAnnotation.type}`,
@@ -359,20 +354,20 @@ function getReturnObjCType(
case 'UnionTypeAnnotation':
switch (typeAnnotation.memberType) {
case 'NumberTypeAnnotation':
return wrapIntoNullableIfNeeded('NSNumber *');
return wrapOptional('NSNumber *', isRequired);
case 'ObjectTypeAnnotation':
return wrapIntoNullableIfNeeded('NSDictionary *');
return wrapOptional('NSDictionary *', isRequired);
case 'StringTypeAnnotation':
// TODO: Can NSString * returns not be _Nullable?
// In the legacy codegen, we don't surround NSSTring * with _Nullable
return wrapIntoNullableIfNeeded('NSString *');
return wrapOptional('NSString *', isRequired);
default:
throw new Error(
`Unsupported union return type for ${methodName}, found: ${typeAnnotation.memberType}"`,
);
}
case 'GenericObjectTypeAnnotation':
return wrapIntoNullableIfNeeded('NSDictionary *');
return wrapOptional('NSDictionary *', isRequired);
default:
(typeAnnotation.type: 'MixedTypeAnnotation');
throw new Error(