mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
b444f0e44e
Summary:
There are cases where we want to pass an enum type into a TurboModule method which is handy to restrict certain arguments to a restricted set of values, e.g. restricting quality to ```enum Quality { SD, HD, }```
Approach:
- We are not generating an ```enum``` type in C++ but rather just cast type safe to the corresponding member type.
- We don't support mixed enum types at this time, e.g. ```export enum StringOption { One = 'one', Two = 2, Three = 'three', };``` will not work. See: https://www.typescriptlang.org/docs/handbook/enums.html#heterogeneous-enums
- We only support untyped (default to String), String, and Number enum properties
This is for C++ only, Java and ObjC are not supported atm.
Changelog:
[General][Added] - react-native-code-gen Add Enum Type support for C++ TurboModules
Reviewed By: RSNara
Differential Revision: D38880963
fbshipit-source-id: f2399b29948306bc555429b6f96c43ea4c39c46e
207 lines
5.5 KiB
JavaScript
207 lines
5.5 KiB
JavaScript
/**
|
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*
|
|
* @flow strict
|
|
* @format
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
import type {
|
|
Nullable,
|
|
NativeModuleObjectTypeAnnotation,
|
|
NativeModuleStringTypeAnnotation,
|
|
NativeModuleNumberTypeAnnotation,
|
|
NativeModuleInt32TypeAnnotation,
|
|
NativeModuleDoubleTypeAnnotation,
|
|
NativeModuleFloatTypeAnnotation,
|
|
NativeModuleBooleanTypeAnnotation,
|
|
NativeModuleGenericObjectTypeAnnotation,
|
|
ReservedTypeAnnotation,
|
|
NativeModuleTypeAliasTypeAnnotation,
|
|
NativeModuleArrayTypeAnnotation,
|
|
NativeModuleBaseTypeAnnotation,
|
|
} from '../../../CodegenSchema';
|
|
|
|
import type {AliasResolver} from '../Utils';
|
|
|
|
const {capitalize} = require('../../Utils');
|
|
const {
|
|
unwrapNullable,
|
|
wrapNullable,
|
|
} = require('../../../parsers/flow/modules/utils');
|
|
|
|
type StructContext = 'CONSTANTS' | 'REGULAR';
|
|
|
|
export type RegularStruct = $ReadOnly<{
|
|
context: 'REGULAR',
|
|
name: string,
|
|
properties: $ReadOnlyArray<StructProperty>,
|
|
}>;
|
|
|
|
export type ConstantsStruct = $ReadOnly<{
|
|
context: 'CONSTANTS',
|
|
name: string,
|
|
properties: $ReadOnlyArray<StructProperty>,
|
|
}>;
|
|
|
|
export type Struct = RegularStruct | ConstantsStruct;
|
|
|
|
export type StructProperty = $ReadOnly<{
|
|
name: string,
|
|
optional: boolean,
|
|
typeAnnotation: Nullable<StructTypeAnnotation>,
|
|
}>;
|
|
|
|
export type StructTypeAnnotation =
|
|
| NativeModuleStringTypeAnnotation
|
|
| NativeModuleNumberTypeAnnotation
|
|
| NativeModuleInt32TypeAnnotation
|
|
| NativeModuleDoubleTypeAnnotation
|
|
| NativeModuleFloatTypeAnnotation
|
|
| NativeModuleBooleanTypeAnnotation
|
|
| NativeModuleGenericObjectTypeAnnotation
|
|
| ReservedTypeAnnotation
|
|
| NativeModuleTypeAliasTypeAnnotation
|
|
| NativeModuleArrayTypeAnnotation<Nullable<StructTypeAnnotation>>;
|
|
|
|
class StructCollector {
|
|
_structs: Map<string, Struct> = new Map();
|
|
|
|
process(
|
|
structName: string,
|
|
structContext: StructContext,
|
|
resolveAlias: AliasResolver,
|
|
nullableTypeAnnotation: Nullable<NativeModuleBaseTypeAnnotation>,
|
|
): Nullable<StructTypeAnnotation> {
|
|
const [typeAnnotation, nullable] = unwrapNullable(nullableTypeAnnotation);
|
|
switch (typeAnnotation.type) {
|
|
case 'ObjectTypeAnnotation': {
|
|
this._insertStruct(
|
|
structName,
|
|
structContext,
|
|
resolveAlias,
|
|
typeAnnotation,
|
|
);
|
|
return wrapNullable(nullable, {
|
|
type: 'TypeAliasTypeAnnotation',
|
|
name: structName,
|
|
});
|
|
}
|
|
case 'ArrayTypeAnnotation': {
|
|
if (typeAnnotation.elementType == null) {
|
|
return wrapNullable(nullable, {
|
|
type: 'ArrayTypeAnnotation',
|
|
});
|
|
}
|
|
|
|
return wrapNullable(nullable, {
|
|
type: 'ArrayTypeAnnotation',
|
|
elementType: this.process(
|
|
structName + 'Element',
|
|
structContext,
|
|
resolveAlias,
|
|
typeAnnotation.elementType,
|
|
),
|
|
});
|
|
}
|
|
case 'TypeAliasTypeAnnotation': {
|
|
this._insertAlias(typeAnnotation.name, structContext, resolveAlias);
|
|
return wrapNullable(nullable, typeAnnotation);
|
|
}
|
|
case 'EnumDeclaration':
|
|
throw new Error('Enum types are unsupported in structs');
|
|
case 'MixedTypeAnnotation':
|
|
throw new Error('Mixed types are unsupported in structs');
|
|
case 'UnionTypeAnnotation':
|
|
throw new Error('Union types are unsupported in structs');
|
|
default: {
|
|
return wrapNullable(nullable, typeAnnotation);
|
|
}
|
|
}
|
|
}
|
|
|
|
_insertAlias(
|
|
aliasName: string,
|
|
structContext: StructContext,
|
|
resolveAlias: AliasResolver,
|
|
): void {
|
|
const usedStruct = this._structs.get(aliasName);
|
|
if (usedStruct == null) {
|
|
this._insertStruct(
|
|
aliasName,
|
|
structContext,
|
|
resolveAlias,
|
|
resolveAlias(aliasName),
|
|
);
|
|
} else if (usedStruct.context !== structContext) {
|
|
throw new Error(
|
|
`Tried to use alias '${aliasName}' in a getConstants() return type and inside a regular struct.`,
|
|
);
|
|
}
|
|
}
|
|
|
|
_insertStruct(
|
|
structName: string,
|
|
structContext: StructContext,
|
|
resolveAlias: AliasResolver,
|
|
objectTypeAnnotation: NativeModuleObjectTypeAnnotation,
|
|
): void {
|
|
// $FlowFixMe[missing-type-arg]
|
|
const properties = objectTypeAnnotation.properties.map<
|
|
$ReadOnly<{
|
|
name: string,
|
|
optional: boolean,
|
|
typeAnnotation: Nullable<StructTypeAnnotation>,
|
|
}>,
|
|
>(property => {
|
|
const propertyStructName = structName + capitalize(property.name);
|
|
|
|
return {
|
|
...property,
|
|
typeAnnotation: this.process(
|
|
propertyStructName,
|
|
structContext,
|
|
resolveAlias,
|
|
property.typeAnnotation,
|
|
),
|
|
};
|
|
});
|
|
|
|
switch (structContext) {
|
|
case 'REGULAR':
|
|
this._structs.set(structName, {
|
|
name: structName,
|
|
context: 'REGULAR',
|
|
properties: properties,
|
|
});
|
|
break;
|
|
case 'CONSTANTS':
|
|
this._structs.set(structName, {
|
|
name: structName,
|
|
context: 'CONSTANTS',
|
|
properties: properties,
|
|
});
|
|
break;
|
|
default:
|
|
(structContext: empty);
|
|
throw new Error(`Detected an invalid struct context: ${structContext}`);
|
|
}
|
|
}
|
|
|
|
getAllStructs(): $ReadOnlyArray<Struct> {
|
|
return [...this._structs.values()];
|
|
}
|
|
|
|
getStruct(name: string): ?Struct {
|
|
return this._structs.get(name);
|
|
}
|
|
}
|
|
|
|
module.exports = {
|
|
StructCollector,
|
|
};
|