diff --git a/packages/react-native-codegen/src/CodegenSchema.d.ts b/packages/react-native-codegen/src/CodegenSchema.d.ts index 2d28bbfe7e271c..3c1ba4b9f4bb1d 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'; } @@ -42,6 +46,21 @@ 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 { readonly type: 'ObjectTypeAnnotation'; readonly properties: readonly NamedShape[]; @@ -49,6 +68,18 @@ export interface ObjectTypeAnnotation { readonly baseTypes?: readonly string[] | undefined; } +export interface UnionTypeAnnotation { + 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'; } @@ -304,10 +335,14 @@ export interface NativeModuleStringLiteralTypeAnnotation { readonly value: string; } -export interface StringLiteralUnionTypeAnnotation { - readonly type: 'StringLiteralUnionTypeAnnotation'; - readonly types: NativeModuleStringLiteralTypeAnnotation[]; -} +export type StringLiteralUnionTypeAnnotation = + UnionTypeAnnotation; + +export type NumberLiteralUnionTypeAnnotation = + UnionTypeAnnotation; + +export type BooleanLiteralUnionTypeAnnotation = + UnionTypeAnnotation; export interface NativeModuleNumberTypeAnnotation { readonly type: 'NumberTypeAnnotation'; @@ -369,15 +404,17 @@ export interface NativeModulePromiseTypeAnnotation { readonly elementType: Nullable | 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; 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 99299dafc3c043..d94e410ee5f681 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', }>; @@ -52,11 +56,20 @@ export type StringLiteralTypeAnnotation = $ReadOnly<{ value: string, }>; -export type StringLiteralUnionTypeAnnotation = $ReadOnly<{ - type: 'StringLiteralUnionTypeAnnotation', - types: $ReadOnlyArray, +export type BooleanLiteralTypeAnnotation = $ReadOnly<{ + type: 'BooleanLiteralTypeAnnotation', + value: boolean, }>; +export type StringLiteralUnionTypeAnnotation = + UnionTypeAnnotation; + +export type NumberLiteralUnionTypeAnnotation = + UnionTypeAnnotation; + +export type BooleanLiteralUnionTypeAnnotation = + UnionTypeAnnotation; + export type VoidTypeAnnotation = $ReadOnly<{ type: 'VoidTypeAnnotation', }>; @@ -68,6 +81,18 @@ export type ObjectTypeAnnotation<+T> = $ReadOnly<{ baseTypes?: $ReadOnlyArray, }>; +export type UnionTypeAnnotation<+T> = $ReadOnly<{ + type: 'UnionTypeAnnotation', + 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', }>; @@ -358,15 +383,17 @@ export type NativeModulePromiseTypeAnnotation = $ReadOnly<{ elementType: VoidTypeAnnotation | Nullable, }>; -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; export type NativeModuleMixedTypeAnnotation = $ReadOnly<{ type: 'MixedTypeAnnotation', @@ -396,6 +423,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 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'); 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), 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');