Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 49 additions & 12 deletions packages/react-native-codegen/src/CodegenSchema.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ export interface FloatTypeAnnotation {
readonly type: 'FloatTypeAnnotation';
}

export interface NumberTypeAnnotation {
readonly type: 'NumberTypeAnnotation';
}

export interface BooleanTypeAnnotation {
readonly type: 'BooleanTypeAnnotation';
}
Expand All @@ -42,13 +46,40 @@ export interface VoidTypeAnnotation {
readonly type: 'VoidTypeAnnotation';
}

export interface NumberLiteralTypeAnnotation {
readonly type: 'NumberLiteralTypeAnnotation';
readonly value: number;
}

export interface StringLiteralTypeAnnotation {
readonly type: 'StringLiteralTypeAnnotation';
readonly value: string;
}

export interface BooleanLiteralTypeAnnotation {
readonly type: 'BooleanLiteralTypeAnnotation';
readonly value: boolean;
}

export interface ObjectTypeAnnotation<T> {
readonly type: 'ObjectTypeAnnotation';
readonly properties: readonly NamedShape<T>[];
// metadata for objects that generated from interfaces
readonly baseTypes?: readonly string[] | undefined;
}

export interface UnionTypeAnnotation<T> {
readonly type: 'UnionTypeAnnotation';
readonly types: readonly T[];
}

// TODO(T72031674): TupleTypeAnnotation is added for parity with UnionTypeAnnotation
// to support future implementation. Currently limited to String and Number literals.
export interface TupleTypeAnnotation {
readonly type: 'TupleTypeAnnotation';
readonly types: StringLiteralTypeAnnotation | NumberLiteralTypeAnnotation;
}

export interface MixedTypeAnnotation {
readonly type: 'MixedTypeAnnotation';
}
Expand Down Expand Up @@ -304,10 +335,14 @@ export interface NativeModuleStringLiteralTypeAnnotation {
readonly value: string;
}

export interface StringLiteralUnionTypeAnnotation {
readonly type: 'StringLiteralUnionTypeAnnotation';
readonly types: NativeModuleStringLiteralTypeAnnotation[];
}
export type StringLiteralUnionTypeAnnotation =
UnionTypeAnnotation<StringLiteralTypeAnnotation>;

export type NumberLiteralUnionTypeAnnotation =
UnionTypeAnnotation<NumberLiteralTypeAnnotation>;

export type BooleanLiteralUnionTypeAnnotation =
UnionTypeAnnotation<BooleanLiteralTypeAnnotation>;

export interface NativeModuleNumberTypeAnnotation {
readonly type: 'NumberTypeAnnotation';
Expand Down Expand Up @@ -369,15 +404,17 @@ export interface NativeModulePromiseTypeAnnotation {
readonly elementType: Nullable<NativeModuleBaseTypeAnnotation> | VoidTypeAnnotation;
}

export type UnionTypeAnnotationMemberType =
| 'NumberTypeAnnotation'
| 'ObjectTypeAnnotation'
| 'StringTypeAnnotation';
export type NativeModuleUnionTypeAnnotationMemberType =
| NativeModuleObjectTypeAnnotation
| StringLiteralTypeAnnotation
| NumberLiteralTypeAnnotation
| BooleanLiteralTypeAnnotation
| BooleanTypeAnnotation
| StringTypeAnnotation
| NumberTypeAnnotation;

export interface NativeModuleUnionTypeAnnotation {
readonly type: 'UnionTypeAnnotation';
readonly memberType: UnionTypeAnnotationMemberType;
}
export type NativeModuleUnionTypeAnnotation =
UnionTypeAnnotation<NativeModuleUnionTypeAnnotationMemberType>;

export interface NativeModuleMixedTypeAnnotation {
readonly type: 'MixedTypeAnnotation';
Expand Down
50 changes: 39 additions & 11 deletions packages/react-native-codegen/src/CodegenSchema.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ export type FloatTypeAnnotation = $ReadOnly<{
type: 'FloatTypeAnnotation',
}>;

export type NumberTypeAnnotation = $ReadOnly<{
type: 'NumberTypeAnnotation',
}>;

export type BooleanTypeAnnotation = $ReadOnly<{
type: 'BooleanTypeAnnotation',
}>;
Expand All @@ -52,11 +56,20 @@ export type StringLiteralTypeAnnotation = $ReadOnly<{
value: string,
}>;

export type StringLiteralUnionTypeAnnotation = $ReadOnly<{
type: 'StringLiteralUnionTypeAnnotation',
types: $ReadOnlyArray<StringLiteralTypeAnnotation>,
export type BooleanLiteralTypeAnnotation = $ReadOnly<{
type: 'BooleanLiteralTypeAnnotation',
value: boolean,
}>;

export type StringLiteralUnionTypeAnnotation =
UnionTypeAnnotation<StringLiteralTypeAnnotation>;

export type NumberLiteralUnionTypeAnnotation =
UnionTypeAnnotation<NumberLiteralTypeAnnotation>;

export type BooleanLiteralUnionTypeAnnotation =
UnionTypeAnnotation<BooleanLiteralTypeAnnotation>;

export type VoidTypeAnnotation = $ReadOnly<{
type: 'VoidTypeAnnotation',
}>;
Expand All @@ -68,6 +81,18 @@ export type ObjectTypeAnnotation<+T> = $ReadOnly<{
baseTypes?: $ReadOnlyArray<string>,
}>;

export type UnionTypeAnnotation<+T> = $ReadOnly<{
type: 'UnionTypeAnnotation',
types: $ReadOnlyArray<T>,
}>;

// TODO(T72031674): TupleTypeAnnotation is added for parity with UnionTypeAnnotation
// to support future implementation. Currently limited to String and Number literals.
export type TupleTypeAnnotation = $ReadOnly<{
type: 'TupleTypeAnnotation',
types: StringLiteralTypeAnnotation | NumberLiteralTypeAnnotation,
}>;

export type MixedTypeAnnotation = $ReadOnly<{
type: 'MixedTypeAnnotation',
}>;
Expand Down Expand Up @@ -358,15 +383,17 @@ export type NativeModulePromiseTypeAnnotation = $ReadOnly<{
elementType: VoidTypeAnnotation | Nullable<NativeModuleBaseTypeAnnotation>,
}>;

export type UnionTypeAnnotationMemberType =
| 'NumberTypeAnnotation'
| 'ObjectTypeAnnotation'
| 'StringTypeAnnotation';
export type NativeModuleUnionTypeAnnotationMemberType =
| NativeModuleObjectTypeAnnotation
| StringLiteralTypeAnnotation
| NumberLiteralTypeAnnotation
| BooleanLiteralTypeAnnotation
| BooleanTypeAnnotation
| StringTypeAnnotation
| NumberTypeAnnotation;

export type NativeModuleUnionTypeAnnotation = $ReadOnly<{
type: 'UnionTypeAnnotation',
memberType: UnionTypeAnnotationMemberType,
}>;
export type NativeModuleUnionTypeAnnotation =
UnionTypeAnnotation<NativeModuleUnionTypeAnnotationMemberType>;

export type NativeModuleMixedTypeAnnotation = $ReadOnly<{
type: 'MixedTypeAnnotation',
Expand Down Expand Up @@ -396,6 +423,7 @@ export type NativeModuleBaseTypeAnnotation =
| StringLiteralUnionTypeAnnotation
| NativeModuleNumberTypeAnnotation
| NumberLiteralTypeAnnotation
| BooleanLiteralTypeAnnotation
| Int32TypeAnnotation
| DoubleTypeAnnotation
| FloatTypeAnnotation
Expand Down
51 changes: 51 additions & 0 deletions packages/react-native-codegen/src/generators/Utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

'use strict';

import type {NativeModuleUnionTypeAnnotation} from '../CodegenSchema';

function capitalize(string: string): string {
return string.charAt(0).toUpperCase() + string.slice(1);
}
Expand Down Expand Up @@ -44,9 +46,58 @@ function getEnumName(moduleName: string, origEnumName: string): string {
return `${moduleName}${uppercasedPropName}`;
}

type ValidUnionType = 'boolean' | 'number' | 'object' | 'string';
const NumberTypes = ['NumberTypeAnnotation', 'NumberLiteralTypeAnnotation'];
const StringTypes = ['StringTypeAnnotation', 'StringLiteralTypeAnnotation'];
const ObjectTypes = ['ObjectTypeAnnotation'];
const BooleanTypes = ['BooleanTypeAnnotation', 'BooleanLiteralTypeAnnotation'];
const ValidUnionTypes = [
...NumberTypes,
...ObjectTypes,
...StringTypes,
...BooleanTypes,
];

function parseValidUnionType(
annotation: NativeModuleUnionTypeAnnotation,
): ValidUnionType {
const isUnionOfType = (types: $ReadOnlyArray<string>): boolean => {
return annotation.types.every(memberTypeAnnotation =>
types.includes(memberTypeAnnotation.type),
);
};
if (isUnionOfType(BooleanTypes)) {
return 'boolean';
}
if (isUnionOfType(NumberTypes)) {
return 'number';
}
if (isUnionOfType(ObjectTypes)) {
return 'object';
}
if (isUnionOfType(StringTypes)) {
return 'string';
}

const invalidTypes = annotation.types.filter(member => {
return !ValidUnionTypes.includes(member.type);
});

// Check if union members are all supported but not homogeneous
// (e.g., mix of number and boolean)
if (invalidTypes.length === 0) {
throw new Error(`Non-homogenous union member types`);
} else {
throw new Error(
`Unsupported union member types: ${invalidTypes.join(', ')}"`,
);
}
}

module.exports = {
capitalize,
indent,
parseValidUnionType,
toPascalCase,
toSafeCppString,
getEnumName,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,12 @@ import type {AliasResolver} from './Utils';

const {unwrapNullable} = require('../../parsers/parsers-commons');
const {wrapOptional} = require('../TypeUtils/Cxx');
const {getEnumName, toPascalCase, toSafeCppString} = require('../Utils');
const {
getEnumName,
parseValidUnionType,
toPascalCase,
toSafeCppString,
} = require('../Utils');
const {
createAliasResolver,
getModules,
Expand Down Expand Up @@ -92,10 +97,10 @@ function serializeArg(
return wrap(val => `${val}.asString(rt)`);
case 'StringLiteralTypeAnnotation':
return wrap(val => `${val}.asString(rt)`);
case 'StringLiteralUnionTypeAnnotation':
return wrap(val => `${val}.asString(rt)`);
case 'BooleanTypeAnnotation':
return wrap(val => `${val}.asBool()`);
case 'BooleanLiteralTypeAnnotation':
return wrap(val => `${val}.asBool()`);
case 'EnumDeclaration':
switch (realTypeAnnotation.memberType) {
case 'NumberTypeAnnotation':
Expand Down Expand Up @@ -124,17 +129,19 @@ function serializeArg(
case 'GenericObjectTypeAnnotation':
return wrap(val => `${val}.asObject(rt)`);
case 'UnionTypeAnnotation':
switch (typeAnnotation.memberType) {
case 'NumberTypeAnnotation':
const validUnionType = parseValidUnionType(realTypeAnnotation);
switch (validUnionType) {
case 'boolean':
return wrap(val => `${val}.asBool()`);
case 'number':
return wrap(val => `${val}.asNumber()`);
case 'ObjectTypeAnnotation':
case 'object':
return wrap(val => `${val}.asObject(rt)`);
case 'StringTypeAnnotation':
case 'string':
return wrap(val => `${val}.asString(rt)`);
default:
throw new Error(
`Unsupported union member type for param "${arg.name}, found: ${realTypeAnnotation.memberType}"`,
);
(validUnionType: empty);
throw new Error(`Unsupported union member type`);
}
case 'ObjectTypeAnnotation':
return wrap(val => `${val}.asObject(rt)`);
Expand Down Expand Up @@ -251,8 +258,6 @@ function translatePrimitiveJSTypeToCpp(
return wrapOptional('jsi::String', isRequired);
case 'StringLiteralTypeAnnotation':
return wrapOptional('jsi::String', isRequired);
case 'StringLiteralUnionTypeAnnotation':
return wrapOptional('jsi::String', isRequired);
case 'NumberTypeAnnotation':
return wrapOptional('double', isRequired);
case 'NumberLiteralTypeAnnotation':
Expand All @@ -265,6 +270,8 @@ function translatePrimitiveJSTypeToCpp(
return wrapOptional('int', isRequired);
case 'BooleanTypeAnnotation':
return wrapOptional('bool', isRequired);
case 'BooleanLiteralTypeAnnotation':
return wrapOptional('bool', isRequired);
case 'EnumDeclaration':
switch (realTypeAnnotation.memberType) {
case 'NumberTypeAnnotation':
Expand All @@ -277,15 +284,19 @@ function translatePrimitiveJSTypeToCpp(
case 'GenericObjectTypeAnnotation':
return wrapOptional('jsi::Object', isRequired);
case 'UnionTypeAnnotation':
switch (typeAnnotation.memberType) {
case 'NumberTypeAnnotation':
const validUnionType = parseValidUnionType(realTypeAnnotation);
switch (validUnionType) {
case 'boolean':
return wrapOptional('bool', isRequired);
case 'number':
return wrapOptional('double', isRequired);
case 'ObjectTypeAnnotation':
case 'object':
return wrapOptional('jsi::Object', isRequired);
case 'StringTypeAnnotation':
case 'string':
return wrapOptional('jsi::String', isRequired);
default:
throw new Error(createErrorMessage(realTypeAnnotation.type));
(validUnionType: empty);
throw new Error(`Unsupported union member type`);
}
case 'ObjectTypeAnnotation':
return wrapOptional('jsi::Object', isRequired);
Expand Down
Loading
Loading