Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
d55ea45
Adding NumberTypeAnnotation to Codegen Schema (#54586)
arushikesarwani94 Nov 19, 2025
902df5f
Introduce generic UnionTypeAnnotation (#54587)
arushikesarwani94 Nov 19, 2025
392544f
Introduce NumberLiteralType & StringLiteralType in TS (#54588)
arushikesarwani94 Nov 19, 2025
b6edf3c
Introduce TupleTypeAnnotation
arushikesarwani94 Nov 19, 2025
47102f0
Introduce BooleanLiteralTypeAnnotation (#54590)
arushikesarwani94 Nov 19, 2025
8192211
Introduce the supported member types of Union (#54591)
arushikesarwani94 Nov 19, 2025
35c353f
Introduce UnionTypeAnnotation for Number & Boolean (#54592)
arushikesarwani94 Nov 19, 2025
4575f47
Add BooleanLiteralTypeAnnotation to the NativeModuleBaseTypeAnnotatio…
arushikesarwani94 Nov 19, 2025
8e29196
Refactor NativeModuleUnionTypeAnnotation
arushikesarwani94 Nov 19, 2025
d2bdfe8
Un-special Case StringLiteralUnionTypeAnnotation
arushikesarwani94 Nov 19, 2025
195e737
Modifying the Parser logic to handle Unions of different types and re…
arushikesarwani94 Nov 19, 2025
090a66a
Flow Parser Changes
arushikesarwani94 Nov 19, 2025
4bfda9d
TypeScript Parser Changes
arushikesarwani94 Nov 19, 2025
c428656
Getting rid of UnsupportedUnionTypeAnnotationParserError
arushikesarwani94 Nov 19, 2025
3f7b4ff
Add Handler for Union Type Annotation for generators
arushikesarwani94 Nov 19, 2025
a126b16
Generator Modules handling for Unions & BooleanLiteralTypeAnnotation
arushikesarwani94 Nov 19, 2025
5fbe4fa
Generator Components handing for Unions
arushikesarwani94 Nov 19, 2025
e119e30
Updating tests & fixtures & associated snapshots
arushikesarwani94 Nov 19, 2025
30ace9a
React-Native-Compatibility Checker changes to accomodate the new Unio…
arushikesarwani94 Nov 19, 2025
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 @@ -12,11 +12,23 @@
import type {
EventTypeAnnotation,
NamedShape,
NativeModuleUnionTypeAnnotation,
PropTypeAnnotation,
} from '../../CodegenSchema';

const {getEnumName, toSafeCppString} = require('../Utils');

const NumberTypes = ['NumberTypeAnnotation', 'NumberLiteralTypeAnnotation'];
const StringTypes = ['StringTypeAnnotation', 'StringLiteralTypeAnnotation'];
const ObjectTypes = ['ObjectTypeAnnotation'];
const BooleanTypes = ['BooleanTypeAnnotation', 'BooleanLiteralTypeAnnotation'];
const ValidUnionTypes = [
...NumberTypes,
...ObjectTypes,
...StringTypes,
...BooleanTypes,
];

function toIntEnumValueName(propName: string, value: number): string {
return `${toSafeCppString(propName)}${value}`;
}
Expand Down Expand Up @@ -61,7 +73,54 @@ function getCppArrayTypeForAnnotation(
case 'Int32TypeAnnotation':
case 'MixedTypeAnnotation':
return `std::vector<${getCppTypeForAnnotation(typeElement.type)}>`;
case 'StringLiteralUnionTypeAnnotation':
case 'UnionTypeAnnotation':
const union: NativeModuleUnionTypeAnnotation = typeElement;
const isUnionOfType = (types: $ReadOnlyArray<string>): boolean => {
return union.types.every(memberTypeAnnotation =>
types.includes(memberTypeAnnotation.type),
);
};

if (isUnionOfType(NumberTypes)) {
return `std::vector<${getCppTypeForAnnotation('DoubleTypeAnnotation')}>`;
}

if (isUnionOfType(ObjectTypes)) {
if (!structParts) {
throw new Error(
`Trying to generate the event emitter for an Array of ${typeElement.type} without informations to generate the generic type`,
);
}
return `std::vector<${generateEventStructName(structParts)}>`;
}

if (isUnionOfType(['StringTypeAnnotation'])) {
return `std::vector<${getCppTypeForAnnotation('StringTypeAnnotation')}>`;
}
if (isUnionOfType(['StringLiteralTypeAnnotation'])) {
if (!structParts) {
throw new Error(
`Trying to generate the event emitter for an Array of ${typeElement.type} without informations to generate the generic type`,
);
}
return `std::vector<${generateEventStructName(structParts)}>`;
}

if (isUnionOfType(BooleanTypes)) {
return `std::vector<${getCppTypeForAnnotation('BooleanTypeAnnotation')}>`;
}

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

if (invalidTypes.length === 0) {
throw new Error(`Non-homogenous union member types`);
} else {
throw new Error(
`Unsupported union member types: ${invalidTypes.join(', ')}`,
);
}
case 'ObjectTypeAnnotation':
if (!structParts) {
throw new Error(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ function handleArrayElementType(
loopLocalVariable,
val => `jsi::valueFromDynamic(runtime, ${val})`,
);
case 'StringLiteralUnionTypeAnnotation':
case 'UnionTypeAnnotation':
return setValueAtIndex(
propertyName,
indexVariable,
Expand Down Expand Up @@ -320,7 +320,7 @@ function generateSetters(
usingEvent,
prop => `jsi::valueFromDynamic(runtime, ${prop})`,
);
case 'StringLiteralUnionTypeAnnotation':
case 'UnionTypeAnnotation':
return generateSetter(
parentPropertyName,
eventProperty.name,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ function getNativeTypeFromAnnotation(
case 'FloatTypeAnnotation':
case 'MixedTypeAnnotation':
return getCppTypeForAnnotation(type);
case 'StringLiteralUnionTypeAnnotation':
case 'UnionTypeAnnotation':
case 'ObjectTypeAnnotation':
return generateEventStructName([...nameParts, eventProperty.name]);
case 'ArrayTypeAnnotation':
Expand Down Expand Up @@ -188,7 +188,7 @@ function handleGenerateStructForArray(
nameParts.concat([name]),
nullthrows(elementType.properties),
);
} else if (elementType.type === 'StringLiteralUnionTypeAnnotation') {
} else if (elementType.type === 'UnionTypeAnnotation') {
generateEnum(
structs,
elementType.types.map(literal => literal.value),
Expand Down Expand Up @@ -251,7 +251,7 @@ function generateStruct(
nullthrows(typeAnnotation.properties),
);
return;
case 'StringLiteralUnionTypeAnnotation':
case 'UnionTypeAnnotation':
generateEnum(
structs,
typeAnnotation.types.map(literal => literal.value),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1273,7 +1273,7 @@ const EVENT_PROPS: SchemaType = {
typeAnnotation: {
type: 'ArrayTypeAnnotation',
elementType: {
type: 'StringLiteralUnionTypeAnnotation',
type: 'UnionTypeAnnotation',
types: [
{
type: 'StringLiteralTypeAnnotation',
Expand Down Expand Up @@ -1383,7 +1383,7 @@ const EVENT_PROPS: SchemaType = {
name: 'orientation',
optional: false,
typeAnnotation: {
type: 'StringLiteralUnionTypeAnnotation',
type: 'UnionTypeAnnotation',
types: [
{
type: 'StringLiteralTypeAnnotation',
Expand Down
Loading
Loading