From d55ea45e1b0e9e2111ba6ca95fb66576a762eec0 Mon Sep 17 00:00:00 2001 From: Arushi Kesarwani Date: Tue, 18 Nov 2025 23:59:36 -0800 Subject: [PATCH 01/17] Adding NumberTypeAnnotation to Codegen Schema (#54586) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/54586 Adding NumberTypeAnnotation to the Codegen Schema in order to obtain parity with String & Boolean which will be the Union types Changelog: [Internal] Differential Revision: D87374063 --- packages/react-native-codegen/src/CodegenSchema.d.ts | 4 ++++ packages/react-native-codegen/src/CodegenSchema.js | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/packages/react-native-codegen/src/CodegenSchema.d.ts b/packages/react-native-codegen/src/CodegenSchema.d.ts index 2d28bbfe7e271c..4f1ad89b87e107 100644 --- a/packages/react-native-codegen/src/CodegenSchema.d.ts +++ b/packages/react-native-codegen/src/CodegenSchema.d.ts @@ -26,6 +26,10 @@ export interface FloatTypeAnnotation { readonly type: 'FloatTypeAnnotation'; } +export interface NumberTypeAnnotation { + readonly type: 'NumberTypeAnnotation'; +} + export interface BooleanTypeAnnotation { readonly type: 'BooleanTypeAnnotation'; } diff --git a/packages/react-native-codegen/src/CodegenSchema.js b/packages/react-native-codegen/src/CodegenSchema.js index 99299dafc3c043..c5e154c5b7d84e 100644 --- a/packages/react-native-codegen/src/CodegenSchema.js +++ b/packages/react-native-codegen/src/CodegenSchema.js @@ -30,6 +30,10 @@ export type FloatTypeAnnotation = $ReadOnly<{ type: 'FloatTypeAnnotation', }>; +export type NumberTypeAnnotation = $ReadOnly<{ + type: 'NumberTypeAnnotation', +}>; + export type BooleanTypeAnnotation = $ReadOnly<{ type: 'BooleanTypeAnnotation', }>; From 902df5fd33846071da49a2f177803f0dfc2a487a Mon Sep 17 00:00:00 2001 From: Arushi Kesarwani Date: Tue, 18 Nov 2025 23:59:43 -0800 Subject: [PATCH 02/17] Introduce generic UnionTypeAnnotation (#54587) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/54587 Adding the generic type T UnionTypeAnnotation. This will be used later to create Unions of types String, Number & Boolean. Changelog: [Internal] Differential Revision: D87374445 --- packages/react-native-codegen/src/CodegenSchema.d.ts | 5 +++++ packages/react-native-codegen/src/CodegenSchema.js | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/packages/react-native-codegen/src/CodegenSchema.d.ts b/packages/react-native-codegen/src/CodegenSchema.d.ts index 4f1ad89b87e107..fc68a17224480b 100644 --- a/packages/react-native-codegen/src/CodegenSchema.d.ts +++ b/packages/react-native-codegen/src/CodegenSchema.d.ts @@ -53,6 +53,11 @@ export interface ObjectTypeAnnotation { readonly baseTypes?: readonly string[] | undefined; } +export interface UnionTypeAnnotation { + readonly type: 'UnionTypeAnnotation'; + readonly types: readonly T[]; +} + export interface MixedTypeAnnotation { readonly type: 'MixedTypeAnnotation'; } diff --git a/packages/react-native-codegen/src/CodegenSchema.js b/packages/react-native-codegen/src/CodegenSchema.js index c5e154c5b7d84e..98cf7af93960ab 100644 --- a/packages/react-native-codegen/src/CodegenSchema.js +++ b/packages/react-native-codegen/src/CodegenSchema.js @@ -72,6 +72,11 @@ export type ObjectTypeAnnotation<+T> = $ReadOnly<{ baseTypes?: $ReadOnlyArray, }>; +export type UnionTypeAnnotation<+T> = $ReadOnly<{ + type: 'UnionTypeAnnotation', + types: $ReadOnlyArray, +}>; + export type MixedTypeAnnotation = $ReadOnly<{ type: 'MixedTypeAnnotation', }>; From 392544f4f01a41c7a4c8fae4e5c647114a9200b2 Mon Sep 17 00:00:00 2001 From: Arushi Kesarwani Date: Tue, 18 Nov 2025 23:59:53 -0800 Subject: [PATCH 03/17] Introduce NumberLiteralType & StringLiteralType in TS (#54588) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/54588 Introduce NumberLiteralType & StringLiteralType in TypeScript just as they already exist in Flow here: https://www.internalfb.com/code/fbsource/[9b248afa0cd5548b81dd44f1042b230e6069432b]/xplat/js/react-native-github/packages/react-native-codegen/src/CodegenSchema.js?lines=41-53 Changelog: [Internal] Differential Revision: D87375511 --- packages/react-native-codegen/src/CodegenSchema.d.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/packages/react-native-codegen/src/CodegenSchema.d.ts b/packages/react-native-codegen/src/CodegenSchema.d.ts index fc68a17224480b..24f82ad80b0c40 100644 --- a/packages/react-native-codegen/src/CodegenSchema.d.ts +++ b/packages/react-native-codegen/src/CodegenSchema.d.ts @@ -46,6 +46,16 @@ 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 ObjectTypeAnnotation { readonly type: 'ObjectTypeAnnotation'; readonly properties: readonly NamedShape[]; From b6edf3cea2bd03ff9dc33b388f8587eb45ddc24d Mon Sep 17 00:00:00 2001 From: Arushi Kesarwani Date: Wed, 19 Nov 2025 00:00:00 -0800 Subject: [PATCH 04/17] Introduce TupleTypeAnnotation Summary: TupleTypeAnnotation is added for parity with UnionTypeAnnotation to support future implementation. Currently limited to String and Number literals as per: https://docs.google.com/document/d/1pTBMOEIov5n5-0L9z925XPvGX1YxlmI6n6FJvd0oXtE/edit?tab=t.0#heading=h.fhe5py9plytd Differential Revision: D87383455 --- packages/react-native-codegen/src/CodegenSchema.d.ts | 7 +++++++ packages/react-native-codegen/src/CodegenSchema.js | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/packages/react-native-codegen/src/CodegenSchema.d.ts b/packages/react-native-codegen/src/CodegenSchema.d.ts index 24f82ad80b0c40..a220ca10fa3e43 100644 --- a/packages/react-native-codegen/src/CodegenSchema.d.ts +++ b/packages/react-native-codegen/src/CodegenSchema.d.ts @@ -68,6 +68,13 @@ export interface 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'; } diff --git a/packages/react-native-codegen/src/CodegenSchema.js b/packages/react-native-codegen/src/CodegenSchema.js index 98cf7af93960ab..44286533e2a59a 100644 --- a/packages/react-native-codegen/src/CodegenSchema.js +++ b/packages/react-native-codegen/src/CodegenSchema.js @@ -77,6 +77,13 @@ export type UnionTypeAnnotation<+T> = $ReadOnly<{ types: $ReadOnlyArray, }>; +// 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', }>; From 47102f01973de696c639450baf5f991a7f56271f Mon Sep 17 00:00:00 2001 From: Arushi Kesarwani Date: Wed, 19 Nov 2025 00:00:06 -0800 Subject: [PATCH 05/17] Introduce BooleanLiteralTypeAnnotation (#54590) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/54590 Introduce `BooleanLiteralTypeAnnotation` in Flow & TypeScript to match the existing `StringLiteralTypeAnnotation` & `NumberLiteralTypeAnnotation` since Unions will be supporting Booleans along with String & Number Changelog: [Internal] Differential Revision: D87384473 --- packages/react-native-codegen/src/CodegenSchema.d.ts | 5 +++++ packages/react-native-codegen/src/CodegenSchema.js | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/packages/react-native-codegen/src/CodegenSchema.d.ts b/packages/react-native-codegen/src/CodegenSchema.d.ts index a220ca10fa3e43..88061b89dc6f4e 100644 --- a/packages/react-native-codegen/src/CodegenSchema.d.ts +++ b/packages/react-native-codegen/src/CodegenSchema.d.ts @@ -56,6 +56,11 @@ export interface StringLiteralTypeAnnotation { readonly value: string; } +export interface BooleanLiteralTypeAnnotation { + readonly type: 'BooleanLiteralTypeAnnotation'; + readonly value: boolean; +} + export interface ObjectTypeAnnotation { readonly type: 'ObjectTypeAnnotation'; readonly properties: readonly NamedShape[]; diff --git a/packages/react-native-codegen/src/CodegenSchema.js b/packages/react-native-codegen/src/CodegenSchema.js index 44286533e2a59a..2684864829d6a5 100644 --- a/packages/react-native-codegen/src/CodegenSchema.js +++ b/packages/react-native-codegen/src/CodegenSchema.js @@ -56,6 +56,11 @@ export type StringLiteralTypeAnnotation = $ReadOnly<{ value: string, }>; +export type BooleanLiteralTypeAnnotation = $ReadOnly<{ + type: 'BooleanLiteralTypeAnnotation', + value: boolean, +}>; + export type StringLiteralUnionTypeAnnotation = $ReadOnly<{ type: 'StringLiteralUnionTypeAnnotation', types: $ReadOnlyArray, From 8192211d41bd8706eed12cd2f10776a97c434847 Mon Sep 17 00:00:00 2001 From: Arushi Kesarwani Date: Wed, 19 Nov 2025 00:00:11 -0800 Subject: [PATCH 06/17] Introduce the supported member types of Union (#54591) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/54591 Following types will be supported in Union currently: 1. Number : NumberType + NumberLiteralType 2. Boolean : BooleanType + BooleanLiteralType 3. String : StringType + StringLiteralType 4. Object: NativeModuleObjectType These are the only ones that exist today as per : https://docs.google.com/document/d/1pTBMOEIov5n5-0L9z925XPvGX1YxlmI6n6FJvd0oXtE/edit?tab=t.0#heading=h.fhe5py9plytd Changelog: [Internal] Differential Revision: D87384995 --- packages/react-native-codegen/src/CodegenSchema.d.ts | 9 +++++++++ packages/react-native-codegen/src/CodegenSchema.js | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/packages/react-native-codegen/src/CodegenSchema.d.ts b/packages/react-native-codegen/src/CodegenSchema.d.ts index 88061b89dc6f4e..4f08147cffa278 100644 --- a/packages/react-native-codegen/src/CodegenSchema.d.ts +++ b/packages/react-native-codegen/src/CodegenSchema.d.ts @@ -405,6 +405,15 @@ export type UnionTypeAnnotationMemberType = | 'ObjectTypeAnnotation' | 'StringTypeAnnotation'; +export type NativeModuleUnionTypeAnnotationMemberType = + | NativeModuleObjectTypeAnnotation + | StringLiteralTypeAnnotation + | NumberLiteralTypeAnnotation + | BooleanLiteralTypeAnnotation + | BooleanTypeAnnotation + | StringTypeAnnotation + | NumberTypeAnnotation; + export interface NativeModuleUnionTypeAnnotation { readonly type: 'UnionTypeAnnotation'; readonly memberType: UnionTypeAnnotationMemberType; diff --git a/packages/react-native-codegen/src/CodegenSchema.js b/packages/react-native-codegen/src/CodegenSchema.js index 2684864829d6a5..a40c239390851d 100644 --- a/packages/react-native-codegen/src/CodegenSchema.js +++ b/packages/react-native-codegen/src/CodegenSchema.js @@ -384,6 +384,15 @@ export type UnionTypeAnnotationMemberType = | 'ObjectTypeAnnotation' | 'StringTypeAnnotation'; +export type NativeModuleUnionTypeAnnotationMemberType = + | NativeModuleObjectTypeAnnotation + | StringLiteralTypeAnnotation + | NumberLiteralTypeAnnotation + | BooleanLiteralTypeAnnotation + | BooleanTypeAnnotation + | StringTypeAnnotation + | NumberTypeAnnotation; + export type NativeModuleUnionTypeAnnotation = $ReadOnly<{ type: 'UnionTypeAnnotation', memberType: UnionTypeAnnotationMemberType, From 35c353fb623aba2242c1b1d34e041fe38b250f92 Mon Sep 17 00:00:00 2001 From: Arushi Kesarwani Date: Wed, 19 Nov 2025 00:00:17 -0800 Subject: [PATCH 07/17] Introduce UnionTypeAnnotation for Number & Boolean (#54592) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/54592 Adding `NumberLiteralUnionTypeAnnotation` & `BooleanLiteralUnionTypeAnnotation` to Flow & TypeScript so that they are in parity with other Union type : `StringLiteralUnionTypeAnnotation`. Number & Boolean aren't used anywhere yet. Changelog: [Internal] Differential Revision: D87386144 --- packages/react-native-codegen/src/CodegenSchema.d.ts | 6 ++++++ packages/react-native-codegen/src/CodegenSchema.js | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/packages/react-native-codegen/src/CodegenSchema.d.ts b/packages/react-native-codegen/src/CodegenSchema.d.ts index 4f08147cffa278..d5ab6ef8669078 100644 --- a/packages/react-native-codegen/src/CodegenSchema.d.ts +++ b/packages/react-native-codegen/src/CodegenSchema.d.ts @@ -340,6 +340,12 @@ export interface StringLiteralUnionTypeAnnotation { readonly types: NativeModuleStringLiteralTypeAnnotation[]; } +export type NumberLiteralUnionTypeAnnotation = + UnionTypeAnnotation; + +export type BooleanLiteralUnionTypeAnnotation = + UnionTypeAnnotation; + export interface NativeModuleNumberTypeAnnotation { readonly type: 'NumberTypeAnnotation'; } diff --git a/packages/react-native-codegen/src/CodegenSchema.js b/packages/react-native-codegen/src/CodegenSchema.js index a40c239390851d..bc8f9cdcb78047 100644 --- a/packages/react-native-codegen/src/CodegenSchema.js +++ b/packages/react-native-codegen/src/CodegenSchema.js @@ -66,6 +66,12 @@ export type StringLiteralUnionTypeAnnotation = $ReadOnly<{ types: $ReadOnlyArray, }>; +export type NumberLiteralUnionTypeAnnotation = + UnionTypeAnnotation; + +export type BooleanLiteralUnionTypeAnnotation = + UnionTypeAnnotation; + export type VoidTypeAnnotation = $ReadOnly<{ type: 'VoidTypeAnnotation', }>; From 4575f47e49ee13a8317aea8fcb2fe5df3fb8596f Mon Sep 17 00:00:00 2001 From: Arushi Kesarwani Date: Wed, 19 Nov 2025 00:00:23 -0800 Subject: [PATCH 08/17] Add BooleanLiteralTypeAnnotation to the NativeModuleBaseTypeAnnotation in Flow (#54593) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/54593 Just as `NumberLiteralTypeAnnotation` was part of the `NativeModuleBaseTypeAnnotation` in Flow, adding the `BooleanLiteralTypeAnnotation` NOTE: Didn't add this change for TS as both `NumberLiteralTypeAnnotation` was not included as part of `NativeModuleBaseTypeAnnotation` in TS, also the generators were not failing in TS for this. Changelog: [Internal] Differential Revision: D87392274 --- packages/react-native-codegen/src/CodegenSchema.js | 1 + .../generators/modules/GenerateModuleObjCpp/StructCollector.js | 2 ++ 2 files changed, 3 insertions(+) diff --git a/packages/react-native-codegen/src/CodegenSchema.js b/packages/react-native-codegen/src/CodegenSchema.js index bc8f9cdcb78047..6a760cdd70d208 100644 --- a/packages/react-native-codegen/src/CodegenSchema.js +++ b/packages/react-native-codegen/src/CodegenSchema.js @@ -432,6 +432,7 @@ export type NativeModuleBaseTypeAnnotation = | StringLiteralUnionTypeAnnotation | NativeModuleNumberTypeAnnotation | NumberLiteralTypeAnnotation + | BooleanLiteralTypeAnnotation | Int32TypeAnnotation | DoubleTypeAnnotation | FloatTypeAnnotation diff --git a/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/StructCollector.js b/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/StructCollector.js index db243d9f3024a2..88ef558f40e0bc 100644 --- a/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/StructCollector.js +++ b/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/StructCollector.js @@ -11,6 +11,7 @@ 'use strict'; import type { + BooleanLiteralTypeAnnotation, BooleanTypeAnnotation, DoubleTypeAnnotation, FloatTypeAnnotation, @@ -65,6 +66,7 @@ export type StructTypeAnnotation = | StringLiteralUnionTypeAnnotation | NativeModuleNumberTypeAnnotation | NumberLiteralTypeAnnotation + | BooleanLiteralTypeAnnotation | Int32TypeAnnotation | DoubleTypeAnnotation | FloatTypeAnnotation From 8e291961db28666feffd762e74e586e1d7b8bea7 Mon Sep 17 00:00:00 2001 From: Arushi Kesarwani Date: Wed, 19 Nov 2025 00:00:29 -0800 Subject: [PATCH 09/17] Refactor NativeModuleUnionTypeAnnotation Summary: Refactoring `NativeModuleUnionTypeAnnotation` to use the newly introduced `NativeModuleUnionTypeAnnotationMemberType` Changelog: [Internal] Differential Revision: D87386775 --- packages/react-native-codegen/src/CodegenSchema.d.ts | 11 ++--------- packages/react-native-codegen/src/CodegenSchema.js | 11 ++--------- 2 files changed, 4 insertions(+), 18 deletions(-) diff --git a/packages/react-native-codegen/src/CodegenSchema.d.ts b/packages/react-native-codegen/src/CodegenSchema.d.ts index d5ab6ef8669078..a1532bb7564a2b 100644 --- a/packages/react-native-codegen/src/CodegenSchema.d.ts +++ b/packages/react-native-codegen/src/CodegenSchema.d.ts @@ -406,11 +406,6 @@ export interface NativeModulePromiseTypeAnnotation { readonly elementType: Nullable | VoidTypeAnnotation; } -export type UnionTypeAnnotationMemberType = - | 'NumberTypeAnnotation' - | 'ObjectTypeAnnotation' - | 'StringTypeAnnotation'; - export type NativeModuleUnionTypeAnnotationMemberType = | NativeModuleObjectTypeAnnotation | StringLiteralTypeAnnotation @@ -420,10 +415,8 @@ export type NativeModuleUnionTypeAnnotationMemberType = | StringTypeAnnotation | NumberTypeAnnotation; -export interface NativeModuleUnionTypeAnnotation { - readonly type: 'UnionTypeAnnotation'; - readonly memberType: UnionTypeAnnotationMemberType; -} +export type NativeModuleUnionTypeAnnotation = + UnionTypeAnnotation; export interface NativeModuleMixedTypeAnnotation { readonly type: 'MixedTypeAnnotation'; diff --git a/packages/react-native-codegen/src/CodegenSchema.js b/packages/react-native-codegen/src/CodegenSchema.js index 6a760cdd70d208..2d63fff6cc8013 100644 --- a/packages/react-native-codegen/src/CodegenSchema.js +++ b/packages/react-native-codegen/src/CodegenSchema.js @@ -385,11 +385,6 @@ export type NativeModulePromiseTypeAnnotation = $ReadOnly<{ elementType: VoidTypeAnnotation | Nullable, }>; -export type UnionTypeAnnotationMemberType = - | 'NumberTypeAnnotation' - | 'ObjectTypeAnnotation' - | 'StringTypeAnnotation'; - export type NativeModuleUnionTypeAnnotationMemberType = | NativeModuleObjectTypeAnnotation | StringLiteralTypeAnnotation @@ -399,10 +394,8 @@ export type NativeModuleUnionTypeAnnotationMemberType = | StringTypeAnnotation | NumberTypeAnnotation; -export type NativeModuleUnionTypeAnnotation = $ReadOnly<{ - type: 'UnionTypeAnnotation', - memberType: UnionTypeAnnotationMemberType, -}>; +export type NativeModuleUnionTypeAnnotation = + UnionTypeAnnotation; export type NativeModuleMixedTypeAnnotation = $ReadOnly<{ type: 'MixedTypeAnnotation', From d2bdfe85fa50471270f68a652e3ac9b847a520d9 Mon Sep 17 00:00:00 2001 From: Arushi Kesarwani Date: Wed, 19 Nov 2025 00:00:36 -0800 Subject: [PATCH 10/17] Un-special Case StringLiteralUnionTypeAnnotation Summary: Now that UnionTypeAnnotation itself supports both the member types and value, we can fold the StringLiteralUnionTypeAnnotation into the UnionTypeAnnotation and un-special case the StringLiteralUnionTypeAnnotation Changelog: [Internal] Differential Revision: D87388948 --- packages/react-native-codegen/src/CodegenSchema.d.ts | 6 ++---- packages/react-native-codegen/src/CodegenSchema.js | 6 ++---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/packages/react-native-codegen/src/CodegenSchema.d.ts b/packages/react-native-codegen/src/CodegenSchema.d.ts index a1532bb7564a2b..3c1ba4b9f4bb1d 100644 --- a/packages/react-native-codegen/src/CodegenSchema.d.ts +++ b/packages/react-native-codegen/src/CodegenSchema.d.ts @@ -335,10 +335,8 @@ export interface NativeModuleStringLiteralTypeAnnotation { readonly value: string; } -export interface StringLiteralUnionTypeAnnotation { - readonly type: 'StringLiteralUnionTypeAnnotation'; - readonly types: NativeModuleStringLiteralTypeAnnotation[]; -} +export type StringLiteralUnionTypeAnnotation = + UnionTypeAnnotation; export type NumberLiteralUnionTypeAnnotation = UnionTypeAnnotation; diff --git a/packages/react-native-codegen/src/CodegenSchema.js b/packages/react-native-codegen/src/CodegenSchema.js index 2d63fff6cc8013..d94e410ee5f681 100644 --- a/packages/react-native-codegen/src/CodegenSchema.js +++ b/packages/react-native-codegen/src/CodegenSchema.js @@ -61,10 +61,8 @@ export type BooleanLiteralTypeAnnotation = $ReadOnly<{ value: boolean, }>; -export type StringLiteralUnionTypeAnnotation = $ReadOnly<{ - type: 'StringLiteralUnionTypeAnnotation', - types: $ReadOnlyArray, -}>; +export type StringLiteralUnionTypeAnnotation = + UnionTypeAnnotation; export type NumberLiteralUnionTypeAnnotation = UnionTypeAnnotation; From 195e737fbf0c54609634e8a05d28e64569f15a8b Mon Sep 17 00:00:00 2001 From: Arushi Kesarwani Date: Wed, 19 Nov 2025 00:00:42 -0800 Subject: [PATCH 11/17] Modifying the Parser logic to handle Unions of different types and remove the special handling of StringLiteralUnionType Summary: - Getting rid of emitStringLiteralUnion logic in parser - Modifying the emitUnion logic in parser Changelog: [Internal] Differential Revision: D87412493 --- .../src/parsers/parser.js | 12 +-- .../src/parsers/parserMock.js | 10 +- .../src/parsers/parsers-primitives.js | 99 ++++++++----------- 3 files changed, 46 insertions(+), 75 deletions(-) diff --git a/packages/react-native-codegen/src/parsers/parser.js b/packages/react-native-codegen/src/parsers/parser.js index f151fd1e2f7248..4e25ed6495c5ef 100644 --- a/packages/react-native-codegen/src/parsers/parser.js +++ b/packages/react-native-codegen/src/parsers/parser.js @@ -18,10 +18,10 @@ import type { NativeModuleEnumMember, NativeModuleEnumMemberType, NativeModuleParamTypeAnnotation, + NativeModuleUnionTypeAnnotationMemberType, Nullable, PropTypeAnnotation, SchemaType, - UnionTypeAnnotationMemberType, } from '../CodegenSchema'; import type {ParserType} from './errors'; import type { @@ -146,15 +146,7 @@ export interface Parser { */ remapUnionTypeAnnotationMemberNames( types: $FlowFixMe, - ): UnionTypeAnnotationMemberType[]; - /** - * Given a union annotation members types, it returns an array of string literals. - * @parameter membersTypes: union annotation members types - * @returns: an array of string literals. - */ - getStringLiteralUnionTypeAnnotationStringLiterals( - types: $FlowFixMe, - ): string[]; + ): NativeModuleUnionTypeAnnotationMemberType[]; /** * Given the name of a file, it returns a Schema. * @parameter filename: the name of the file. diff --git a/packages/react-native-codegen/src/parsers/parserMock.js b/packages/react-native-codegen/src/parsers/parserMock.js index 7b22d8a0a5e97c..5ce04ca1139697 100644 --- a/packages/react-native-codegen/src/parsers/parserMock.js +++ b/packages/react-native-codegen/src/parsers/parserMock.js @@ -18,10 +18,10 @@ import type { NativeModuleEnumMember, NativeModuleEnumMemberType, NativeModuleParamTypeAnnotation, + NativeModuleUnionTypeAnnotationMemberType, Nullable, PropTypeAnnotation, SchemaType, - UnionTypeAnnotationMemberType, } from '../CodegenSchema'; import type {ParserType} from './errors'; import type { @@ -105,13 +105,7 @@ export class MockedParser implements Parser { remapUnionTypeAnnotationMemberNames( membersTypes: $FlowFixMe[], - ): UnionTypeAnnotationMemberType[] { - return []; - } - - getStringLiteralUnionTypeAnnotationStringLiterals( - membersTypes: $FlowFixMe[], - ): string[] { + ): NativeModuleUnionTypeAnnotationMemberType[] { return []; } diff --git a/packages/react-native-codegen/src/parsers/parsers-primitives.js b/packages/react-native-codegen/src/parsers/parsers-primitives.js index 27097a0b0b6f09..3dd4b5bf5e4743 100644 --- a/packages/react-native-codegen/src/parsers/parsers-primitives.js +++ b/packages/react-native-codegen/src/parsers/parsers-primitives.js @@ -30,12 +30,12 @@ import type { NativeModuleTypeAliasTypeAnnotation, NativeModuleTypeAnnotation, NativeModuleUnionTypeAnnotation, + NativeModuleUnionTypeAnnotationMemberType, Nullable, NumberLiteralTypeAnnotation, ObjectTypeAnnotation, ReservedTypeAnnotation, StringLiteralTypeAnnotation, - StringLiteralUnionTypeAnnotation, StringTypeAnnotation, VoidTypeAnnotation, } from '../CodegenSchema'; @@ -51,11 +51,7 @@ const { throwIfPartialNotAnnotatingTypeParameter, throwIfPartialWithMoreParameter, } = require('./error-utils'); -const { - ParserError, - UnsupportedTypeAnnotationParserError, - UnsupportedUnionTypeAnnotationParserError, -} = require('./errors'); +const {ParserError, UnsupportedTypeAnnotationParserError} = require('./errors'); const { assertGenericTypeAnnotationHasExactlyOneTypeParameter, translateFunctionTypeAnnotation, @@ -420,61 +416,50 @@ function emitUnion( nullable: boolean, hasteModuleName: string, typeAnnotation: $FlowFixMe, + types: TypeDeclarationMap, + aliasMap: {...NativeModuleAliasMap}, + enumMap: {...NativeModuleEnumMap}, + tryParse: ParserErrorCapturer, + cxxOnly: boolean, + translateTypeAnnotation: $FlowFixMe, parser: Parser, -): Nullable< - NativeModuleUnionTypeAnnotation | StringLiteralUnionTypeAnnotation, -> { - // Get all the literals by type - // Verify they are all the same - // If string, persist as StringLiteralUnionType - // If number, persist as NumberTypeAnnotation (TODO: Number literal) - - const unionTypes = parser.remapUnionTypeAnnotationMemberNames( - typeAnnotation.types, +): Nullable { + const unparsedMemberTypes: $ReadOnlyArray<$FlowFixMe> = + (typeAnnotation.types: $ReadOnlyArray<$FlowFixMe>); + + const memberTypes = unparsedMemberTypes.map( + (memberType: $FlowFixMe): NativeModuleUnionTypeAnnotationMemberType => { + switch (memberType.type) { + case 'NumberLiteralTypeAnnotation': + case 'StringLiteralTypeAnnotation': + case 'BooleanLiteralTypeAnnotation': + case 'TSLiteralType': + case 'GenericTypeAnnotation': + case 'TSTypeLiteral': + case 'ObjectTypeAnnotation': + return translateTypeAnnotation( + hasteModuleName, + memberType, + types, + aliasMap, + enumMap, + tryParse, + cxxOnly, + parser, + ); + default: + throw new UnsupportedTypeAnnotationParserError( + hasteModuleName, + memberType, + parser.language(), + ); + } + }, ); - // Only support unionTypes of the same kind - if (unionTypes.length > 1) { - throw new UnsupportedUnionTypeAnnotationParserError( - hasteModuleName, - typeAnnotation, - unionTypes, - ); - } - - if (unionTypes[0] === 'StringTypeAnnotation') { - // Reprocess as a string literal union - return emitStringLiteralUnion( - nullable, - hasteModuleName, - typeAnnotation, - parser, - ); - } - return wrapNullable(nullable, { type: 'UnionTypeAnnotation', - memberType: unionTypes[0], - }); -} - -function emitStringLiteralUnion( - nullable: boolean, - hasteModuleName: string, - typeAnnotation: $FlowFixMe, - parser: Parser, -): Nullable { - const stringLiterals = - parser.getStringLiteralUnionTypeAnnotationStringLiterals( - typeAnnotation.types, - ); - - return wrapNullable(nullable, { - type: 'StringLiteralUnionTypeAnnotation', - types: stringLiterals.map(stringLiteral => ({ - type: 'StringLiteralTypeAnnotation', - value: stringLiteral, - })), + types: memberTypes, }); } @@ -752,7 +737,7 @@ function emitUnionProp( name, optional, typeAnnotation: { - type: 'StringLiteralUnionTypeAnnotation', + type: 'UnionTypeAnnotation', types: typeAnnotation.types.map(option => ({ type: 'StringLiteralTypeAnnotation', value: parser.getLiteralValue(option), From 090a66aa53648bb618eb4669d17df75cfa8f4b1d Mon Sep 17 00:00:00 2001 From: Arushi Kesarwani Date: Wed, 19 Nov 2025 00:00:49 -0800 Subject: [PATCH 12/17] Flow Parser Changes Summary: Flow Parser changes to accomodate the new emitUnion Changelog: [Internal] Differential Revision: D87412532 --- .../src/parsers/flow/components/events.js | 2 +- .../src/parsers/flow/modules/index.js | 13 ++++++++++++- .../react-native-codegen/src/parsers/flow/parser.js | 10 ++-------- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/packages/react-native-codegen/src/parsers/flow/components/events.js b/packages/react-native-codegen/src/parsers/flow/components/events.js index ba900707aaae0e..c8f41e125c1b0a 100644 --- a/packages/react-native-codegen/src/parsers/flow/components/events.js +++ b/packages/react-native-codegen/src/parsers/flow/components/events.js @@ -115,7 +115,7 @@ function extractArrayElementType( }; case 'UnionTypeAnnotation': return { - type: 'StringLiteralUnionTypeAnnotation', + type: 'UnionTypeAnnotation', types: typeAnnotation.types.map(option => ({ type: 'StringLiteralTypeAnnotation', value: parser.getLiteralValue(option), diff --git a/packages/react-native-codegen/src/parsers/flow/modules/index.js b/packages/react-native-codegen/src/parsers/flow/modules/index.js index 51972f39ae03f6..33d858d8ba8a77 100644 --- a/packages/react-native-codegen/src/parsers/flow/modules/index.js +++ b/packages/react-native-codegen/src/parsers/flow/modules/index.js @@ -244,7 +244,18 @@ function translateTypeAnnotation( ); } case 'UnionTypeAnnotation': { - return emitUnion(nullable, hasteModuleName, typeAnnotation, parser); + return emitUnion( + nullable, + hasteModuleName, + typeAnnotation, + types, + aliasMap, + enumMap, + tryParse, + cxxOnly, + translateTypeAnnotation, + parser, + ); } case 'NumberLiteralTypeAnnotation': { return emitNumberLiteral(nullable, typeAnnotation.value); diff --git a/packages/react-native-codegen/src/parsers/flow/parser.js b/packages/react-native-codegen/src/parsers/flow/parser.js index c8224d4e44e729..d251d7976dbcd5 100644 --- a/packages/react-native-codegen/src/parsers/flow/parser.js +++ b/packages/react-native-codegen/src/parsers/flow/parser.js @@ -18,10 +18,10 @@ import type { NativeModuleEnumMember, NativeModuleEnumMemberType, NativeModuleParamTypeAnnotation, + NativeModuleUnionTypeAnnotationMemberType, Nullable, PropTypeAnnotation, SchemaType, - UnionTypeAnnotationMemberType, } from '../../CodegenSchema'; import type {ParserType} from '../errors'; import type { @@ -111,7 +111,7 @@ class FlowParser implements Parser { remapUnionTypeAnnotationMemberNames( membersTypes: $FlowFixMe[], - ): UnionTypeAnnotationMemberType[] { + ): NativeModuleUnionTypeAnnotationMemberType[] { const remapLiteral = (item: $FlowFixMe) => { return item.type .replace('NumberLiteralTypeAnnotation', 'NumberTypeAnnotation') @@ -121,12 +121,6 @@ class FlowParser implements Parser { return [...new Set(membersTypes.map(remapLiteral))]; } - getStringLiteralUnionTypeAnnotationStringLiterals( - membersTypes: $FlowFixMe[], - ): string[] { - return membersTypes.map((item: $FlowFixMe) => item.value); - } - parseFile(filename: string): SchemaType { const contents = fs.readFileSync(filename, 'utf8'); From 4bfda9d2eedaad07d53fb7eec088464db09e7172 Mon Sep 17 00:00:00 2001 From: Arushi Kesarwani Date: Wed, 19 Nov 2025 00:00:57 -0800 Subject: [PATCH 13/17] TypeScript Parser Changes Summary: TypeScript Parser changes to accomodate new emitUnion Changelog: [Internal] Differential Revision: D87412635 --- .../src/parsers/typescript/components/events.js | 2 +- .../src/parsers/typescript/modules/index.js | 13 ++++++++++++- .../src/parsers/typescript/parser.js | 10 ++-------- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/packages/react-native-codegen/src/parsers/typescript/components/events.js b/packages/react-native-codegen/src/parsers/typescript/components/events.js index 1a2e038756bda3..9a97288a98f53e 100644 --- a/packages/react-native-codegen/src/parsers/typescript/components/events.js +++ b/packages/react-native-codegen/src/parsers/typescript/components/events.js @@ -127,7 +127,7 @@ function extractArrayElementType( }; case 'TSUnionType': return { - type: 'StringLiteralUnionTypeAnnotation', + type: 'UnionTypeAnnotation', types: typeAnnotation.types.map(option => ({ type: 'StringLiteralTypeAnnotation', value: parser.getLiteralValue(option), diff --git a/packages/react-native-codegen/src/parsers/typescript/modules/index.js b/packages/react-native-codegen/src/parsers/typescript/modules/index.js index 15f96966660d6b..56573e49645c72 100644 --- a/packages/react-native-codegen/src/parsers/typescript/modules/index.js +++ b/packages/react-native-codegen/src/parsers/typescript/modules/index.js @@ -398,7 +398,18 @@ function translateTypeAnnotation( ); } case 'TSUnionType': { - return emitUnion(nullable, hasteModuleName, typeAnnotation, parser); + return emitUnion( + nullable, + hasteModuleName, + typeAnnotation, + types, + aliasMap, + enumMap, + tryParse, + cxxOnly, + translateTypeAnnotation, + parser, + ); } case 'TSLiteralType': { const literal = typeAnnotation.literal; diff --git a/packages/react-native-codegen/src/parsers/typescript/parser.js b/packages/react-native-codegen/src/parsers/typescript/parser.js index edbaf368b526e0..60416eb6a1b3ff 100644 --- a/packages/react-native-codegen/src/parsers/typescript/parser.js +++ b/packages/react-native-codegen/src/parsers/typescript/parser.js @@ -18,10 +18,10 @@ import type { NativeModuleEnumMember, NativeModuleEnumMemberType, NativeModuleParamTypeAnnotation, + NativeModuleUnionTypeAnnotationMemberType, Nullable, PropTypeAnnotation, SchemaType, - UnionTypeAnnotationMemberType, } from '../../CodegenSchema'; import type {ParserType} from '../errors'; import type { @@ -109,7 +109,7 @@ class TypeScriptParser implements Parser { remapUnionTypeAnnotationMemberNames( membersTypes: Array<$FlowFixMe>, - ): Array { + ): Array { const remapLiteral = (item: $FlowFixMe) => { return item.literal ? item.literal.type @@ -123,12 +123,6 @@ class TypeScriptParser implements Parser { return [...new Set(membersTypes.map(remapLiteral))]; } - getStringLiteralUnionTypeAnnotationStringLiterals( - membersTypes: Array<$FlowFixMe>, - ): Array { - return membersTypes.map((item: $FlowFixMe) => item.literal.value); - } - parseFile(filename: string): SchemaType { const contents = fs.readFileSync(filename, 'utf8'); From c428656db92ca0205367cfdad5a95826b9672984 Mon Sep 17 00:00:00 2001 From: Arushi Kesarwani Date: Wed, 19 Nov 2025 00:01:03 -0800 Subject: [PATCH 14/17] Getting rid of UnsupportedUnionTypeAnnotationParserError Summary: Now that different member types in Union is no more a parser error getting rid of `UnsupportedUnionTypeAnnotationParserError` Changelog: [Internal] Differential Revision: D87412703 --- .../src/parsers/errors.js | 22 ------------------- 1 file changed, 22 deletions(-) diff --git a/packages/react-native-codegen/src/parsers/errors.js b/packages/react-native-codegen/src/parsers/errors.js index d86cc1d9ae2ca1..ba5b3604efbc92 100644 --- a/packages/react-native-codegen/src/parsers/errors.js +++ b/packages/react-native-codegen/src/parsers/errors.js @@ -10,7 +10,6 @@ 'use strict'; -import type {UnionTypeAnnotationMemberType} from '../CodegenSchema'; import type {Parser} from './parser'; export type ParserType = 'Flow' | 'TypeScript'; @@ -337,26 +336,6 @@ class UnsupportedEnumDeclarationParserError extends ParserError { } } -/** - * Union parsing errors - */ - -class UnsupportedUnionTypeAnnotationParserError extends ParserError { - constructor( - nativeModuleName: string, - arrayElementTypeAST: $FlowFixMe, - types: UnionTypeAnnotationMemberType[], - ) { - super( - nativeModuleName, - arrayElementTypeAST, - `Union members must be of the same type, but multiple types were found ${types.join( - ', ', - )}'.`, - ); - } -} - /** * Module parsing errors */ @@ -460,7 +439,6 @@ module.exports = { UnsupportedFunctionParamTypeAnnotationParserError, UnsupportedFunctionReturnTypeAnnotationParserError, UnsupportedEnumDeclarationParserError, - UnsupportedUnionTypeAnnotationParserError, UnsupportedModuleEventEmitterTypePropertyParserError, UnsupportedModuleEventEmitterPropertyParserError, UnsupportedModulePropertyParserError, From 3f7b4ffda6d9054501f17d1179f11e89c08a08cb Mon Sep 17 00:00:00 2001 From: Arushi Kesarwani Date: Wed, 19 Nov 2025 00:01:08 -0800 Subject: [PATCH 15/17] Add Handler for Union Type Annotation for generators Summary: Added logic for handling Unions that will be used by all generators. NOTE: Generators behavior still remain unchanged hence don't allow unions of different types. Only RN Compat Checker consumes this new change of Union support of different types Changelog: [Internal] Differential Revision: D87391424 --- .../src/generators/Utils.js | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/packages/react-native-codegen/src/generators/Utils.js b/packages/react-native-codegen/src/generators/Utils.js index da692692daafac..63a9a9dabafdc4 100644 --- a/packages/react-native-codegen/src/generators/Utils.js +++ b/packages/react-native-codegen/src/generators/Utils.js @@ -10,6 +10,8 @@ 'use strict'; +import type {NativeModuleUnionTypeAnnotation} from '../CodegenSchema'; + function capitalize(string: string): string { return string.charAt(0).toUpperCase() + string.slice(1); } @@ -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): 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, From a126b1631d2fb5bacfd1b205b348f38d10dc93e4 Mon Sep 17 00:00:00 2001 From: Arushi Kesarwani Date: Wed, 19 Nov 2025 00:01:14 -0800 Subject: [PATCH 16/17] Generator Modules handling for Unions & BooleanLiteralTypeAnnotation Summary: - Adding handling in generators/modules for handling Unions using the newly defined Utils function (parseValidUnionType) - Adding handling for generators/modules for BooleanLiteralTypeAnnotation (same as BooleanTypeAnnotation) just as is done for NumberLiteralTypeAnnotation NOTE:Generators behavior still remain unchanged hence don't allow unions of different types. Only RN Compat Checker consumes this new change of Union support of different types Changelog: [Internal] Differential Revision: D87410022 --- .../src/generators/modules/GenerateModuleH.js | 45 ++++++---- .../modules/GenerateModuleJavaSpec.js | 88 ++++++++++++------- .../modules/GenerateModuleJniCpp.js | 63 +++++++------ .../GenerateModuleObjCpp/StructCollector.js | 24 ++--- .../header/serializeConstantsStruct.js | 40 +++++++-- .../header/serializeRegularStruct.js | 40 +++++++-- .../serializeEventEmitter.js | 25 ++++-- .../GenerateModuleObjCpp/serializeMethod.js | 63 ++++++++----- 8 files changed, 259 insertions(+), 129 deletions(-) diff --git a/packages/react-native-codegen/src/generators/modules/GenerateModuleH.js b/packages/react-native-codegen/src/generators/modules/GenerateModuleH.js index 2779f16572e10d..9c85b82a59cb85 100644 --- a/packages/react-native-codegen/src/generators/modules/GenerateModuleH.js +++ b/packages/react-native-codegen/src/generators/modules/GenerateModuleH.js @@ -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, @@ -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': @@ -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)`); @@ -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': @@ -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': @@ -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); diff --git a/packages/react-native-codegen/src/generators/modules/GenerateModuleJavaSpec.js b/packages/react-native-codegen/src/generators/modules/GenerateModuleJavaSpec.js index e634125797cae6..ee55413d361615 100644 --- a/packages/react-native-codegen/src/generators/modules/GenerateModuleJavaSpec.js +++ b/packages/react-native-codegen/src/generators/modules/GenerateModuleJavaSpec.js @@ -24,7 +24,7 @@ import type {AliasResolver} from './Utils'; const {unwrapNullable} = require('../../parsers/parsers-commons'); const {wrapOptional} = require('../TypeUtils/Java'); -const {toPascalCase} = require('../Utils'); +const {parseValidUnionType, toPascalCase} = require('../Utils'); const {createAliasResolver, getModules} = require('./Utils'); type FilesOutput = Map; @@ -127,14 +127,28 @@ function translateEventEmitterTypeToJavaType( eventEmitter: NativeModuleEventEmitterShape, imports: Set, ): string { - const type = eventEmitter.typeAnnotation.typeAnnotation.type; - switch (type) { + const typeAnnotation = eventEmitter.typeAnnotation.typeAnnotation; + switch (typeAnnotation.type) { case 'StringTypeAnnotation': return 'String'; case 'StringLiteralTypeAnnotation': return 'String'; - case 'StringLiteralUnionTypeAnnotation': - return 'String'; + case 'UnionTypeAnnotation': + const validUnionType = parseValidUnionType(typeAnnotation); + switch (validUnionType) { + case 'boolean': + return 'boolean'; + case 'number': + return 'double'; + case 'object': + imports.add('com.facebook.react.bridge.ReadableMap'); + return 'ReadableMap'; + case 'string': + return 'String'; + default: + (validUnionType: empty); + throw new Error(`Unsupported union member type`); + } case 'NumberTypeAnnotation': case 'NumberLiteralTypeAnnotation': case 'FloatTypeAnnotation': @@ -160,7 +174,7 @@ function translateEventEmitterTypeToJavaType( `Unsupported eventType for ${eventEmitter.name}. Found: ${eventEmitter.typeAnnotation.typeAnnotation.type}`, ); default: - (type: empty); + (typeAnnotation.type: empty); throw new Error( `Unsupported eventType for ${eventEmitter.name}. Found: ${eventEmitter.typeAnnotation.typeAnnotation.type}`, ); @@ -200,8 +214,6 @@ function translateFunctionParamToJavaType( return wrapOptional('String', isRequired); case 'StringLiteralTypeAnnotation': return wrapOptional('String', isRequired); - case 'StringLiteralUnionTypeAnnotation': - return wrapOptional('String', isRequired); case 'NumberTypeAnnotation': return wrapOptional('double', isRequired); case 'NumberLiteralTypeAnnotation': @@ -214,6 +226,8 @@ function translateFunctionParamToJavaType( return wrapOptional('double', isRequired); case 'BooleanTypeAnnotation': return wrapOptional('boolean', isRequired); + case 'BooleanLiteralTypeAnnotation': + return wrapOptional('boolean', isRequired); case 'EnumDeclaration': switch (realTypeAnnotation.memberType) { case 'NumberTypeAnnotation': @@ -224,18 +238,20 @@ function translateFunctionParamToJavaType( throw new Error(createErrorMessage(realTypeAnnotation.type)); } case 'UnionTypeAnnotation': - switch (typeAnnotation.memberType) { - case 'NumberTypeAnnotation': + const validUnionType = parseValidUnionType(realTypeAnnotation); + switch (validUnionType) { + case 'boolean': + return wrapOptional('boolean', isRequired); + case 'number': return wrapOptional('double', isRequired); - case 'ObjectTypeAnnotation': + case 'object': imports.add('com.facebook.react.bridge.ReadableMap'); return wrapOptional('ReadableMap', isRequired); - case 'StringTypeAnnotation': + case 'string': return wrapOptional('String', isRequired); default: - throw new Error( - `Unsupported union member returning value, found: ${realTypeAnnotation.memberType}"`, - ); + (validUnionType: empty); + throw new Error(`Unsupported union member type`); } case 'ObjectTypeAnnotation': imports.add('com.facebook.react.bridge.ReadableMap'); @@ -296,8 +312,6 @@ function translateFunctionReturnTypeToJavaType( return wrapOptional('String', isRequired); case 'StringLiteralTypeAnnotation': return wrapOptional('String', isRequired); - case 'StringLiteralUnionTypeAnnotation': - return wrapOptional('String', isRequired); case 'NumberTypeAnnotation': return wrapOptional('double', isRequired); case 'NumberLiteralTypeAnnotation': @@ -310,6 +324,8 @@ function translateFunctionReturnTypeToJavaType( return wrapOptional('double', isRequired); case 'BooleanTypeAnnotation': return wrapOptional('boolean', isRequired); + case 'BooleanLiteralTypeAnnotation': + return wrapOptional('boolean', isRequired); case 'EnumDeclaration': switch (realTypeAnnotation.memberType) { case 'NumberTypeAnnotation': @@ -320,18 +336,20 @@ function translateFunctionReturnTypeToJavaType( throw new Error(createErrorMessage(realTypeAnnotation.type)); } case 'UnionTypeAnnotation': - switch (realTypeAnnotation.memberType) { - case 'NumberTypeAnnotation': + const validUnionType = parseValidUnionType(realTypeAnnotation); + switch (validUnionType) { + case 'boolean': + return wrapOptional('boolean', isRequired); + case 'number': return wrapOptional('double', isRequired); - case 'ObjectTypeAnnotation': + case 'object': imports.add('com.facebook.react.bridge.WritableMap'); - return wrapOptional('WritableMap', isRequired); - case 'StringTypeAnnotation': + return wrapOptional('ReadableMap', isRequired); + case 'string': return wrapOptional('String', isRequired); default: - throw new Error( - `Unsupported union member returning value, found: ${realTypeAnnotation.memberType}"`, - ); + (validUnionType: empty); + throw new Error(`Unsupported union member type`); } case 'ObjectTypeAnnotation': imports.add('com.facebook.react.bridge.WritableMap'); @@ -388,6 +406,8 @@ function getFalsyReturnStatementFromReturnType( return nullable ? 'return null;' : 'return 0;'; case 'BooleanTypeAnnotation': return nullable ? 'return null;' : 'return false;'; + case 'BooleanLiteralTypeAnnotation': + return nullable ? 'return null;' : 'return false;'; case 'EnumDeclaration': switch (realTypeAnnotation.memberType) { case 'NumberTypeAnnotation': @@ -398,24 +418,24 @@ function getFalsyReturnStatementFromReturnType( throw new Error(createErrorMessage(realTypeAnnotation.type)); } case 'UnionTypeAnnotation': - switch (realTypeAnnotation.memberType) { - case 'NumberTypeAnnotation': + const validUnionType = parseValidUnionType(realTypeAnnotation); + switch (validUnionType) { + case 'boolean': + return nullable ? 'return null;' : 'return false;'; + case 'number': return nullable ? 'return null;' : 'return 0;'; - case 'ObjectTypeAnnotation': + case 'object': return 'return null;'; - case 'StringTypeAnnotation': + case 'string': return nullable ? 'return null;' : 'return "";'; default: - throw new Error( - `Unsupported union member returning value, found: ${realTypeAnnotation.memberType}"`, - ); + (validUnionType: empty); + throw new Error(`Unsupported union member type`); } case 'StringTypeAnnotation': return nullable ? 'return null;' : 'return "";'; case 'StringLiteralTypeAnnotation': return nullable ? 'return null;' : 'return "";'; - case 'StringLiteralUnionTypeAnnotation': - return nullable ? 'return null;' : 'return "";'; case 'ObjectTypeAnnotation': return 'return null;'; case 'GenericObjectTypeAnnotation': diff --git a/packages/react-native-codegen/src/generators/modules/GenerateModuleJniCpp.js b/packages/react-native-codegen/src/generators/modules/GenerateModuleJniCpp.js index e9ece53f47d867..691c5a30c2e51d 100644 --- a/packages/react-native-codegen/src/generators/modules/GenerateModuleJniCpp.js +++ b/packages/react-native-codegen/src/generators/modules/GenerateModuleJniCpp.js @@ -23,6 +23,7 @@ import type { import type {AliasResolver} from './Utils'; const {unwrapNullable} = require('../../parsers/parsers-commons'); +const {parseValidUnionType} = require('../Utils'); const {createAliasResolver, getModules} = require('./Utils'); type FilesOutput = Map; @@ -167,10 +168,10 @@ function translateReturnTypeToKind( return 'StringKind'; case 'StringLiteralTypeAnnotation': return 'StringKind'; - case 'StringLiteralUnionTypeAnnotation': - return 'StringKind'; case 'BooleanTypeAnnotation': return 'BooleanKind'; + case 'BooleanLiteralTypeAnnotation': + return 'BooleanKind'; case 'EnumDeclaration': switch (typeAnnotation.memberType) { case 'NumberTypeAnnotation': @@ -183,17 +184,19 @@ function translateReturnTypeToKind( ); } case 'UnionTypeAnnotation': - switch (typeAnnotation.memberType) { - case 'NumberTypeAnnotation': + const validUnionType = parseValidUnionType(realTypeAnnotation); + switch (validUnionType) { + case 'boolean': + return 'BooleanKind'; + case 'number': return 'NumberKind'; - case 'ObjectTypeAnnotation': + case 'object': return 'ObjectKind'; - case 'StringTypeAnnotation': + case 'string': return 'StringKind'; default: - throw new Error( - `Unsupported union member returning value, found: ${realTypeAnnotation.memberType}"`, - ); + (validUnionType: empty); + throw new Error(`Unsupported union member type`); } case 'NumberTypeAnnotation': return 'NumberKind'; @@ -252,10 +255,10 @@ function translateParamTypeToJniType( return 'Ljava/lang/String;'; case 'StringLiteralTypeAnnotation': return 'Ljava/lang/String;'; - case 'StringLiteralUnionTypeAnnotation': - return 'Ljava/lang/String;'; case 'BooleanTypeAnnotation': return !isRequired ? 'Ljava/lang/Boolean;' : 'Z'; + case 'BooleanLiteralTypeAnnotation': + return !isRequired ? 'Ljava/lang/Boolean;' : 'Z'; case 'EnumDeclaration': switch (typeAnnotation.memberType) { case 'NumberTypeAnnotation': @@ -268,17 +271,19 @@ function translateParamTypeToJniType( ); } case 'UnionTypeAnnotation': - switch (typeAnnotation.memberType) { - case 'NumberTypeAnnotation': + const validUnionType = parseValidUnionType(realTypeAnnotation); + switch (validUnionType) { + case 'boolean': + return !isRequired ? 'Ljava/lang/Boolean;' : 'Z'; + case 'number': return !isRequired ? 'Ljava/lang/Double;' : 'D'; - case 'ObjectTypeAnnotation': + case 'object': return 'Lcom/facebook/react/bridge/ReadableMap;'; - case 'StringTypeAnnotation': + case 'string': return 'Ljava/lang/String;'; default: - throw new Error( - `Unsupported union prop value, found: ${realTypeAnnotation.memberType}"`, - ); + (validUnionType: empty); + throw new Error(`Unsupported union member type`); } case 'NumberTypeAnnotation': return !isRequired ? 'Ljava/lang/Double;' : 'D'; @@ -334,10 +339,10 @@ function translateReturnTypeToJniType( return 'Ljava/lang/String;'; case 'StringLiteralTypeAnnotation': return 'Ljava/lang/String;'; - case 'StringLiteralUnionTypeAnnotation': - return 'Ljava/lang/String;'; case 'BooleanTypeAnnotation': return nullable ? 'Ljava/lang/Boolean;' : 'Z'; + case 'BooleanLiteralTypeAnnotation': + return nullable ? 'Ljava/lang/Boolean;' : 'Z'; case 'EnumDeclaration': switch (typeAnnotation.memberType) { case 'NumberTypeAnnotation': @@ -350,17 +355,19 @@ function translateReturnTypeToJniType( ); } case 'UnionTypeAnnotation': - switch (typeAnnotation.memberType) { - case 'NumberTypeAnnotation': + const validUnionType = parseValidUnionType(realTypeAnnotation); + switch (validUnionType) { + case 'boolean': + return nullable ? 'Ljava/lang/Boolean;' : 'Z'; + case 'number': return nullable ? 'Ljava/lang/Double;' : 'D'; - case 'ObjectTypeAnnotation': - return 'Lcom/facebook/react/bridge/WritableMap;'; - case 'StringTypeAnnotation': + case 'object': + return 'Lcom/facebook/react/bridge/ReadableMap;'; + case 'string': return 'Ljava/lang/String;'; default: - throw new Error( - `Unsupported union member type, found: ${realTypeAnnotation.memberType}"`, - ); + (validUnionType: empty); + throw new Error(`Unsupported union member type`); } case 'NumberTypeAnnotation': return nullable ? 'Ljava/lang/Double;' : 'D'; diff --git a/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/StructCollector.js b/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/StructCollector.js index 88ef558f40e0bc..3f46ca9c5da355 100644 --- a/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/StructCollector.js +++ b/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/StructCollector.js @@ -36,7 +36,7 @@ const { unwrapNullable, wrapNullable, } = require('../../../parsers/parsers-commons'); -const {capitalize} = require('../../Utils'); +const {capitalize, parseValidUnionType} = require('../../Utils'); type StructContext = 'CONSTANTS' | 'REGULAR'; @@ -129,27 +129,29 @@ class StructCollector { case 'MixedTypeAnnotation': throw new Error('Mixed types are unsupported in structs'); case 'UnionTypeAnnotation': - switch (typeAnnotation.memberType) { - case 'StringTypeAnnotation': + const validUnionType = parseValidUnionType(typeAnnotation); + switch (validUnionType) { + case 'boolean': return wrapNullable(nullable, { - type: 'StringTypeAnnotation', + type: 'BooleanTypeAnnotation', }); - case 'NumberTypeAnnotation': + case 'number': return wrapNullable(nullable, { type: 'NumberTypeAnnotation', }); - case 'ObjectTypeAnnotation': + case 'object': // This isn't smart enough to actually know how to generate the // options on the native side. So we just treat it as an unknown object type return wrapNullable(nullable, { type: 'GenericObjectTypeAnnotation', }); + case 'string': + return wrapNullable(nullable, { + type: 'StringTypeAnnotation', + }); default: - (typeAnnotation.memberType: empty); - throw new Error( - 'Union types are unsupported in structs' + - JSON.stringify(typeAnnotation), - ); + (validUnionType: empty); + throw new Error(`Unsupported union member types`); } default: { return wrapNullable(nullable, typeAnnotation); diff --git a/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/header/serializeConstantsStruct.js b/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/header/serializeConstantsStruct.js index 9cee0665e8f396..dcc0e7fff2a4e8 100644 --- a/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/header/serializeConstantsStruct.js +++ b/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/header/serializeConstantsStruct.js @@ -19,7 +19,7 @@ const {wrapOptional: wrapCxxOptional} = require('../../../TypeUtils/Cxx'); const { wrapOptional: wrapObjCOptional, } = require('../../../TypeUtils/Objective-C'); -const {capitalize} = require('../../../Utils'); +const {capitalize, parseValidUnionType} = require('../../../Utils'); const {getNamespacedStructName, getSafePropertyName} = require('../Utils'); const StructTemplate = ({ @@ -96,8 +96,21 @@ function toObjCType( return 'NSString *'; case 'StringLiteralTypeAnnotation': return 'NSString *'; - case 'StringLiteralUnionTypeAnnotation': - return 'NSString *'; + case 'UnionTypeAnnotation': + const validUnionType = parseValidUnionType(typeAnnotation); + switch (validUnionType) { + case 'boolean': + return wrapCxxOptional('bool', isRequired); + case 'number': + return wrapCxxOptional('double', isRequired); + case 'object': + return wrapObjCOptional('id', isRequired); + case 'string': + return 'NSString *'; + default: + (validUnionType: empty); + throw new Error(`Unsupported union member type`); + } case 'NumberTypeAnnotation': return wrapCxxOptional('double', isRequired); case 'NumberLiteralTypeAnnotation': @@ -110,6 +123,8 @@ function toObjCType( return wrapCxxOptional('double', isRequired); case 'BooleanTypeAnnotation': return wrapCxxOptional('bool', isRequired); + case 'BooleanLiteralTypeAnnotation': + return wrapCxxOptional('bool', isRequired); case 'EnumDeclaration': switch (typeAnnotation.memberType) { case 'NumberTypeAnnotation': @@ -181,8 +196,21 @@ function toObjCValue( return value; case 'StringLiteralTypeAnnotation': return value; - case 'StringLiteralUnionTypeAnnotation': - return value; + case 'UnionTypeAnnotation': + const validUnionType = parseValidUnionType(typeAnnotation); + switch (validUnionType) { + case 'boolean': + return wrapPrimitive('BOOL'); + case 'number': + return wrapPrimitive('double'); + case 'object': + return value; + case 'string': + return value; + default: + (validUnionType: empty); + throw new Error(`Unsupported union member type`); + } case 'NumberTypeAnnotation': return wrapPrimitive('double'); case 'NumberLiteralTypeAnnotation': @@ -195,6 +223,8 @@ function toObjCValue( return wrapPrimitive('double'); case 'BooleanTypeAnnotation': return wrapPrimitive('BOOL'); + case 'BooleanLiteralTypeAnnotation': + return wrapPrimitive('BOOL'); case 'EnumDeclaration': switch (typeAnnotation.memberType) { case 'NumberTypeAnnotation': diff --git a/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/header/serializeRegularStruct.js b/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/header/serializeRegularStruct.js index 9fca06510ad933..f633f909437d02 100644 --- a/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/header/serializeRegularStruct.js +++ b/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/header/serializeRegularStruct.js @@ -19,7 +19,7 @@ const {wrapOptional: wrapCxxOptional} = require('../../../TypeUtils/Cxx'); const { wrapOptional: wrapObjCOptional, } = require('../../../TypeUtils/Objective-C'); -const {capitalize} = require('../../../Utils'); +const {capitalize, parseValidUnionType} = require('../../../Utils'); const {getNamespacedStructName, getSafePropertyName} = require('../Utils'); const StructTemplate = ({ @@ -87,8 +87,21 @@ function toObjCType( return 'NSString *'; case 'StringLiteralTypeAnnotation': return 'NSString *'; - case 'StringLiteralUnionTypeAnnotation': - return 'NSString *'; + case 'UnionTypeAnnotation': + const validUnionType = parseValidUnionType(typeAnnotation); + switch (validUnionType) { + case 'boolean': + return wrapCxxOptional('bool', isRequired); + case 'number': + return wrapCxxOptional('double', isRequired); + case 'object': + return wrapObjCOptional('id', isRequired); + case 'string': + return 'NSString *'; + default: + (validUnionType: empty); + throw new Error(`Unsupported union member type`); + } case 'NumberTypeAnnotation': return wrapCxxOptional('double', isRequired); case 'NumberLiteralTypeAnnotation': @@ -101,6 +114,8 @@ function toObjCType( return wrapCxxOptional('double', isRequired); case 'BooleanTypeAnnotation': return wrapCxxOptional('bool', isRequired); + case 'BooleanLiteralTypeAnnotation': + return wrapCxxOptional('bool', isRequired); case 'EnumDeclaration': switch (typeAnnotation.memberType) { case 'NumberTypeAnnotation': @@ -171,8 +186,21 @@ function toObjCValue( return RCTBridgingTo('String'); case 'StringLiteralTypeAnnotation': return RCTBridgingTo('String'); - case 'StringLiteralUnionTypeAnnotation': - return RCTBridgingTo('String'); + case 'UnionTypeAnnotation': + const validUnionType = parseValidUnionType(typeAnnotation); + switch (validUnionType) { + case 'boolean': + return RCTBridgingTo('Bool'); + case 'number': + return RCTBridgingTo('Double'); + case 'object': + return value; + case 'string': + return RCTBridgingTo('String'); + default: + (validUnionType: empty); + throw new Error(`Unsupported union member type`); + } case 'NumberTypeAnnotation': return RCTBridgingTo('Double'); case 'NumberLiteralTypeAnnotation': @@ -185,6 +213,8 @@ function toObjCValue( return RCTBridgingTo('Double'); case 'BooleanTypeAnnotation': return RCTBridgingTo('Bool'); + case 'BooleanLiteralTypeAnnotation': + return RCTBridgingTo('Bool'); case 'EnumDeclaration': switch (typeAnnotation.memberType) { case 'NumberTypeAnnotation': diff --git a/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/serializeEventEmitter.js b/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/serializeEventEmitter.js index fd1afff066fbf7..42aca1934b5816 100644 --- a/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/serializeEventEmitter.js +++ b/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/serializeEventEmitter.js @@ -10,20 +10,33 @@ import type {NativeModuleEventEmitterShape} from '../../../CodegenSchema'; -const {toPascalCase} = require('../../Utils'); +const {parseValidUnionType, toPascalCase} = require('../../Utils'); function getEventEmitterTypeObjCType( eventEmitter: NativeModuleEventEmitterShape, ): string { - const type = eventEmitter.typeAnnotation.typeAnnotation.type; + const typeAnnotation = eventEmitter.typeAnnotation.typeAnnotation; - switch (type) { + switch (typeAnnotation.type) { case 'StringTypeAnnotation': return 'NSString *_Nonnull'; case 'StringLiteralTypeAnnotation': return 'NSString *_Nonnull'; - case 'StringLiteralUnionTypeAnnotation': - return 'NSString *_Nonnull'; + case 'UnionTypeAnnotation': + const validUnionType = parseValidUnionType(typeAnnotation); + switch (validUnionType) { + case 'boolean': + return 'BOOL'; + case 'number': + return 'NSNumber *_Nonnull'; + case 'object': + return 'NSDictionary *'; + case 'string': + return 'NSString *_Nonnull'; + default: + (validUnionType: empty); + throw new Error(`Unsupported union member type`); + } case 'NumberTypeAnnotation': case 'NumberLiteralTypeAnnotation': return 'NSNumber *_Nonnull'; @@ -44,7 +57,7 @@ function getEventEmitterTypeObjCType( `Unsupported eventType for ${eventEmitter.name}. Found: ${eventEmitter.typeAnnotation.typeAnnotation.type}`, ); default: - (type: empty); + (typeAnnotation.type: empty); throw new Error( `Unsupported eventType for ${eventEmitter.name}. Found: ${eventEmitter.typeAnnotation.typeAnnotation.type}`, ); diff --git a/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/serializeMethod.js b/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/serializeMethod.js index 8e0a56472ff8b3..8a9c76f76f3eb8 100644 --- a/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/serializeMethod.js +++ b/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/serializeMethod.js @@ -25,7 +25,7 @@ const { wrapNullable, } = require('../../../parsers/parsers-commons'); const {wrapOptional} = require('../../TypeUtils/Objective-C'); -const {capitalize} = require('../../Utils'); +const {capitalize, parseValidUnionType} = require('../../Utils'); const {getNamespacedStructName} = require('./Utils'); const invariant = require('invariant'); @@ -259,8 +259,21 @@ function getParamObjCType( return notStruct(wrapOptional('NSString *', !nullable)); case 'StringLiteralTypeAnnotation': return notStruct(wrapOptional('NSString *', !nullable)); - case 'StringLiteralUnionTypeAnnotation': - return notStruct(wrapOptional('NSString *', !nullable)); + case 'UnionTypeAnnotation': + const validUnionType = parseValidUnionType(structTypeAnnotation); + switch (validUnionType) { + case 'boolean': + return notStruct(isRequired ? 'BOOL' : 'NSNumber *'); + case 'number': + return notStruct(isRequired ? 'double' : 'NSNumber *'); + case 'object': + return notStruct(wrapOptional('NSDictionary *', !nullable)); + case 'string': + return notStruct(wrapOptional('NSString *', !nullable)); + default: + (validUnionType: empty); + throw new Error(`Unsupported union member type`); + } case 'NumberTypeAnnotation': return notStruct(isRequired ? 'double' : 'NSNumber *'); case 'NumberLiteralTypeAnnotation': @@ -273,6 +286,8 @@ function getParamObjCType( return notStruct(isRequired ? 'NSInteger' : 'NSNumber *'); case 'BooleanTypeAnnotation': return notStruct(isRequired ? 'BOOL' : 'NSNumber *'); + case 'BooleanLiteralTypeAnnotation': + return notStruct(isRequired ? 'BOOL' : 'NSNumber *'); case 'EnumDeclaration': switch (typeAnnotation.memberType) { case 'NumberTypeAnnotation': @@ -340,10 +355,6 @@ function getReturnObjCType( // TODO: Can NSString * returns not be _Nullable? // In the legacy codegen, we don't surround NSSTring * with _Nullable return wrapOptional('NSString *', isRequired); - case 'StringLiteralUnionTypeAnnotation': - // TODO: Can NSString * returns not be _Nullable? - // In the legacy codegen, we don't surround NSSTring * with _Nullable - return wrapOptional('NSString *', isRequired); case 'NumberTypeAnnotation': return wrapOptional('NSNumber *', isRequired); case 'NumberLiteralTypeAnnotation': @@ -356,6 +367,8 @@ function getReturnObjCType( return wrapOptional('NSNumber *', isRequired); case 'BooleanTypeAnnotation': return wrapOptional('NSNumber *', isRequired); + case 'BooleanLiteralTypeAnnotation': + return wrapOptional('NSNumber *', isRequired); case 'EnumDeclaration': switch (typeAnnotation.memberType) { case 'NumberTypeAnnotation': @@ -368,19 +381,21 @@ function getReturnObjCType( ); } case 'UnionTypeAnnotation': - switch (typeAnnotation.memberType) { - case 'NumberTypeAnnotation': + const validUnionType = parseValidUnionType(typeAnnotation); + switch (validUnionType) { + case 'boolean': return wrapOptional('NSNumber *', isRequired); - case 'ObjectTypeAnnotation': + case 'number': + return wrapOptional('NSNumber *', isRequired); + case 'object': return wrapOptional('NSDictionary *', isRequired); - case 'StringTypeAnnotation': + case 'string': // TODO: Can NSString * returns not be _Nullable? // In the legacy codegen, we don't surround NSSTring * with _Nullable return wrapOptional('NSString *', isRequired); default: - throw new Error( - `Unsupported union return type for ${methodName}, found: ${typeAnnotation.memberType}"`, - ); + (validUnionType: empty); + throw new Error(`Unsupported union member type`); } case 'GenericObjectTypeAnnotation': return wrapOptional('NSDictionary *', isRequired); @@ -414,8 +429,6 @@ function getReturnJSType( return 'StringKind'; case 'StringLiteralTypeAnnotation': return 'StringKind'; - case 'StringLiteralUnionTypeAnnotation': - return 'StringKind'; case 'NumberTypeAnnotation': return 'NumberKind'; case 'NumberLiteralTypeAnnotation': @@ -428,6 +441,8 @@ function getReturnJSType( return 'NumberKind'; case 'BooleanTypeAnnotation': return 'BooleanKind'; + case 'BooleanLiteralTypeAnnotation': + return 'BooleanKind'; case 'GenericObjectTypeAnnotation': return 'ObjectKind'; case 'EnumDeclaration': @@ -442,17 +457,19 @@ function getReturnJSType( ); } case 'UnionTypeAnnotation': - switch (typeAnnotation.memberType) { - case 'NumberTypeAnnotation': + const validUnionType = parseValidUnionType(typeAnnotation); + switch (validUnionType) { + case 'boolean': + return 'BooleanKind'; + case 'number': return 'NumberKind'; - case 'ObjectTypeAnnotation': + case 'object': return 'ObjectKind'; - case 'StringTypeAnnotation': + case 'string': return 'StringKind'; default: - throw new Error( - `Unsupported return type for ${methodName}. Found: ${typeAnnotation.type}`, - ); + (validUnionType: empty); + throw new Error(`Unsupported union member types`); } default: (typeAnnotation.type: 'MixedTypeAnnotation'); From e3c7b99ee28629736ed1ad92976f211aad5cfbb6 Mon Sep 17 00:00:00 2001 From: Arushi Kesarwani Date: Wed, 19 Nov 2025 00:25:11 -0800 Subject: [PATCH 17/17] Generator Components handing for Unions Summary: Modifying the generators/components to handle Unions. Did not use the Utils function parseValidUnionType in CppHelpers.js since it needs to handle StringLiteralTypeAnnotation & StringTypeAnnotation differently as was done before. NOTE:Generators behavior still remain unchanged hence don't allow unions of different types. Only RN Compat Checker consumes this new change of Union support of different types Differential Revision: D87410890 --- .../src/generators/components/CppHelpers.js | 61 ++++++++++++++++++- .../components/GenerateEventEmitterCpp.js | 4 +- .../components/GenerateEventEmitterH.js | 6 +- 3 files changed, 65 insertions(+), 6 deletions(-) diff --git a/packages/react-native-codegen/src/generators/components/CppHelpers.js b/packages/react-native-codegen/src/generators/components/CppHelpers.js index fa3d56629fec56..e4a1f5bdcc37be 100644 --- a/packages/react-native-codegen/src/generators/components/CppHelpers.js +++ b/packages/react-native-codegen/src/generators/components/CppHelpers.js @@ -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}`; } @@ -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): 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( diff --git a/packages/react-native-codegen/src/generators/components/GenerateEventEmitterCpp.js b/packages/react-native-codegen/src/generators/components/GenerateEventEmitterCpp.js index 6d9b72cd2909ae..a890b238c675aa 100644 --- a/packages/react-native-codegen/src/generators/components/GenerateEventEmitterCpp.js +++ b/packages/react-native-codegen/src/generators/components/GenerateEventEmitterCpp.js @@ -207,7 +207,7 @@ function handleArrayElementType( loopLocalVariable, val => `jsi::valueFromDynamic(runtime, ${val})`, ); - case 'StringLiteralUnionTypeAnnotation': + case 'UnionTypeAnnotation': return setValueAtIndex( propertyName, indexVariable, @@ -320,7 +320,7 @@ function generateSetters( usingEvent, prop => `jsi::valueFromDynamic(runtime, ${prop})`, ); - case 'StringLiteralUnionTypeAnnotation': + case 'UnionTypeAnnotation': return generateSetter( parentPropertyName, eventProperty.name, diff --git a/packages/react-native-codegen/src/generators/components/GenerateEventEmitterH.js b/packages/react-native-codegen/src/generators/components/GenerateEventEmitterH.js index 0c3468dbc61c81..0546b13f6a8f52 100644 --- a/packages/react-native-codegen/src/generators/components/GenerateEventEmitterH.js +++ b/packages/react-native-codegen/src/generators/components/GenerateEventEmitterH.js @@ -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': @@ -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), @@ -251,7 +251,7 @@ function generateStruct( nullthrows(typeAnnotation.properties), ); return; - case 'StringLiteralUnionTypeAnnotation': + case 'UnionTypeAnnotation': generateEnum( structs, typeAnnotation.types.map(literal => literal.value),