From bbb2fb212d112b9b96b9b47df5bc22074f24f7da Mon Sep 17 00:00:00 2001 From: Riccardo Cipolleschi Date: Mon, 26 Sep 2022 07:33:07 -0700 Subject: [PATCH] Parse custom NativeState in TypeScript (#34786) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/34786 This diff is the TS equivalent of D39686251. It introduces the possibility to parse a custom Native State in Typescript. The parsing follows the exact same rules as props, as initial heuristic. This should allow enough customization for the developers who needs a custom state. Currently, we only support using `interface` for the state and the interface must contain the `NativeState` string in its name. This diff introduces also tests for the TypeScript parser and it aligns the tests between Flow and TS. ## Changelog [General][Added] - Implement custom Native State parsing in TypeScript Reviewed By: cortinico Differential Revision: D39811476 fbshipit-source-id: 1e1b86b50b9632c13157ff6c8115f5ebcbada643 --- .../__tests__/checkComponentSnaps-test.js | 15 +- .../components/__test_fixtures__/failures.js | 315 ++ .../components/__test_fixtures__/fixtures.js | 534 ++- .../typescript-component-parser-test.js.snap | 4249 +++++++++++++---- .../typescript/components/componentsUtils.js | 693 +++ .../parsers/typescript/components/index.js | 45 +- .../parsers/typescript/components/props.js | 650 +-- .../parsers/typescript/components/schema.js | 4 + .../parsers/typescript/components/states.js | 58 + 9 files changed, 5082 insertions(+), 1481 deletions(-) create mode 100644 packages/react-native-codegen/src/parsers/typescript/components/componentsUtils.js create mode 100644 packages/react-native-codegen/src/parsers/typescript/components/states.js diff --git a/packages/react-native-codegen/src/parsers/consistency/__tests__/checkComponentSnaps-test.js b/packages/react-native-codegen/src/parsers/consistency/__tests__/checkComponentSnaps-test.js index bb54ecb30c4aa6..0e3efb671d607d 100644 --- a/packages/react-native-codegen/src/parsers/consistency/__tests__/checkComponentSnaps-test.js +++ b/packages/react-native-codegen/src/parsers/consistency/__tests__/checkComponentSnaps-test.js @@ -14,20 +14,11 @@ const {compareSnaps, compareTsArraySnaps} = require('../compareSnaps.js'); const flowFixtures = require('../../flow/components/__test_fixtures__/fixtures.js'); const flowSnaps = require('../../../../src/parsers/flow/components/__tests__/__snapshots__/component-parser-test.js.snap'); -const flowExtraCases = [ - //TODO: remove these once we implement TypeScript parser for Custom State - 'ALL_STATE_TYPES', - 'ARRAY_STATE_TYPES', - 'COMMANDS_EVENTS_STATE_TYPES_EXPORTED', - 'OBJECT_STATE_TYPES', -]; +const flowExtraCases = []; const tsFixtures = require('../../typescript/components/__test_fixtures__/fixtures.js'); const tsSnaps = require('../../../../src/parsers/typescript/components/__tests__/__snapshots__/typescript-component-parser-test.js.snap'); -const tsExtraCases = ['ARRAY2_PROP_TYPES_NO_EVENTS'].concat([ - //TODO: remove these once we implement TypeScript parser for Custom State - 'COMMANDS_AND_EVENTS_TYPES_EXPORTED', -]); -const ignoredCases = ['ARRAY_PROP_TYPES_NO_EVENTS']; +const tsExtraCases = ['ARRAY2_PROP_TYPES_NO_EVENTS', 'ARRAY2_STATE_TYPES']; +const ignoredCases = ['ARRAY_PROP_TYPES_NO_EVENTS', 'ARRAY_STATE_TYPES']; compareSnaps( flowFixtures, diff --git a/packages/react-native-codegen/src/parsers/typescript/components/__test_fixtures__/failures.js b/packages/react-native-codegen/src/parsers/typescript/components/__test_fixtures__/failures.js index eefd9e316f18e5..130ec051317aa8 100644 --- a/packages/react-native-codegen/src/parsers/typescript/components/__test_fixtures__/failures.js +++ b/packages/react-native-codegen/src/parsers/typescript/components/__test_fixtures__/failures.js @@ -485,6 +485,310 @@ export default codegenNativeComponent( ) as HostComponent; `; +// === STATE === +const NULLABLE_STATE_WITH_DEFAULT = ` +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + */ + +const codegenNativeComponent = require('codegenNativeComponent'); + +import type {WithDefault, Float} from 'CodegenTypes'; +import type {ViewProps} from 'ViewPropTypes'; +import type {HostComponent} from 'react-native'; + +export interface ModuleProps extends ViewProps { } + +interface ModuleNativeState { + nullable_with_default: WithDefault | null | undefined; +} + +export default codegenNativeComponent( + 'Module', +) as HostComponent; +`; + +const NON_OPTIONAL_KEY_STATE_WITH_DEFAULT_VALUE = ` +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + */ + +const codegenNativeComponent = require('codegenNativeComponent'); + +import type {WithDefault, Float} from 'CodegenTypes'; +import type {ViewProps} from 'ViewPropTypes'; +import type {HostComponent} from 'react-native'; + +export interface ModuleProps extends ViewProps {} + +export interface ModuleNativeState { + required_key_with_default: WithDefault; +} + +export default codegenNativeComponent( + 'Module', +) as HostComponent; +`; + +const STATE_CONFLICT_NAMES = ` +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + */ + +const codegenNativeComponent = require('codegenNativeComponent'); + +import type {ViewProps} from 'ViewPropTypes'; +import type {HostComponent} from 'react-native'; + +export interface ModuleProps extends ViewProps { } + +interface ModuleNativeState { + isEnabled: string, + + isEnabled: boolean, +} + +export default codegenNativeComponent( + 'Module', +) as HostComponent; +`; + +const STATE_CONFLICT_WITH_SPREAD_PROPS = ` +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + */ + +const codegenNativeComponent = require('codegenNativeComponent'); + +import type {ViewProps} from 'ViewPropTypes'; +import type {HostComponent} from 'react-native'; + +export interface ModuleProps extends ViewProps { } + +type PropsInFile = Readonly<{ + isEnabled: boolean, +}>; + +export interface ModuleNativeState extends PropsInFile { + isEnabled: boolean, +} + +export default codegenNativeComponent( + 'Module', +) as HostComponent; +`; + +const STATE_NUMBER_TYPE = ` +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + */ + +const codegenNativeComponent = require('codegenNativeComponent'); + +import type {ViewProps} from 'ViewPropTypes'; +import type {HostComponent} from 'react-native'; + +export interface ModuleProps extends ViewProps { } + +interface ModuleNativeState { + someProp: number +} + +export default codegenNativeComponent( + 'Module', +) as HostComponent; +`; + +const STATE_MIXED_ENUM = ` +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + */ + +const codegenNativeComponent = require('codegenNativeComponent'); + +import type {ViewProps} from 'ViewPropTypes'; +import type {HostComponent} from 'react-native'; +import type {WithDefault} from 'CodegenTypes'; + +export interface ModuleProps extends ViewProps { } + +export interface ModuleNativeState { + someProp?: WithDefault<'foo' | 1, 1>; +} + +export default codegenNativeComponent( + 'Module', +) as HostComponent; +`; + +const STATE_ENUM_BOOLEAN = ` +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + */ + +const codegenNativeComponent = require('codegenNativeComponent'); + +import type {ViewProps} from 'ViewPropTypes'; +import type {HostComponent} from 'react-native'; +import type {WithDefault} from 'CodegenTypes'; + +export interface ModuleProps extends ViewProps { } + +interface ModuleNativeState { + someProp?: WithDefault +} + +export default codegenNativeComponent( + 'Module', +) as HostComponent; +`; + +const STATE_ARRAY_MIXED_ENUM = ` +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + */ + +const codegenNativeComponent = require('codegenNativeComponent'); + +import type {ViewProps} from 'ViewPropTypes'; +import type {HostComponent} from 'react-native'; +import type {WithDefault} from 'CodegenTypes'; + +export interface ModuleProps extends ViewProps { } + +export interface ModuleNativeState { + someProp?: WithDefault, 1>; +} + +export default codegenNativeComponent( + 'Module', +) as HostComponent; +`; + +const STATE_ARRAY_ENUM_BOOLEAN = ` +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + */ + +const codegenNativeComponent = require('codegenNativeComponent'); + +import type {ViewProps} from 'ViewPropTypes'; +import type {HostComponent} from 'react-native'; +import type {WithDefault} from 'CodegenTypes'; + +export interface ModuleProps extends ViewProps { } + +interface ModuleNativeState { + someProp?: WithDefault, false>; +} + +export default codegenNativeComponent( + 'Module', +) as HostComponent; +`; + +const STATE_ARRAY_ENUM_INT = ` +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + */ + +const codegenNativeComponent = require('codegenNativeComponent'); + +import type {ViewProps} from 'ViewPropTypes'; +import type {HostComponent} from 'react-native'; +import type {WithDefault} from 'CodegenTypes'; + +export interface ModuleProps extends ViewProps { } + +export interface ModuleNativeState { + someProp?: WithDefault, 0>; +} + +export default codegenNativeComponent( + 'Module', +) as HostComponent; +`; + +const DOUBLE_STATE_IN_FILE = ` +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + */ + +const codegenNativeComponent = require('codegenNativeComponent'); + +import type {ViewProps} from 'ViewPropTypes'; +import type {HostComponent} from 'react-native'; + +export interface ModuleProps extends ViewProps { } + +interface SecondNativeState { + someProp: boolean +} + +export interface ModuleNativeState { + someOtherProp: boolean +} + +export default codegenNativeComponent( + 'Module', +) as HostComponent; +`; + module.exports = { COMMANDS_DEFINED_INLINE, COMMANDS_DEFINED_MULTIPLE_TIMES, @@ -502,4 +806,15 @@ module.exports = { PROP_ARRAY_MIXED_ENUM, PROP_ARRAY_ENUM_BOOLEAN, PROP_ARRAY_ENUM_INT, + NULLABLE_STATE_WITH_DEFAULT, + NON_OPTIONAL_KEY_STATE_WITH_DEFAULT_VALUE, + STATE_CONFLICT_NAMES, + STATE_CONFLICT_WITH_SPREAD_PROPS, + STATE_NUMBER_TYPE, + STATE_MIXED_ENUM, + STATE_ENUM_BOOLEAN, + STATE_ARRAY_MIXED_ENUM, + STATE_ARRAY_ENUM_BOOLEAN, + STATE_ARRAY_ENUM_INT, + DOUBLE_STATE_IN_FILE, }; diff --git a/packages/react-native-codegen/src/parsers/typescript/components/__test_fixtures__/fixtures.js b/packages/react-native-codegen/src/parsers/typescript/components/__test_fixtures__/fixtures.js index 6320d158efed7d..f3b0df5c46ae1b 100644 --- a/packages/react-native-codegen/src/parsers/typescript/components/__test_fixtures__/fixtures.js +++ b/packages/react-native-codegen/src/parsers/typescript/components/__test_fixtures__/fixtures.js @@ -1034,7 +1034,7 @@ export default codegenNativeComponent('Module') as NativeType; `; -const COMMANDS_AND_EVENTS_TYPES_EXPORTED = ` +const COMMANDS_EVENTS_STATE_TYPES_EXPORTED = ` /** * Copyright (c) Meta Platforms, Inc. and affiliates. * @@ -1071,6 +1071,13 @@ export interface ModuleProps extends ViewProps { onDirectEventDefinedInlineWithPaperName: DirectEventHandler, } +// Add state here +export interface ModuleNativeState { + boolean_required: boolean, + boolean_optional_key?: WithDefault, + boolean_optional_both?: WithDefault, +} + type NativeType = HostComponent; export type ScrollTo = (viewRef: React.ElementRef, y: Int, animated: Boolean) => Void; @@ -1088,6 +1095,525 @@ export default codegenNativeComponent( ) as NativeType; `; +// === STATE === +const ALL_STATE_TYPES = ` +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + */ + +'use strict'; + +const codegenNativeComponent = require('codegenNativeComponent'); + +import type {Int32, Double, Float, WithDefault} from 'CodegenTypes'; +import type {ImageSource} from 'ImageSource'; +import type { + ColorValue, + ColorArrayValue, + PointValue, + EdgeInsetsValue, +} from 'StyleSheetTypes'; +import type {ViewProps} from 'ViewPropTypes'; +import type {HostComponent} from 'react-native'; + +export interface ModuleProps extends ViewProps { } + +export interface ModuleNativeState { + // Props + // Boolean props + boolean_required: boolean; + boolean_optional_key?: WithDefault; + boolean_optional_both?: WithDefault; + + // Boolean props, null default + boolean_null_optional_key?: WithDefault; + boolean_null_optional_both?: WithDefault; + + // String props + string_required: string; + string_optional_key?: WithDefault; + string_optional_both?: WithDefault; + + // String props, null default + string_null_optional_key?: WithDefault; + string_null_optional_both?: WithDefault; + + // Stringish props + stringish_required: Stringish; + stringish_optional_key?: WithDefault; + stringish_optional_both?: WithDefault; + + // Stringish props, null default + stringish_null_optional_key?: WithDefault; + stringish_null_optional_both?: WithDefault; + + // Double props + double_required: Double; + double_optional_key?: WithDefault; + double_optional_both?: WithDefault; + + // Float props + float_required: Float; + float_optional_key?: WithDefault; + float_optional_both?: WithDefault; + + // Float props, null default + float_null_optional_key?: WithDefault; + float_null_optional_both?: WithDefault; + + // Int32 props + int32_required: Int32; + int32_optional_key?: WithDefault; + int32_optional_both?: WithDefault; + + // String enum props + enum_optional_key?: WithDefault<'small' | 'large', 'small'>; + enum_optional_both?: WithDefault<'small' | 'large', 'small'>; + + // Int enum props + int_enum_optional_key?: WithDefault<0 | 1, 0>; + + // Object props + object_optional_key?: Readonly<{prop: string}>; + object_optional_both?: Readonly<{prop: string} | null | undefined>; + object_optional_value: Readonly<{prop: string} | null | undefined>; + + // ImageSource props + image_required: ImageSource; + image_optional_value: ImageSource | null | undefined; + image_optional_both?: ImageSource | null | undefined; + + // ColorValue props + color_required: ColorValue; + color_optional_key?: ColorValue; + color_optional_value: ColorValue | null | undefined; + color_optional_both?: ColorValue | null | undefined; + + // ColorArrayValue props + color_array_required: ColorArrayValue; + color_array_optional_key?: ColorArrayValue; + color_array_optional_value: ColorArrayValue | null | undefined; + color_array_optional_both?: ColorArrayValue | null | undefined; + + // ProcessedColorValue props + processed_color_required: ProcessedColorValue; + processed_color_optional_key?: ProcessedColorValue; + processed_color_optional_value: ProcessedColorValue | null | undefined; + processed_color_optional_both?: ProcessedColorValue | null | undefined; + + // PointValue props + point_required: PointValue; + point_optional_key?: PointValue; + point_optional_value: PointValue | null | undefined; + point_optional_both?: PointValue | null | undefined; + + // EdgeInsets props + insets_required: EdgeInsetsValue; + insets_optional_key?: EdgeInsetsValue; + insets_optional_value: EdgeInsetsValue | null | undefined; + insets_optional_both?: EdgeInsetsValue | null | undefined; +} + +export default codegenNativeComponent( + 'Module', +) as HostComponent; +`; + +const ARRAY_STATE_TYPES = ` +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + */ + +'use strict'; + +const codegenNativeComponent = require('codegenNativeComponent'); + +import type {Int32, Double, Float, WithDefault} from 'CodegenTypes'; +import type {ImageSource} from 'ImageSource'; +import type { + ColorValue, + ColorArrayValue, + PointValue, + EdgeInsetsValue, +} from 'StyleSheetTypes'; +import type {ViewProps} from 'ViewPropTypes'; +import type {HostComponent} from 'react-native'; + +type ObjectType = Readonly<{prop: string}>; +type ArrayObjectType = ReadonlyArray>; + +export interface ModuleProps extends ViewProps {} + +interface ModuleNativeState { + // Props + // Boolean props + array_boolean_required: ReadonlyArray; + array_boolean_optional_key?: ReadonlyArray; + array_boolean_optional_value: ReadonlyArray | null | undefined; + array_boolean_optional_both?: ReadonlyArray | null | undefined; + + // String props + array_string_required: ReadonlyArray; + array_string_optional_key?: ReadonlyArray; + array_string_optional_value: ReadonlyArray | null | undefined; + array_string_optional_both?: ReadonlyArray | null | undefined; + + // Double props + array_double_required: ReadonlyArray; + array_double_optional_key?: ReadonlyArray; + array_double_optional_value: ReadonlyArray | null | undefined; + array_double_optional_both?: ReadonlyArray | null | undefined; + + // Float props + array_float_required: ReadonlyArray; + array_float_optional_key?: ReadonlyArray; + array_float_optional_value: ReadonlyArray | null | undefined; + array_float_optional_both?: ReadonlyArray | null | undefined; + + // Int32 props + array_int32_required: ReadonlyArray; + array_int32_optional_key?: ReadonlyArray; + array_int32_optional_value: ReadonlyArray | null | undefined; + array_int32_optional_both?: ReadonlyArray | null | undefined; + + // String enum props + array_enum_optional_key?: WithDefault< + ReadonlyArray<'small' | 'large'>, + 'small' + >; + array_enum_optional_both?: WithDefault< + ReadonlyArray<'small' | 'large'>, + 'small' + >; + + // ImageSource props + array_image_required: ReadonlyArray; + array_image_optional_key?: ReadonlyArray; + array_image_optional_value: ReadonlyArray | null | undefined; + array_image_optional_both?: ReadonlyArray | null | undefined; + + // ColorValue props + array_color_required: ReadonlyArray; + array_color_optional_key?: ReadonlyArray; + array_color_optional_value: ReadonlyArray | null | undefined; + array_color_optional_both?: ReadonlyArray | null | undefined; + + // PointValue props + array_point_required: ReadonlyArray; + array_point_optional_key?: ReadonlyArray; + array_point_optional_value: ReadonlyArray | null | undefined; + array_point_optional_both?: ReadonlyArray | null | undefined; + + // EdgeInsetsValue props + array_insets_required: ReadonlyArray; + array_insets_optional_key?: ReadonlyArray; + array_insets_optional_value: ReadonlyArray | null | undefined; + array_insets_optional_both?: ReadonlyArray | null | undefined; + + // Object props + array_object_required: ReadonlyArray>; + array_object_optional_key?: ReadonlyArray>; + array_object_optional_value: ArrayObjectType | null | undefined; + array_object_optional_both?: ReadonlyArray | null | undefined; + + // Nested array object types + array_of_array_object_required: ReadonlyArray< + Readonly<{ + // This needs to be the same name as the top level array above + array_object_required: ReadonlyArray>; + }> + >; + array_of_array_object_optional_key?: ReadonlyArray< + Readonly<{ + // This needs to be the same name as the top level array above + array_object_optional_key: ReadonlyArray>; + }> + >; + array_of_array_object_optional_value: ReadonlyArray< + Readonly<{ + // This needs to be the same name as the top level array above + array_object_optional_value: ReadonlyArray< + Readonly<{prop: string | null | undefined}> + >; + }> + > | null | undefined; + array_of_array_object_optional_both?: ReadonlyArray< + Readonly<{ + // This needs to be the same name as the top level array above + array_object_optional_both: ReadonlyArray< + Readonly<{prop?: string | null | undefined}> + >; + }> + > | null | undefined; + + // Nested array of array of object types + array_of_array_of_object_required: ReadonlyArray< + ReadonlyArray< + Readonly<{ + prop: string; + }> + > + >; + + // Nested array of array of object types (in file) + array_of_array_of_object_required_in_file: ReadonlyArray< + ReadonlyArray + >; +} + +export default codegenNativeComponent( + 'Module', +) as HostComponent; +`; + +const ARRAY2_STATE_TYPES = ` +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + */ + +'use strict'; + +const codegenNativeComponent = require('codegenNativeComponent'); + +import type {Int32, Double, Float, WithDefault} from 'CodegenTypes'; +import type {ImageSource} from 'ImageSource'; +import type { + ColorValue, + ColorArrayValue, + PointValue, + EdgeInsetsValue, +} from 'StyleSheetTypes'; +import type {ViewProps} from 'ViewPropTypes'; +import type {HostComponent} from 'react-native'; + +type ObjectType = Readonly<{prop: string}>; +type ArrayObjectType = readonly Readonly<{prop: string}>[]; + +export interface ModuleProps extends ViewProps {} + +export interface ModuleNativeState{ + // Props + // Boolean props + array_boolean_required: readonly boolean[]; + array_boolean_optional_key?: readonly boolean[]; + array_boolean_optional_value: readonly boolean[] | null | undefined; + array_boolean_optional_both?: readonly boolean[] | null | undefined; + + // String props + array_string_required: readonly string[]; + array_string_optional_key?: readonly string[]; + array_string_optional_value: readonly string[] | null | undefined; + array_string_optional_both?: readonly string[] | null | undefined; + + // Double props + array_double_required: readonly Double[]; + array_double_optional_key?: readonly Double[]; + array_double_optional_value: readonly Double[] | null | undefined; + array_double_optional_both?: readonly Double[] | null | undefined; + + // Float props + array_float_required: readonly Float[]; + array_float_optional_key?: readonly Float[]; + array_float_optional_value: readonly Float[] | null | undefined; + array_float_optional_both?: readonly Float[] | null | undefined; + + // Int32 props + array_int32_required: readonly Int32[]; + array_int32_optional_key?: readonly Int32[]; + array_int32_optional_value: readonly Int32[] | null | undefined; + array_int32_optional_both?: readonly Int32[] | null | undefined; + + // String enum props + array_enum_optional_key?: WithDefault< + readonly ('small' | 'large')[], + 'small' + >; + array_enum_optional_both?: WithDefault< + readonly ('small' | 'large')[], + 'small' + >; + + // ImageSource props + array_image_required: readonly ImageSource[]; + array_image_optional_key?: readonly ImageSource[]; + array_image_optional_value: readonly ImageSource[] | null | undefined; + array_image_optional_both?: readonly ImageSource[] | null | undefined; + + // ColorValue props + array_color_required: readonly ColorValue[]; + array_color_optional_key?: readonly ColorValue[]; + array_color_optional_value: readonly ColorValue[] | null | undefined; + array_color_optional_both?: readonly ColorValue[] | null | undefined; + + // PointValue props + array_point_required: readonly PointValue[]; + array_point_optional_key?: readonly PointValue[]; + array_point_optional_value: readonly PointValue[] | null | undefined; + array_point_optional_both?: readonly PointValue[] | null | undefined; + + // EdgeInsetsValue props + array_insets_required: readonly EdgeInsetsValue[]; + array_insets_optional_key?: readonly EdgeInsetsValue[]; + array_insets_optional_value: readonly EdgeInsetsValue[] | null | undefined; + array_insets_optional_both?: readonly EdgeInsetsValue[] | null | undefined; + + // Object props + array_object_required: readonly Readonly<{prop: string}>[]; + array_object_optional_key?: readonly Readonly<{prop: string}>[]; + array_object_optional_value: ArrayObjectType | null | undefined; + array_object_optional_both?: readonly ObjectType[] | null | undefined; + + // Nested array object types + array_of_array_object_required: readonly Readonly<{ + // This needs to be the same name as the top level array above + array_object_required: readonly Readonly<{prop: string}>[]; + }>[]; + array_of_array_object_optional_key?: readonly Readonly<{ + // This needs to be the same name as the top level array above + array_object_optional_key: readonly Readonly<{prop?: string}>[]; + }>[]; + array_of_array_object_optional_value: readonly Readonly<{ + // This needs to be the same name as the top level array above + array_object_optional_value: readonly Readonly<{prop: string | null | undefined}>[]; + }>[] | null | undefined; + array_of_array_object_optional_both?: readonly Readonly<{ + // This needs to be the same name as the top level array above + array_object_optional_both: readonly Readonly<{prop?: string | null | undefined}>[]; + }>[] | null | undefined; + + // Nested array of array of object types + array_of_array_of_object_required: readonly Readonly<{ + prop: string; + }>[][]; + + // Nested array of array of object types (in file) + array_of_array_of_object_required_in_file: readonly ObjectType[][]; +} + +export default codegenNativeComponent( + 'Module', +) as HostComponent; +`; + +const OBJECT_STATE_TYPES = ` +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + */ + +'use strict'; + +const codegenNativeComponent = require('codegenNativeComponent'); + +import type {Int32, Double, Float, WithDefault} from 'CodegenTypes'; +import type {ImageSource} from 'ImageSource'; +import type { + ColorValue, + ColorArrayValue, + PointValue, + EdgeInsetsValue, +} from 'StyleSheetTypes'; +import type {ViewProps} from 'ViewPropTypes'; +import type {HostComponent} from 'react-native'; + +export interface ModuleProps extends ViewProps {} + +interface ModuleNativeState { + // Props + // Boolean props + boolean_required: Readonly<{prop: boolean}>; + boolean_optional: Readonly<{prop?: WithDefault}>; + + // String props + string_required: Readonly<{prop: string}>; + string_optional: Readonly<{prop?: WithDefault}>; + + // Double props + double_required: Readonly<{prop: Double}>; + double_optional: Readonly<{prop?: WithDefault}>; + + // Float props + float_required: Readonly<{prop: Float}>; + float_optional: Readonly<{prop?: WithDefault}>; + + // Int32 props + int_required: Readonly<{prop: Int32}>; + int_optional: Readonly<{prop?: WithDefault}>; + + // String enum props + enum_optional: Readonly<{ + prop?: WithDefault, 'small'>; + }>; + + // ImageSource props + image_required: Readonly<{prop: ImageSource}>; + image_optional_key: Readonly<{prop?: ImageSource}>; + image_optional_value: Readonly<{prop: ImageSource | null | undefined}>; + image_optional_both: Readonly<{prop?: ImageSource | null | undefined}>; + + // ColorValue props + color_required: Readonly<{prop: ColorValue}>; + color_optional_key: Readonly<{prop?: ColorValue}>; + color_optional_value: Readonly<{prop: ColorValue | null | undefined}>; + color_optional_both: Readonly<{prop?: ColorValue | null | undefined}>; + + // ProcessedColorValue props + processed_color_required: Readonly<{prop: ProcessedColorValue}>; + processed_color_optional_key: Readonly<{prop?: ProcessedColorValue}>; + processed_color_optional_value: Readonly<{ + prop: ProcessedColorValue | null | undefined; + }>; + processed_color_optional_both: Readonly<{ + prop?: ProcessedColorValue | null | undefined; + }>; + + // PointValue props + point_required: Readonly<{prop: PointValue}>; + point_optional_key: Readonly<{prop?: PointValue}>; + point_optional_value: Readonly<{prop: PointValue | null | undefined}>; + point_optional_both: Readonly<{prop?: PointValue | null | undefined}>; + + // EdgeInsetsValue props + insets_required: Readonly<{prop: EdgeInsetsValue}>; + insets_optional_key: Readonly<{prop?: EdgeInsetsValue}>; + insets_optional_value: Readonly<{prop: EdgeInsetsValue | null | undefined}>; + insets_optional_both: Readonly<{prop?: EdgeInsetsValue | null | undefined}>; + + // Nested object props + object_required: Readonly<{prop: Readonly<{nestedProp: string}>}>; + object_optional_key?: Readonly<{prop: Readonly<{nestedProp: string}>}>; + object_optional_value: Readonly<{ + prop: Readonly<{nestedProp: string}>; + }> | null | undefined; + object_optional_both?: Readonly<{ + prop: Readonly<{nestedProp: string}>; + }> | null | undefined; +} + +export default codegenNativeComponent( + 'Module', +) as HostComponent; +`; + module.exports = { ALL_PROP_TYPES_NO_EVENTS, ARRAY_PROP_TYPES_NO_EVENTS, @@ -1100,8 +1626,12 @@ module.exports = { EVENTS_DEFINED_INLINE_WITH_ALL_TYPES, EVENTS_DEFINED_AS_NULL_INLINE, PROPS_AND_EVENTS_TYPES_EXPORTED, - COMMANDS_AND_EVENTS_TYPES_EXPORTED, + COMMANDS_EVENTS_STATE_TYPES_EXPORTED, COMMANDS_DEFINED_WITH_ALL_TYPES, PROPS_AS_EXTERNAL_TYPES, COMMANDS_WITH_EXTERNAL_TYPES, + ALL_STATE_TYPES, + ARRAY_STATE_TYPES, + ARRAY2_STATE_TYPES, + OBJECT_STATE_TYPES, }; diff --git a/packages/react-native-codegen/src/parsers/typescript/components/__tests__/__snapshots__/typescript-component-parser-test.js.snap b/packages/react-native-codegen/src/parsers/typescript/components/__tests__/__snapshots__/typescript-component-parser-test.js.snap index d0e62f5ee1c02b..1634f2bfe48f1a 100644 --- a/packages/react-native-codegen/src/parsers/typescript/components/__tests__/__snapshots__/typescript-component-parser-test.js.snap +++ b/packages/react-native-codegen/src/parsers/typescript/components/__tests__/__snapshots__/typescript-component-parser-test.js.snap @@ -12,8 +12,14 @@ exports[`RN Codegen TypeScript Parser Fails with error message COMMANDS_DEFINED_ exports[`RN Codegen TypeScript Parser Fails with error message COMMANDS_DEFINED_WITHOUT_REF 1`] = `"The first argument of method hotspotUpdate must be of type React.ElementRef<>"`; +exports[`RN Codegen TypeScript Parser Fails with error message DOUBLE_STATE_IN_FILE 1`] = `"Found 2 NativeStates for Module. Each component can have only 1 NativeState"`; + +exports[`RN Codegen TypeScript Parser Fails with error message NON_OPTIONAL_KEY_STATE_WITH_DEFAULT_VALUE 1`] = `"key required_key_with_default must be optional if used with WithDefault<> annotation"`; + exports[`RN Codegen TypeScript Parser Fails with error message NON_OPTIONAL_KEY_WITH_DEFAULT_VALUE 1`] = `"key required_key_with_default must be optional if used with WithDefault<> annotation"`; +exports[`RN Codegen TypeScript Parser Fails with error message NULLABLE_STATE_WITH_DEFAULT 1`] = `"WithDefault<> is optional and does not need to be marked as optional. Please remove the union of undefined and/or null"`; + exports[`RN Codegen TypeScript Parser Fails with error message NULLABLE_WITH_DEFAULT 1`] = `"WithDefault<> is optional and does not need to be marked as optional. Please remove the union of undefined and/or null"`; exports[`RN Codegen TypeScript Parser Fails with error message PROP_ARRAY_ENUM_BOOLEAN 1`] = `"Unsupported union type for \\"someProp\\", received \\"BooleanLiteral\\""`; @@ -32,6 +38,22 @@ exports[`RN Codegen TypeScript Parser Fails with error message PROPS_CONFLICT_NA exports[`RN Codegen TypeScript Parser Fails with error message PROPS_CONFLICT_WITH_SPREAD_PROPS 1`] = `"A prop was already defined with the name isEnabled"`; +exports[`RN Codegen TypeScript Parser Fails with error message STATE_ARRAY_ENUM_BOOLEAN 1`] = `"Unsupported union type for \\"someProp\\", received \\"BooleanLiteral\\""`; + +exports[`RN Codegen TypeScript Parser Fails with error message STATE_ARRAY_ENUM_INT 1`] = `"Arrays of int enums are not supported (see: \\"someProp\\")"`; + +exports[`RN Codegen TypeScript Parser Fails with error message STATE_ARRAY_MIXED_ENUM 1`] = `"Mixed types are not supported (see \\"someProp\\")"`; + +exports[`RN Codegen TypeScript Parser Fails with error message STATE_CONFLICT_NAMES 1`] = `"A prop was already defined with the name isEnabled"`; + +exports[`RN Codegen TypeScript Parser Fails with error message STATE_CONFLICT_WITH_SPREAD_PROPS 1`] = `"A prop was already defined with the name isEnabled"`; + +exports[`RN Codegen TypeScript Parser Fails with error message STATE_ENUM_BOOLEAN 1`] = `"Unsupported union type for \\"someProp\\", received \\"BooleanLiteral\\""`; + +exports[`RN Codegen TypeScript Parser Fails with error message STATE_MIXED_ENUM 1`] = `"Mixed types are not supported (see \\"someProp\\")"`; + +exports[`RN Codegen TypeScript Parser Fails with error message STATE_NUMBER_TYPE 1`] = `"Cannot use \\"TSNumberKeyword\\" type annotation for \\"someProp\\": must use a specific numeric type like Int32, Double, or Float"`; + exports[`RN Codegen TypeScript Parser can generate fixture ALL_PROP_TYPES_NO_EVENTS 1`] = ` "{ 'modules': { @@ -547,7 +569,7 @@ exports[`RN Codegen TypeScript Parser can generate fixture ALL_PROP_TYPES_NO_EVE }" `; -exports[`RN Codegen TypeScript Parser can generate fixture ARRAY_PROP_TYPES_NO_EVENTS 1`] = ` +exports[`RN Codegen TypeScript Parser can generate fixture ALL_STATE_TYPES 1`] = ` "{ 'modules': { 'Module': { @@ -561,669 +583,501 @@ exports[`RN Codegen TypeScript Parser can generate fixture ARRAY_PROP_TYPES_NO_E } ], 'events': [], - 'props': [ + 'props': [], + 'commands': [], + 'state': [ { - 'name': 'array_boolean_required', + 'name': 'boolean_required', 'optional': false, 'typeAnnotation': { - 'type': 'ArrayTypeAnnotation', - 'elementType': { - 'type': 'BooleanTypeAnnotation' - } + 'type': 'BooleanTypeAnnotation', + 'default': false } }, { - 'name': 'array_boolean_optional_key', + 'name': 'boolean_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'ArrayTypeAnnotation', - 'elementType': { - 'type': 'BooleanTypeAnnotation' - } + 'type': 'BooleanTypeAnnotation', + 'default': true } }, { - 'name': 'array_boolean_optional_value', + 'name': 'boolean_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'ArrayTypeAnnotation', - 'elementType': { - 'type': 'BooleanTypeAnnotation' - } + 'type': 'BooleanTypeAnnotation', + 'default': true } }, { - 'name': 'array_boolean_optional_both', + 'name': 'boolean_null_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'ArrayTypeAnnotation', - 'elementType': { - 'type': 'BooleanTypeAnnotation' - } + 'type': 'BooleanTypeAnnotation', + 'default': null } }, { - 'name': 'array_string_required', + 'name': 'boolean_null_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation', + 'default': null + } + }, + { + 'name': 'string_required', 'optional': false, 'typeAnnotation': { - 'type': 'ArrayTypeAnnotation', - 'elementType': { - 'type': 'StringTypeAnnotation' - } + 'type': 'StringTypeAnnotation', + 'default': null } }, { - 'name': 'array_string_optional_key', + 'name': 'string_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'ArrayTypeAnnotation', - 'elementType': { - 'type': 'StringTypeAnnotation' - } + 'type': 'StringTypeAnnotation', + 'default': '' } }, { - 'name': 'array_string_optional_value', + 'name': 'string_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'ArrayTypeAnnotation', - 'elementType': { - 'type': 'StringTypeAnnotation' - } + 'type': 'StringTypeAnnotation', + 'default': '' } }, { - 'name': 'array_string_optional_both', + 'name': 'string_null_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'ArrayTypeAnnotation', - 'elementType': { - 'type': 'StringTypeAnnotation' - } + 'type': 'StringTypeAnnotation', + 'default': null } }, { - 'name': 'array_double_required', - 'optional': false, + 'name': 'string_null_optional_both', + 'optional': true, 'typeAnnotation': { - 'type': 'ArrayTypeAnnotation', - 'elementType': { - 'type': 'DoubleTypeAnnotation' - } + 'type': 'StringTypeAnnotation', + 'default': null } }, { - 'name': 'array_double_optional_key', - 'optional': true, + 'name': 'stringish_required', + 'optional': false, 'typeAnnotation': { - 'type': 'ArrayTypeAnnotation', - 'elementType': { - 'type': 'DoubleTypeAnnotation' - } + 'type': 'StringTypeAnnotation', + 'default': null } }, { - 'name': 'array_double_optional_value', + 'name': 'stringish_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'ArrayTypeAnnotation', - 'elementType': { - 'type': 'DoubleTypeAnnotation' - } + 'type': 'StringTypeAnnotation', + 'default': '' } }, { - 'name': 'array_double_optional_both', + 'name': 'stringish_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'ArrayTypeAnnotation', - 'elementType': { - 'type': 'DoubleTypeAnnotation' - } + 'type': 'StringTypeAnnotation', + 'default': '' } }, { - 'name': 'array_float_required', - 'optional': false, + 'name': 'stringish_null_optional_key', + 'optional': true, 'typeAnnotation': { - 'type': 'ArrayTypeAnnotation', - 'elementType': { - 'type': 'FloatTypeAnnotation' - } + 'type': 'StringTypeAnnotation', + 'default': null } }, { - 'name': 'array_float_optional_key', + 'name': 'stringish_null_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'ArrayTypeAnnotation', - 'elementType': { - 'type': 'FloatTypeAnnotation' - } + 'type': 'StringTypeAnnotation', + 'default': null } }, { - 'name': 'array_float_optional_value', - 'optional': true, + 'name': 'double_required', + 'optional': false, 'typeAnnotation': { - 'type': 'ArrayTypeAnnotation', - 'elementType': { - 'type': 'FloatTypeAnnotation' - } + 'type': 'DoubleTypeAnnotation', + 'default': 0 } }, { - 'name': 'array_float_optional_both', + 'name': 'double_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'ArrayTypeAnnotation', - 'elementType': { - 'type': 'FloatTypeAnnotation' - } + 'type': 'DoubleTypeAnnotation', + 'default': 1.1 } }, { - 'name': 'array_int32_required', - 'optional': false, + 'name': 'double_optional_both', + 'optional': true, 'typeAnnotation': { - 'type': 'ArrayTypeAnnotation', - 'elementType': { - 'type': 'Int32TypeAnnotation' - } + 'type': 'DoubleTypeAnnotation', + 'default': 1.1 } }, { - 'name': 'array_int32_optional_key', - 'optional': true, + 'name': 'float_required', + 'optional': false, 'typeAnnotation': { - 'type': 'ArrayTypeAnnotation', - 'elementType': { - 'type': 'Int32TypeAnnotation' - } + 'type': 'FloatTypeAnnotation', + 'default': 0 } }, { - 'name': 'array_int32_optional_value', + 'name': 'float_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'ArrayTypeAnnotation', - 'elementType': { - 'type': 'Int32TypeAnnotation' - } + 'type': 'FloatTypeAnnotation', + 'default': 1.1 } }, { - 'name': 'array_int32_optional_both', + 'name': 'float_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'ArrayTypeAnnotation', - 'elementType': { - 'type': 'Int32TypeAnnotation' - } + 'type': 'FloatTypeAnnotation', + 'default': 1.1 } }, { - 'name': 'array_enum_optional_key', + 'name': 'float_null_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'ArrayTypeAnnotation', - 'elementType': { - 'type': 'StringEnumTypeAnnotation', - 'default': 'small', - 'options': [ - 'small', - 'large' - ] - } + 'type': 'FloatTypeAnnotation', + 'default': null } }, { - 'name': 'array_enum_optional_both', + 'name': 'float_null_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'ArrayTypeAnnotation', - 'elementType': { - 'type': 'StringEnumTypeAnnotation', - 'default': 'small', - 'options': [ - 'small', - 'large' - ] - } + 'type': 'FloatTypeAnnotation', + 'default': null } }, { - 'name': 'array_image_required', + 'name': 'int32_required', 'optional': false, 'typeAnnotation': { - 'type': 'ArrayTypeAnnotation', - 'elementType': { - 'type': 'ReservedPropTypeAnnotation', - 'name': 'ImageSourcePrimitive' - } + 'type': 'Int32TypeAnnotation', + 'default': 0 } }, { - 'name': 'array_image_optional_key', + 'name': 'int32_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'ArrayTypeAnnotation', - 'elementType': { - 'type': 'ReservedPropTypeAnnotation', - 'name': 'ImageSourcePrimitive' - } + 'type': 'Int32TypeAnnotation', + 'default': 1 } }, { - 'name': 'array_image_optional_value', + 'name': 'int32_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'ArrayTypeAnnotation', - 'elementType': { - 'type': 'ReservedPropTypeAnnotation', - 'name': 'ImageSourcePrimitive' - } + 'type': 'Int32TypeAnnotation', + 'default': 1 } }, { - 'name': 'array_image_optional_both', + 'name': 'enum_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'ArrayTypeAnnotation', - 'elementType': { - 'type': 'ReservedPropTypeAnnotation', - 'name': 'ImageSourcePrimitive' - } - } - }, + 'type': 'StringEnumTypeAnnotation', + 'default': 'small', + 'options': [ + 'small', + 'large' + ] + } + }, { - 'name': 'array_color_required', - 'optional': false, + 'name': 'enum_optional_both', + 'optional': true, 'typeAnnotation': { - 'type': 'ArrayTypeAnnotation', - 'elementType': { - 'type': 'ReservedPropTypeAnnotation', - 'name': 'ColorPrimitive' - } + 'type': 'StringEnumTypeAnnotation', + 'default': 'small', + 'options': [ + 'small', + 'large' + ] } }, { - 'name': 'array_color_optional_key', + 'name': 'int_enum_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'ArrayTypeAnnotation', - 'elementType': { - 'type': 'ReservedPropTypeAnnotation', - 'name': 'ColorPrimitive' - } + 'type': 'Int32EnumTypeAnnotation', + 'default': 0, + 'options': [ + 0, + 1 + ] } }, { - 'name': 'array_color_optional_value', + 'name': 'object_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'ArrayTypeAnnotation', - 'elementType': { - 'type': 'ReservedPropTypeAnnotation', - 'name': 'ColorPrimitive' - } + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation', + 'default': null + } + } + ] } }, { - 'name': 'array_color_optional_both', + 'name': 'object_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'ArrayTypeAnnotation', - 'elementType': { - 'type': 'ReservedPropTypeAnnotation', - 'name': 'ColorPrimitive' - } + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation', + 'default': null + } + } + ] } }, { - 'name': 'array_point_required', + 'name': 'object_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation', + 'default': null + } + } + ] + } + }, + { + 'name': 'image_required', 'optional': false, 'typeAnnotation': { - 'type': 'ArrayTypeAnnotation', - 'elementType': { - 'type': 'ReservedPropTypeAnnotation', - 'name': 'PointPrimitive' - } + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ImageSourcePrimitive' } }, { - 'name': 'array_point_optional_key', + 'name': 'image_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'ArrayTypeAnnotation', - 'elementType': { - 'type': 'ReservedPropTypeAnnotation', - 'name': 'PointPrimitive' - } + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ImageSourcePrimitive' } }, { - 'name': 'array_point_optional_value', + 'name': 'image_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'ArrayTypeAnnotation', - 'elementType': { - 'type': 'ReservedPropTypeAnnotation', - 'name': 'PointPrimitive' - } + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ImageSourcePrimitive' } }, { - 'name': 'array_point_optional_both', + 'name': 'color_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ColorPrimitive' + } + }, + { + 'name': 'color_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'ArrayTypeAnnotation', - 'elementType': { - 'type': 'ReservedPropTypeAnnotation', - 'name': 'PointPrimitive' - } + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ColorPrimitive' } }, { - 'name': 'array_insets_required', + 'name': 'color_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ColorPrimitive' + } + }, + { + 'name': 'color_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ColorPrimitive' + } + }, + { + 'name': 'color_array_required', 'optional': false, 'typeAnnotation': { 'type': 'ArrayTypeAnnotation', 'elementType': { 'type': 'ReservedPropTypeAnnotation', - 'name': 'EdgeInsetsPrimitive' + 'name': 'ColorPrimitive' } } }, { - 'name': 'array_insets_optional_key', + 'name': 'color_array_optional_key', 'optional': true, 'typeAnnotation': { 'type': 'ArrayTypeAnnotation', 'elementType': { 'type': 'ReservedPropTypeAnnotation', - 'name': 'EdgeInsetsPrimitive' + 'name': 'ColorPrimitive' } } }, { - 'name': 'array_insets_optional_value', + 'name': 'color_array_optional_value', 'optional': true, 'typeAnnotation': { 'type': 'ArrayTypeAnnotation', 'elementType': { 'type': 'ReservedPropTypeAnnotation', - 'name': 'EdgeInsetsPrimitive' + 'name': 'ColorPrimitive' } } }, { - 'name': 'array_insets_optional_both', + 'name': 'color_array_optional_both', 'optional': true, 'typeAnnotation': { 'type': 'ArrayTypeAnnotation', 'elementType': { 'type': 'ReservedPropTypeAnnotation', - 'name': 'EdgeInsetsPrimitive' + 'name': 'ColorPrimitive' } } }, { - 'name': 'array_object_required', + 'name': 'processed_color_required', 'optional': false, 'typeAnnotation': { - 'type': 'ArrayTypeAnnotation', - 'elementType': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'prop', - 'optional': false, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation', - 'default': null - } - } - ] - } + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ColorPrimitive' } }, { - 'name': 'array_object_optional_key', + 'name': 'processed_color_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'ArrayTypeAnnotation', - 'elementType': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'prop', - 'optional': false, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation', - 'default': null - } - } - ] - } + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ColorPrimitive' } }, { - 'name': 'array_object_optional_value', + 'name': 'processed_color_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'ArrayTypeAnnotation', - 'elementType': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'prop', - 'optional': false, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation', - 'default': null - } - } - ] - } + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ColorPrimitive' } }, { - 'name': 'array_object_optional_both', + 'name': 'processed_color_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'ArrayTypeAnnotation', - 'elementType': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'prop', - 'optional': false, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation', - 'default': null - } - } - ] - } + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ColorPrimitive' } }, { - 'name': 'array_of_array_object_required', + 'name': 'point_required', 'optional': false, 'typeAnnotation': { - 'type': 'ArrayTypeAnnotation', - 'elementType': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'array_object_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'ArrayTypeAnnotation', - 'elementType': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'prop', - 'optional': false, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation', - 'default': null - } - } - ] - } - } - } - ] - } + 'type': 'ReservedPropTypeAnnotation', + 'name': 'PointPrimitive' } }, { - 'name': 'array_of_array_object_optional_key', + 'name': 'point_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'ArrayTypeAnnotation', - 'elementType': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'array_object_optional_key', - 'optional': false, - 'typeAnnotation': { - 'type': 'ArrayTypeAnnotation', - 'elementType': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'prop', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation', - 'default': null - } - } - ] - } - } - } - ] - } + 'type': 'ReservedPropTypeAnnotation', + 'name': 'PointPrimitive' } }, { - 'name': 'array_of_array_object_optional_value', + 'name': 'point_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'ArrayTypeAnnotation', - 'elementType': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'array_object_optional_value', - 'optional': false, - 'typeAnnotation': { - 'type': 'ArrayTypeAnnotation', - 'elementType': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'prop', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation', - 'default': null - } - } - ] - } - } - } - ] - } + 'type': 'ReservedPropTypeAnnotation', + 'name': 'PointPrimitive' } }, { - 'name': 'array_of_array_object_optional_both', + 'name': 'point_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'ArrayTypeAnnotation', - 'elementType': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'array_object_optional_both', - 'optional': false, - 'typeAnnotation': { - 'type': 'ArrayTypeAnnotation', - 'elementType': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'prop', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation', - 'default': null - } - } - ] - } - } - } - ] - } + 'type': 'ReservedPropTypeAnnotation', + 'name': 'PointPrimitive' } }, { - 'name': 'array_of_array_of_object_required', + 'name': 'insets_required', 'optional': false, 'typeAnnotation': { - 'type': 'ArrayTypeAnnotation', - 'elementType': { - 'type': 'ArrayTypeAnnotation', - 'elementType': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'prop', - 'optional': false, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation', - 'default': null - } - } - ] - } - } + 'type': 'ReservedPropTypeAnnotation', + 'name': 'EdgeInsetsPrimitive' } }, { - 'name': 'array_of_array_of_object_required_in_file', - 'optional': false, + 'name': 'insets_optional_key', + 'optional': true, 'typeAnnotation': { - 'type': 'ArrayTypeAnnotation', - 'elementType': { - 'type': 'ArrayTypeAnnotation', - 'elementType': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'prop', - 'optional': false, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation', - 'default': null - } - } - ] - } - } + 'type': 'ReservedPropTypeAnnotation', + 'name': 'EdgeInsetsPrimitive' + } + }, + { + 'name': 'insets_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'EdgeInsetsPrimitive' + } + }, + { + 'name': 'insets_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'EdgeInsetsPrimitive' } } - ], - 'commands': [] + ] } } } @@ -1231,7 +1085,7 @@ exports[`RN Codegen TypeScript Parser can generate fixture ARRAY_PROP_TYPES_NO_E }" `; -exports[`RN Codegen TypeScript Parser can generate fixture ARRAY2_PROP_TYPES_NO_EVENTS 1`] = ` +exports[`RN Codegen TypeScript Parser can generate fixture ARRAY_PROP_TYPES_NO_EVENTS 1`] = ` "{ 'modules': { 'Module': { @@ -1915,7 +1769,7 @@ exports[`RN Codegen TypeScript Parser can generate fixture ARRAY2_PROP_TYPES_NO_ }" `; -exports[`RN Codegen TypeScript Parser can generate fixture COMMANDS_AND_EVENTS_TYPES_EXPORTED 1`] = ` +exports[`RN Codegen TypeScript Parser can generate fixture ARRAY_STATE_TYPES 1`] = ` "{ 'modules': { 'Module': { @@ -1928,96 +1782,2253 @@ exports[`RN Codegen TypeScript Parser can generate fixture COMMANDS_AND_EVENTS_T 'knownTypeName': 'ReactNativeCoreViewProps' } ], - 'events': [ + 'events': [], + 'props': [], + 'commands': [], + 'state': [ { - 'name': 'onBubblingEventDefinedInline', + 'name': 'array_boolean_required', 'optional': false, - 'bubblingType': 'bubble', 'typeAnnotation': { - 'type': 'EventTypeAnnotation', - 'argument': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'boolean_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' - } - }, - { - 'name': 'boolean_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' - } - }, - { - 'name': 'boolean_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' - } - }, - { - 'name': 'boolean_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' - } - }, - { - 'name': 'string_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation' - } - }, - { - 'name': 'string_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation' - } - }, - { - 'name': 'string_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation' - } - }, - { - 'name': 'string_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation' - } - }, - { - 'name': 'double_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' - } - }, - { - 'name': 'double_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' - } - }, - { - 'name': 'double_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' - } - }, - { - 'name': 'double_optional_both', - 'optional': true, + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'array_boolean_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'array_boolean_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'array_boolean_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'array_string_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'array_string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'array_string_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'array_string_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'array_double_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'array_double_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'array_double_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'array_double_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'array_float_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'array_float_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'array_float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'array_float_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'array_int32_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'array_int32_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'array_int32_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'array_int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'array_enum_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'default': 'small', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'array_enum_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'default': 'small', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'array_image_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ImageSourcePrimitive' + } + } + }, + { + 'name': 'array_image_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ImageSourcePrimitive' + } + } + }, + { + 'name': 'array_image_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ImageSourcePrimitive' + } + } + }, + { + 'name': 'array_image_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ImageSourcePrimitive' + } + } + }, + { + 'name': 'array_color_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ColorPrimitive' + } + } + }, + { + 'name': 'array_color_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ColorPrimitive' + } + } + }, + { + 'name': 'array_color_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ColorPrimitive' + } + } + }, + { + 'name': 'array_color_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ColorPrimitive' + } + } + }, + { + 'name': 'array_point_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'PointPrimitive' + } + } + }, + { + 'name': 'array_point_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'PointPrimitive' + } + } + }, + { + 'name': 'array_point_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'PointPrimitive' + } + } + }, + { + 'name': 'array_point_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'PointPrimitive' + } + } + }, + { + 'name': 'array_insets_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'EdgeInsetsPrimitive' + } + } + }, + { + 'name': 'array_insets_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'EdgeInsetsPrimitive' + } + } + }, + { + 'name': 'array_insets_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'EdgeInsetsPrimitive' + } + } + }, + { + 'name': 'array_insets_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'EdgeInsetsPrimitive' + } + } + }, + { + 'name': 'array_object_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation', + 'default': null + } + } + ] + } + } + }, + { + 'name': 'array_object_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation', + 'default': null + } + } + ] + } + } + }, + { + 'name': 'array_object_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation', + 'default': null + } + } + ] + } + } + }, + { + 'name': 'array_object_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation', + 'default': null + } + } + ] + } + } + }, + { + 'name': 'array_of_array_object_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'array_object_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation', + 'default': null + } + } + ] + } + } + } + ] + } + } + }, + { + 'name': 'array_of_array_object_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'array_object_optional_key', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation', + 'default': null + } + } + ] + } + } + } + ] + } + } + }, + { + 'name': 'array_of_array_object_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'array_object_optional_value', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation', + 'default': null + } + } + ] + } + } + } + ] + } + } + }, + { + 'name': 'array_of_array_object_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'array_object_optional_both', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation', + 'default': null + } + } + ] + } + } + } + ] + } + } + }, + { + 'name': 'array_of_array_of_object_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation', + 'default': null + } + } + ] + } + } + } + }, + { + 'name': 'array_of_array_of_object_required_in_file', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation', + 'default': null + } + } + ] + } + } + } + } + ] + } + } + } + } +}" +`; + +exports[`RN Codegen TypeScript Parser can generate fixture ARRAY2_PROP_TYPES_NO_EVENTS 1`] = ` +"{ + 'modules': { + 'Module': { + 'type': 'Component', + 'components': { + 'Module': { + 'extendsProps': [ + { + 'type': 'ReactNativeBuiltInType', + 'knownTypeName': 'ReactNativeCoreViewProps' + } + ], + 'events': [], + 'props': [ + { + 'name': 'array_boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'array_boolean_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'array_boolean_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'array_boolean_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'array_string_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'array_string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'array_string_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'array_string_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'array_double_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'array_double_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'array_double_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'array_double_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'array_float_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'array_float_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'array_float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'array_float_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'array_int32_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'array_int32_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'array_int32_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'array_int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'array_enum_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'default': 'small', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'array_enum_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'default': 'small', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'array_image_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ImageSourcePrimitive' + } + } + }, + { + 'name': 'array_image_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ImageSourcePrimitive' + } + } + }, + { + 'name': 'array_image_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ImageSourcePrimitive' + } + } + }, + { + 'name': 'array_image_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ImageSourcePrimitive' + } + } + }, + { + 'name': 'array_color_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ColorPrimitive' + } + } + }, + { + 'name': 'array_color_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ColorPrimitive' + } + } + }, + { + 'name': 'array_color_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ColorPrimitive' + } + } + }, + { + 'name': 'array_color_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ColorPrimitive' + } + } + }, + { + 'name': 'array_point_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'PointPrimitive' + } + } + }, + { + 'name': 'array_point_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'PointPrimitive' + } + } + }, + { + 'name': 'array_point_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'PointPrimitive' + } + } + }, + { + 'name': 'array_point_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'PointPrimitive' + } + } + }, + { + 'name': 'array_insets_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'EdgeInsetsPrimitive' + } + } + }, + { + 'name': 'array_insets_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'EdgeInsetsPrimitive' + } + } + }, + { + 'name': 'array_insets_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'EdgeInsetsPrimitive' + } + } + }, + { + 'name': 'array_insets_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'EdgeInsetsPrimitive' + } + } + }, + { + 'name': 'array_object_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation', + 'default': null + } + } + ] + } + } + }, + { + 'name': 'array_object_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation', + 'default': null + } + } + ] + } + } + }, + { + 'name': 'array_object_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation', + 'default': null + } + } + ] + } + } + }, + { + 'name': 'array_object_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation', + 'default': null + } + } + ] + } + } + }, + { + 'name': 'array_of_array_object_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'array_object_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation', + 'default': null + } + } + ] + } + } + } + ] + } + } + }, + { + 'name': 'array_of_array_object_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'array_object_optional_key', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation', + 'default': null + } + } + ] + } + } + } + ] + } + } + }, + { + 'name': 'array_of_array_object_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'array_object_optional_value', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation', + 'default': null + } + } + ] + } + } + } + ] + } + } + }, + { + 'name': 'array_of_array_object_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'array_object_optional_both', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation', + 'default': null + } + } + ] + } + } + } + ] + } + } + }, + { + 'name': 'array_of_array_of_object_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation', + 'default': null + } + } + ] + } + } + } + }, + { + 'name': 'array_of_array_of_object_required_in_file', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation', + 'default': null + } + } + ] + } + } + } + } + ], + 'commands': [] + } + } + } + } +}" +`; + +exports[`RN Codegen TypeScript Parser can generate fixture ARRAY2_STATE_TYPES 1`] = ` +"{ + 'modules': { + 'Module': { + 'type': 'Component', + 'components': { + 'Module': { + 'extendsProps': [ + { + 'type': 'ReactNativeBuiltInType', + 'knownTypeName': 'ReactNativeCoreViewProps' + } + ], + 'events': [], + 'props': [], + 'commands': [], + 'state': [ + { + 'name': 'array_boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'array_boolean_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'array_boolean_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'array_boolean_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'array_string_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'array_string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'array_string_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'array_string_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'array_double_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'array_double_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'array_double_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'array_double_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'array_float_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'array_float_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'array_float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'array_float_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'array_int32_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'array_int32_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'array_int32_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'array_int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'array_enum_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'default': 'small', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'array_enum_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'default': 'small', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'array_image_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ImageSourcePrimitive' + } + } + }, + { + 'name': 'array_image_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ImageSourcePrimitive' + } + } + }, + { + 'name': 'array_image_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ImageSourcePrimitive' + } + } + }, + { + 'name': 'array_image_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ImageSourcePrimitive' + } + } + }, + { + 'name': 'array_color_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ColorPrimitive' + } + } + }, + { + 'name': 'array_color_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ColorPrimitive' + } + } + }, + { + 'name': 'array_color_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ColorPrimitive' + } + } + }, + { + 'name': 'array_color_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ColorPrimitive' + } + } + }, + { + 'name': 'array_point_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'PointPrimitive' + } + } + }, + { + 'name': 'array_point_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'PointPrimitive' + } + } + }, + { + 'name': 'array_point_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'PointPrimitive' + } + } + }, + { + 'name': 'array_point_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'PointPrimitive' + } + } + }, + { + 'name': 'array_insets_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'EdgeInsetsPrimitive' + } + } + }, + { + 'name': 'array_insets_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'EdgeInsetsPrimitive' + } + } + }, + { + 'name': 'array_insets_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'EdgeInsetsPrimitive' + } + } + }, + { + 'name': 'array_insets_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'EdgeInsetsPrimitive' + } + } + }, + { + 'name': 'array_object_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation', + 'default': null + } + } + ] + } + } + }, + { + 'name': 'array_object_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation', + 'default': null + } + } + ] + } + } + }, + { + 'name': 'array_object_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation', + 'default': null + } + } + ] + } + } + }, + { + 'name': 'array_object_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation', + 'default': null + } + } + ] + } + } + }, + { + 'name': 'array_of_array_object_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'array_object_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation', + 'default': null + } + } + ] + } + } + } + ] + } + } + }, + { + 'name': 'array_of_array_object_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'array_object_optional_key', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation', + 'default': null + } + } + ] + } + } + } + ] + } + } + }, + { + 'name': 'array_of_array_object_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'array_object_optional_value', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation', + 'default': null + } + } + ] + } + } + } + ] + } + } + }, + { + 'name': 'array_of_array_object_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'array_object_optional_both', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation', + 'default': null + } + } + ] + } + } + } + ] + } + } + }, + { + 'name': 'array_of_array_of_object_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation', + 'default': null + } + } + ] + } + } + } + }, + { + 'name': 'array_of_array_of_object_required_in_file', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation', + 'default': null + } + } + ] + } + } + } + } + ] + } + } + } + } +}" +`; + +exports[`RN Codegen TypeScript Parser can generate fixture COMMANDS_DEFINED_WITH_ALL_TYPES 1`] = ` +"{ + 'modules': { + 'Module': { + 'type': 'Component', + 'components': { + 'Module': { + 'extendsProps': [ + { + 'type': 'ReactNativeBuiltInType', + 'knownTypeName': 'ReactNativeCoreViewProps' + } + ], + 'events': [], + 'props': [], + 'commands': [ + { + 'name': 'handleRootTag', + 'optional': false, + 'typeAnnotation': { + 'type': 'FunctionTypeAnnotation', + 'params': [ + { + 'name': 'rootTag', + 'typeAnnotation': { + 'type': 'ReservedTypeAnnotation', + 'name': 'RootTag' + } + } + ], + 'returnTypeAnnotation': { + 'type': 'VoidTypeAnnotation' + } + } + }, + { + 'name': 'hotspotUpdate', + 'optional': false, + 'typeAnnotation': { + 'type': 'FunctionTypeAnnotation', + 'params': [ + { + 'name': 'x', + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'y', + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ], + 'returnTypeAnnotation': { + 'type': 'VoidTypeAnnotation' + } + } + }, + { + 'name': 'scrollTo', + 'optional': false, + 'typeAnnotation': { + 'type': 'FunctionTypeAnnotation', + 'params': [ + { + 'name': 'x', + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'y', + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'z', + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'animated', + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ], + 'returnTypeAnnotation': { + 'type': 'VoidTypeAnnotation' + } + } + } + ] + } + } + } + } +}" +`; + +exports[`RN Codegen TypeScript Parser can generate fixture COMMANDS_EVENTS_STATE_TYPES_EXPORTED 1`] = ` +"{ + 'modules': { + 'Module': { + 'type': 'Component', + 'components': { + 'Module': { + 'extendsProps': [ + { + 'type': 'ReactNativeBuiltInType', + 'knownTypeName': 'ReactNativeCoreViewProps' + } + ], + 'events': [ + { + 'name': 'onBubblingEventDefinedInline', + 'optional': false, + 'bubblingType': 'bubble', + 'typeAnnotation': { + 'type': 'EventTypeAnnotation', + 'argument': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'boolean_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'boolean_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'boolean_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'string_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'string_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'string_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'double_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'double_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'double_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'double_optional_both', + 'optional': true, 'typeAnnotation': { 'type': 'DoubleTypeAnnotation' } @@ -3470,107 +5481,30 @@ exports[`RN Codegen TypeScript Parser can generate fixture COMMANDS_AND_EVENTS_T } } } - ] - } - } - } - } -}" -`; - -exports[`RN Codegen TypeScript Parser can generate fixture COMMANDS_DEFINED_WITH_ALL_TYPES 1`] = ` -"{ - 'modules': { - 'Module': { - 'type': 'Component', - 'components': { - 'Module': { - 'extendsProps': [ - { - 'type': 'ReactNativeBuiltInType', - 'knownTypeName': 'ReactNativeCoreViewProps' - } ], - 'events': [], - 'props': [], - 'commands': [ + 'state': [ { - 'name': 'handleRootTag', + 'name': 'boolean_required', 'optional': false, 'typeAnnotation': { - 'type': 'FunctionTypeAnnotation', - 'params': [ - { - 'name': 'rootTag', - 'typeAnnotation': { - 'type': 'ReservedTypeAnnotation', - 'name': 'RootTag' - } - } - ], - 'returnTypeAnnotation': { - 'type': 'VoidTypeAnnotation' - } + 'type': 'BooleanTypeAnnotation', + 'default': false } }, { - 'name': 'hotspotUpdate', - 'optional': false, + 'name': 'boolean_optional_key', + 'optional': true, 'typeAnnotation': { - 'type': 'FunctionTypeAnnotation', - 'params': [ - { - 'name': 'x', - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } - }, - { - 'name': 'y', - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } - } - ], - 'returnTypeAnnotation': { - 'type': 'VoidTypeAnnotation' - } + 'type': 'BooleanTypeAnnotation', + 'default': true } }, { - 'name': 'scrollTo', - 'optional': false, + 'name': 'boolean_optional_both', + 'optional': true, 'typeAnnotation': { - 'type': 'FunctionTypeAnnotation', - 'params': [ - { - 'name': 'x', - 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' - } - }, - { - 'name': 'y', - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } - }, - { - 'name': 'z', - 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' - } - }, - { - 'name': 'animated', - 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' - } - } - ], - 'returnTypeAnnotation': { - 'type': 'VoidTypeAnnotation' - } + 'type': 'BooleanTypeAnnotation', + 'default': true } } ] @@ -7322,257 +9256,943 @@ exports[`RN Codegen TypeScript Parser can generate fixture EVENTS_DEFINED_INLINE } }, { - 'name': 'int32_optional_key', + 'name': 'int32_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'int32_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'enum_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'enum_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'enum_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'enum_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'object_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + } + ] } }, { - 'name': 'int32_optional_value', + 'name': 'object_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] } }, { - 'name': 'int32_optional_both', - 'optional': true, + 'name': 'object_required_nested_2_layers', + 'optional': false, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'object_optional_nested_1_layer', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'double_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + } + ] } }, { - 'name': 'enum_required', + 'name': 'object_readonly_required', 'optional': false, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } ] } }, { - 'name': 'enum_optional_key', + 'name': 'object_readonly_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + } ] } }, { - 'name': 'enum_optional_value', + 'name': 'object_readonly_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + } ] } }, { - 'name': 'enum_optional_both', + 'name': 'object_readonly_optional_both', 'optional': true, 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + } + ] + } + } + } + ], + 'props': [], + 'commands': [] + } + } + } + } +}" +`; + +exports[`RN Codegen TypeScript Parser can generate fixture NO_PROPS_EVENTS_ONLY_DEPRECATED_VIEW_CONFIG_NAME_OPTION 1`] = ` +"{ + 'modules': { + 'Module': { + 'type': 'Component', + 'components': { + 'Module': { + 'deprecatedViewConfigName': 'DeprecateModuleName', + 'extendsProps': [ + { + 'type': 'ReactNativeBuiltInType', + 'knownTypeName': 'ReactNativeCoreViewProps' + } + ], + 'events': [], + 'props': [], + 'commands': [] + } + } + } + } +}" +`; + +exports[`RN Codegen TypeScript Parser can generate fixture OBJECT_PROP_TYPES_NO_EVENTS 1`] = ` +"{ + 'modules': { + 'Module': { + 'type': 'Component', + 'components': { + 'Module': { + 'extendsProps': [ + { + 'type': 'ReactNativeBuiltInType', + 'knownTypeName': 'ReactNativeCoreViewProps' + } + ], + 'events': [], + 'props': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation', + 'default': false + } + } + ] + } + }, + { + 'name': 'boolean_optional', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation', + 'default': false + } + } + ] + } + }, + { + 'name': 'string_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation', + 'default': null + } + } + ] + } + }, + { + 'name': 'string_optional', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation', + 'default': '' + } + } + ] + } + }, + { + 'name': 'double_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': false, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation', + 'default': 0 + } + } + ] + } + }, + { + 'name': 'double_optional', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation', + 'default': 0 + } + } + ] + } + }, + { + 'name': 'float_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': false, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation', + 'default': 0 + } + } + ] + } + }, + { + 'name': 'float_optional', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation', + 'default': 0 + } + } + ] + } + }, + { + 'name': 'int_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': false, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation', + 'default': 0 + } + } + ] + } + }, + { + 'name': 'int_optional', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation', + 'default': 0 + } + } + ] + } + }, + { + 'name': 'enum_optional', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { 'type': 'StringEnumTypeAnnotation', + 'default': 'small', 'options': [ 'small', 'large' ] } - }, - { - 'name': 'object_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'boolean_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' - } - } - ] - } - }, - { - 'name': 'object_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'string_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation' - } - } - ] - } - }, - { - 'name': 'object_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'float_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' - } - } - ] - } - }, - { - 'name': 'object_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'int32_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } - } - ] - } - }, - { - 'name': 'object_required_nested_2_layers', - 'optional': false, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'object_optional_nested_1_layer', - 'optional': true, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'boolean_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } - }, - { - 'name': 'string_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation' - } - }, - { - 'name': 'double_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' - } - }, - { - 'name': 'float_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' - } - }, - { - 'name': 'int32_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } - } - ] - } - } - ] - } - }, - { - 'name': 'object_readonly_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'boolean_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' - } + } + } + ] + } + }, + { + 'name': 'image_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': false, + 'typeAnnotation': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ImageSourcePrimitive' + } + } + ] + } + }, + { + 'name': 'image_optional_key', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': true, + 'typeAnnotation': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ImageSourcePrimitive' + } + } + ] + } + }, + { + 'name': 'image_optional_value', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': true, + 'typeAnnotation': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ImageSourcePrimitive' + } + } + ] + } + }, + { + 'name': 'image_optional_both', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': true, + 'typeAnnotation': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ImageSourcePrimitive' + } + } + ] + } + }, + { + 'name': 'color_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': false, + 'typeAnnotation': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ColorPrimitive' + } + } + ] + } + }, + { + 'name': 'color_optional_key', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': true, + 'typeAnnotation': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ColorPrimitive' + } + } + ] + } + }, + { + 'name': 'color_optional_value', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': true, + 'typeAnnotation': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ColorPrimitive' + } + } + ] + } + }, + { + 'name': 'color_optional_both', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': true, + 'typeAnnotation': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ColorPrimitive' + } + } + ] + } + }, + { + 'name': 'processed_color_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': false, + 'typeAnnotation': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ColorPrimitive' + } + } + ] + } + }, + { + 'name': 'processed_color_optional_key', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': true, + 'typeAnnotation': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ColorPrimitive' + } + } + ] + } + }, + { + 'name': 'processed_color_optional_value', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': true, + 'typeAnnotation': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ColorPrimitive' + } + } + ] + } + }, + { + 'name': 'processed_color_optional_both', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': true, + 'typeAnnotation': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ColorPrimitive' + } + } + ] + } + }, + { + 'name': 'point_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': false, + 'typeAnnotation': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'PointPrimitive' + } + } + ] + } + }, + { + 'name': 'point_optional_key', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': true, + 'typeAnnotation': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'PointPrimitive' + } + } + ] + } + }, + { + 'name': 'point_optional_value', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': true, + 'typeAnnotation': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'PointPrimitive' + } + } + ] + } + }, + { + 'name': 'point_optional_both', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': true, + 'typeAnnotation': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'PointPrimitive' + } + } + ] + } + }, + { + 'name': 'insets_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': false, + 'typeAnnotation': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'EdgeInsetsPrimitive' + } + } + ] + } + }, + { + 'name': 'insets_optional_key', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': true, + 'typeAnnotation': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'EdgeInsetsPrimitive' + } + } + ] + } + }, + { + 'name': 'insets_optional_value', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': true, + 'typeAnnotation': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'EdgeInsetsPrimitive' + } + } + ] + } + }, + { + 'name': 'insets_optional_both', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': true, + 'typeAnnotation': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'EdgeInsetsPrimitive' + } + } + ] + } + }, + { + 'name': 'object_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'nestedProp', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation', + 'default': null } - ] - } - }, - { - 'name': 'object_readonly_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'string_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation' - } + } + ] + } + } + ] + } + }, + { + 'name': 'object_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'nestedProp', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation', + 'default': null } - ] - } - }, - { - 'name': 'object_readonly_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'float_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' - } + } + ] + } + } + ] + } + }, + { + 'name': 'object_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'nestedProp', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation', + 'default': null } - ] - } - }, - { - 'name': 'object_readonly_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'int32_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } + } + ] + } + } + ] + } + }, + { + 'name': 'object_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'nestedProp', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation', + 'default': null } - ] - } + } + ] } - ] - } + } + ] } } ], - 'props': [], 'commands': [] } } @@ -7581,14 +10201,13 @@ exports[`RN Codegen TypeScript Parser can generate fixture EVENTS_DEFINED_INLINE }" `; -exports[`RN Codegen TypeScript Parser can generate fixture NO_PROPS_EVENTS_ONLY_DEPRECATED_VIEW_CONFIG_NAME_OPTION 1`] = ` +exports[`RN Codegen TypeScript Parser can generate fixture OBJECT_STATE_TYPES 1`] = ` "{ 'modules': { 'Module': { 'type': 'Component', 'components': { 'Module': { - 'deprecatedViewConfigName': 'DeprecateModuleName', 'extendsProps': [ { 'type': 'ReactNativeBuiltInType', @@ -7597,29 +10216,8 @@ exports[`RN Codegen TypeScript Parser can generate fixture NO_PROPS_EVENTS_ONLY_ ], 'events': [], 'props': [], - 'commands': [] - } - } - } - } -}" -`; - -exports[`RN Codegen TypeScript Parser can generate fixture OBJECT_PROP_TYPES_NO_EVENTS 1`] = ` -"{ - 'modules': { - 'Module': { - 'type': 'Component', - 'components': { - 'Module': { - 'extendsProps': [ - { - 'type': 'ReactNativeBuiltInType', - 'knownTypeName': 'ReactNativeCoreViewProps' - } - ], - 'events': [], - 'props': [ + 'commands': [], + 'state': [ { 'name': 'boolean_required', 'optional': false, @@ -8258,8 +10856,7 @@ exports[`RN Codegen TypeScript Parser can generate fixture OBJECT_PROP_TYPES_NO_ ] } } - ], - 'commands': [] + ] } } } diff --git a/packages/react-native-codegen/src/parsers/typescript/components/componentsUtils.js b/packages/react-native-codegen/src/parsers/typescript/components/componentsUtils.js new file mode 100644 index 00000000000000..f8818eb77cbcaa --- /dev/null +++ b/packages/react-native-codegen/src/parsers/typescript/components/componentsUtils.js @@ -0,0 +1,693 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow strict-local + * @format + */ + +'use strict'; +import type {ASTNode} from '../utils'; +import type {TypeDeclarationMap} from '../utils.js'; +import type {NamedShape} from '../../../CodegenSchema.js'; +const {getValueFromTypes} = require('../utils.js'); + +function getProperties( + typeName: string, + types: TypeDeclarationMap, +): $FlowFixMe { + const alias = types[typeName]; + if (!alias) { + throw new Error( + `Failed to find definition for "${typeName}", please check that you have a valid codegen typescript file`, + ); + } + const aliasKind = + alias.type === 'TSInterfaceDeclaration' ? 'interface' : 'type'; + + try { + if (aliasKind === 'interface') { + return [...(alias.extends ?? []), ...alias.body.body]; + } + + return ( + alias.typeAnnotation.members || + alias.typeAnnotation.typeParameters.params[0].members || + alias.typeAnnotation.typeParameters.params + ); + } catch (e) { + throw new Error( + `Failed to find ${aliasKind} definition for "${typeName}", please check that you have a valid codegen typescript file`, + ); + } +} + +function getTypeAnnotationForObjectAsArrayElement( + objectType: $FlowFixMe, + types: TypeDeclarationMap, + buildSchema: (property: PropAST, types: TypeDeclarationMap) => ?NamedShape, +): $FlowFixMe { + return { + type: 'ObjectTypeAnnotation', + properties: flattenProperties( + objectType.typeParameters.params[0].members || + objectType.typeParameters.params, + types, + ) + .map(prop => buildSchema(prop, types)) + .filter(Boolean), + }; +} + +function getTypeAnnotationForArrayOfArrayOfObject( + typeAnnotation: $FlowFixMe, + types: TypeDeclarationMap, + buildSchema: (property: PropAST, types: TypeDeclarationMap) => ?NamedShape, +): $FlowFixMe { + // We need to go yet another level deeper to resolve + // types that may be defined in a type alias + const nestedObjectType = getValueFromTypes(typeAnnotation, types); + + return { + type: 'ArrayTypeAnnotation', + elementType: getTypeAnnotationForObjectAsArrayElement( + nestedObjectType, + types, + buildSchema, + ), + }; +} + +function getTypeAnnotationForArray( + name: string, + typeAnnotation: $FlowFixMe, + defaultValue: $FlowFixMe | null, + types: TypeDeclarationMap, + buildSchema: (property: PropAST, types: TypeDeclarationMap) => ?NamedShape, +): $FlowFixMe { + if (typeAnnotation.type === 'TSParenthesizedType') { + return getTypeAnnotationForArray( + name, + typeAnnotation.typeAnnotation, + defaultValue, + types, + buildSchema, + ); + } + + const extractedTypeAnnotation = getValueFromTypes(typeAnnotation, types); + + if ( + extractedTypeAnnotation.type === 'TSUnionType' && + extractedTypeAnnotation.types.some( + t => t.type === 'TSNullKeyword' || t.type === 'TSUndefinedKeyword', + ) + ) { + throw new Error( + 'Nested optionals such as "ReadonlyArray" are not supported, please declare optionals at the top level of value definitions as in "ReadonlyArray | null | undefined"', + ); + } + + if ( + extractedTypeAnnotation.type === 'TSTypeReference' && + extractedTypeAnnotation.typeName.name === 'WithDefault' + ) { + throw new Error( + 'Nested defaults such as "ReadonlyArray>" are not supported, please declare defaults at the top level of value definitions as in "WithDefault, false>"', + ); + } + + // Covers: T[] + if (typeAnnotation.type === 'TSArrayType') { + return getTypeAnnotationForArrayOfArrayOfObject( + typeAnnotation.elementType, + types, + buildSchema, + ); + } + + if (extractedTypeAnnotation.type === 'TSTypeReference') { + // Resolve the type alias if it's not defined inline + const objectType = getValueFromTypes(extractedTypeAnnotation, types); + + if (objectType.typeName.name === 'Readonly') { + return getTypeAnnotationForObjectAsArrayElement( + objectType, + types, + buildSchema, + ); + } + + // Covers: ReadonlyArray + if (objectType.typeName.name === 'ReadonlyArray') { + return getTypeAnnotationForArrayOfArrayOfObject( + objectType.typeParameters.params[0], + types, + buildSchema, + ); + } + } + + const type = + extractedTypeAnnotation.elementType === 'TSTypeReference' + ? extractedTypeAnnotation.elementType.typeName.name + : extractedTypeAnnotation.elementType?.type || + extractedTypeAnnotation.typeName?.name || + extractedTypeAnnotation.type; + + switch (type) { + case 'TSNumberKeyword': + return { + type: 'FloatTypeAnnotation', + }; + case 'ImageSource': + return { + type: 'ReservedPropTypeAnnotation', + name: 'ImageSourcePrimitive', + }; + case 'ColorValue': + case 'ProcessedColorValue': + return { + type: 'ReservedPropTypeAnnotation', + name: 'ColorPrimitive', + }; + case 'PointValue': + return { + type: 'ReservedPropTypeAnnotation', + name: 'PointPrimitive', + }; + case 'EdgeInsetsValue': + return { + type: 'ReservedPropTypeAnnotation', + name: 'EdgeInsetsPrimitive', + }; + case 'Stringish': + return { + type: 'StringTypeAnnotation', + }; + case 'Int32': + return { + type: 'Int32TypeAnnotation', + }; + case 'Double': + return { + type: 'DoubleTypeAnnotation', + }; + case 'Float': + return { + type: 'FloatTypeAnnotation', + }; + case 'TSBooleanKeyword': + return { + type: 'BooleanTypeAnnotation', + }; + case 'TSStringKeyword': + return { + type: 'StringTypeAnnotation', + }; + case 'TSUnionType': + typeAnnotation.types.reduce((lastType, currType) => { + const lastFlattenedType = + lastType && lastType.type === 'TSLiteralType' + ? lastType.literal.type + : lastType.type; + const currFlattenedType = + currType.type === 'TSLiteralType' + ? currType.literal.type + : currType.type; + + if (lastFlattenedType && currFlattenedType !== lastFlattenedType) { + throw new Error(`Mixed types are not supported (see "${name}")`); + } + return currType; + }); + + if (defaultValue === null) { + throw new Error(`A default enum value is required for "${name}"`); + } + + const unionType = typeAnnotation.types[0].type; + if ( + unionType === 'TSLiteralType' && + typeAnnotation.types[0].literal?.type === 'StringLiteral' + ) { + return { + type: 'StringEnumTypeAnnotation', + default: (defaultValue: string), + options: typeAnnotation.types.map(option => option.literal.value), + }; + } else if ( + unionType === 'TSLiteralType' && + typeAnnotation.types[0].literal?.type === 'NumericLiteral' + ) { + throw new Error( + `Arrays of int enums are not supported (see: "${name}")`, + ); + } else { + throw new Error( + `Unsupported union type for "${name}", received "${ + unionType === 'TSLiteralType' + ? typeAnnotation.types[0].literal?.type + : unionType + }"`, + ); + } + default: + (type: empty); + throw new Error(`Unknown prop type for "${name}": ${type}`); + } +} + +function getTypeAnnotation( + name: string, + annotation: $FlowFixMe | ASTNode, + defaultValue: $FlowFixMe | null, + withNullDefault: boolean, + types: TypeDeclarationMap, + buildSchema: (property: PropAST, types: TypeDeclarationMap) => ?NamedShape, +): $FlowFixMe { + const typeAnnotation = getValueFromTypes(annotation, types); + + // Covers: (T) + if (typeAnnotation.type === 'TSParenthesizedType') { + return getTypeAnnotation( + name, + typeAnnotation.typeAnnotation, + defaultValue, + withNullDefault, + types, + buildSchema, + ); + } + + // Covers: readonly T[] + if ( + typeAnnotation.type === 'TSTypeOperator' && + typeAnnotation.operator === 'readonly' && + typeAnnotation.typeAnnotation.type === 'TSArrayType' + ) { + return { + type: 'ArrayTypeAnnotation', + elementType: getTypeAnnotationForArray( + name, + typeAnnotation.typeAnnotation.elementType, + defaultValue, + types, + buildSchema, + ), + }; + } + + // Covers: ReadonlyArray + if ( + typeAnnotation.type === 'TSTypeReference' && + typeAnnotation.typeName.name === 'ReadonlyArray' + ) { + return { + type: 'ArrayTypeAnnotation', + elementType: getTypeAnnotationForArray( + name, + typeAnnotation.typeParameters.params[0], + defaultValue, + types, + buildSchema, + ), + }; + } + + // Covers: Readonly + if ( + typeAnnotation.type === 'TSTypeReference' && + typeAnnotation.typeName?.name === 'Readonly' && + typeAnnotation.typeParameters.type === 'TSTypeParameterInstantiation' && + typeAnnotation.typeParameters.params[0].type === 'TSArrayType' + ) { + return { + type: 'ArrayTypeAnnotation', + elementType: getTypeAnnotationForArray( + name, + typeAnnotation.typeParameters.params[0], + defaultValue, + types, + buildSchema, + ), + }; + } + + if ( + (typeAnnotation.type === 'TSTypeReference' || + typeAnnotation.type === 'TSTypeLiteral') && + typeAnnotation.typeName?.name === 'Readonly' + ) { + const rawProperties = + typeAnnotation.typeParameters.params[0].members || + (typeAnnotation.typeParameters.params[0].types && + typeAnnotation.typeParameters.params[0].types[0].members) || + typeAnnotation.typeParameters.params; + + const flattenedProperties = flattenProperties(rawProperties, types); + + const properties = flattenedProperties + .map(prop => buildSchema(prop, types)) + .filter(Boolean); + + return { + type: 'ObjectTypeAnnotation', + properties, + }; + } + + const type = + typeAnnotation.type === 'TSTypeReference' || + typeAnnotation.type === 'TSTypeAliasDeclaration' + ? typeAnnotation.typeName.name + : typeAnnotation.type; + + switch (type) { + case 'ImageSource': + return { + type: 'ReservedPropTypeAnnotation', + name: 'ImageSourcePrimitive', + }; + case 'ColorValue': + case 'ProcessedColorValue': + return { + type: 'ReservedPropTypeAnnotation', + name: 'ColorPrimitive', + }; + case 'ColorArrayValue': + return { + type: 'ArrayTypeAnnotation', + elementType: { + type: 'ReservedPropTypeAnnotation', + name: 'ColorPrimitive', + }, + }; + case 'PointValue': + return { + type: 'ReservedPropTypeAnnotation', + name: 'PointPrimitive', + }; + case 'EdgeInsetsValue': + return { + type: 'ReservedPropTypeAnnotation', + name: 'EdgeInsetsPrimitive', + }; + case 'Int32': + return { + type: 'Int32TypeAnnotation', + default: ((defaultValue ? defaultValue : 0): number), + }; + case 'Double': + return { + type: 'DoubleTypeAnnotation', + default: ((defaultValue ? defaultValue : 0): number), + }; + case 'Float': + return { + type: 'FloatTypeAnnotation', + default: withNullDefault + ? (defaultValue: number | null) + : ((defaultValue ? defaultValue : 0): number), + }; + case 'TSBooleanKeyword': + return { + type: 'BooleanTypeAnnotation', + default: withNullDefault + ? (defaultValue: boolean | null) + : ((defaultValue == null ? false : defaultValue): boolean), + }; + case 'TSStringKeyword': + if (typeof defaultValue !== 'undefined') { + return { + type: 'StringTypeAnnotation', + default: (defaultValue: string | null), + }; + } + throw new Error(`A default string (or null) is required for "${name}"`); + case 'Stringish': + if (typeof defaultValue !== 'undefined') { + return { + type: 'StringTypeAnnotation', + default: (defaultValue: string | null), + }; + } + throw new Error(`A default string (or null) is required for "${name}"`); + case 'TSUnionType': + typeAnnotation.types.reduce((lastType, currType) => { + const lastFlattenedType = + lastType && lastType.type === 'TSLiteralType' + ? lastType.literal.type + : lastType.type; + const currFlattenedType = + currType.type === 'TSLiteralType' + ? currType.literal.type + : currType.type; + + if (lastFlattenedType && currFlattenedType !== lastFlattenedType) { + throw new Error(`Mixed types are not supported (see "${name}")`); + } + return currType; + }); + + if (defaultValue === null) { + throw new Error(`A default enum value is required for "${name}"`); + } + + const unionType = typeAnnotation.types[0].type; + if ( + unionType === 'TSLiteralType' && + typeAnnotation.types[0].literal?.type === 'StringLiteral' + ) { + return { + type: 'StringEnumTypeAnnotation', + default: (defaultValue: string), + options: typeAnnotation.types.map(option => option.literal.value), + }; + } else if ( + unionType === 'TSLiteralType' && + typeAnnotation.types[0].literal?.type === 'NumericLiteral' + ) { + return { + type: 'Int32EnumTypeAnnotation', + default: (defaultValue: number), + options: typeAnnotation.types.map(option => option.literal.value), + }; + } else { + throw new Error( + `Unsupported union type for "${name}", received "${ + unionType === 'TSLiteralType' + ? typeAnnotation.types[0].literal?.type + : unionType + }"`, + ); + } + case 'TSNumberKeyword': + throw new Error( + `Cannot use "${type}" type annotation for "${name}": must use a specific numeric type like Int32, Double, or Float`, + ); + default: + (type: empty); + throw new Error(`Unknown prop type for "${name}": "${type}"`); + } +} + +function findProp( + name: string, + typeAnnotation: $FlowFixMe, + optionalType: boolean, +) { + switch (typeAnnotation.type) { + // Check for (T) + case 'TSParenthesizedType': + return findProp(name, typeAnnotation.typeAnnotation, optionalType); + + // Check for optional type in union e.g. T | null | undefined + case 'TSUnionType': + return findProp( + name, + typeAnnotation.types.filter( + t => t.type !== 'TSNullKeyword' && t.type !== 'TSUndefinedKeyword', + )[0], + optionalType || + typeAnnotation.types.some( + t => t.type === 'TSNullKeyword' || t.type === 'TSUndefinedKeyword', + ), + ); + + case 'TSTypeReference': + // Check against optional type inside `WithDefault` + if (typeAnnotation.typeName.name === 'WithDefault' && optionalType) { + throw new Error( + 'WithDefault<> is optional and does not need to be marked as optional. Please remove the union of undefined and/or null', + ); + } + // Remove unwanted types + if ( + typeAnnotation.typeName.name === 'DirectEventHandler' || + typeAnnotation.typeName.name === 'BubblingEventHandler' + ) { + return null; + } + if ( + name === 'style' && + typeAnnotation.type === 'GenericTypeAnnotation' && + typeAnnotation.typeName.name === 'ViewStyleProp' + ) { + return null; + } + return {typeAnnotation, optionalType}; + default: + return {typeAnnotation, optionalType}; + } +} + +type SchemaInfo = { + name: string, + optional: boolean, + typeAnnotation: $FlowFixMe, + defaultValue: $FlowFixMe, + withNullDefault: boolean, +}; + +function getSchemaInfo( + property: PropAST, + types: TypeDeclarationMap, +): ?SchemaInfo { + const name = property.key.name; + + const value = getValueFromTypes( + property.typeAnnotation.typeAnnotation, + types, + ); + + const foundProp = findProp(name, value, false); + if (!foundProp) { + return null; + } + let {typeAnnotation, optionalType} = foundProp; + let optional = property.optional || optionalType; + + // example: Readonly<{prop: string} | null | undefined>; + if ( + value.type === 'TSTypeReference' && + typeAnnotation.typeParameters?.params[0].type === 'TSUnionType' && + typeAnnotation.typeParameters?.params[0].types.some( + element => + element.type === 'TSNullKeyword' || + element.type === 'TSUndefinedKeyword', + ) + ) { + optional = true; + } + + if ( + !property.optional && + value.type === 'TSTypeReference' && + typeAnnotation.typeName.name === 'WithDefault' + ) { + throw new Error( + `key ${name} must be optional if used with WithDefault<> annotation`, + ); + } + + let type = typeAnnotation.type; + let defaultValue = null; + let withNullDefault = false; + if ( + type === 'TSTypeReference' && + typeAnnotation.typeName.name === 'WithDefault' + ) { + if (typeAnnotation.typeParameters.params.length === 1) { + throw new Error( + `WithDefault requires two parameters, did you forget to provide a default value for "${name}"?`, + ); + } + + let defaultValueType = typeAnnotation.typeParameters.params[1].type; + defaultValue = typeAnnotation.typeParameters.params[1].value; + + if (defaultValueType === 'TSLiteralType') { + defaultValueType = typeAnnotation.typeParameters.params[1].literal.type; + defaultValue = typeAnnotation.typeParameters.params[1].literal.value; + } + + if (defaultValueType === 'TSNullKeyword') { + defaultValue = null; + withNullDefault = true; + } + + typeAnnotation = typeAnnotation.typeParameters.params[0]; + type = + typeAnnotation.type === 'TSTypeReference' + ? typeAnnotation.typeName.name + : typeAnnotation.type; + } + + return { + name, + optional, + typeAnnotation, + defaultValue, + withNullDefault, + }; +} + +// $FlowFixMe[unclear-type] TODO(T108222691): Use flow-types for @babel/parser +type PropAST = Object; + +function verifyPropNotAlreadyDefined( + props: $ReadOnlyArray, + needleProp: PropAST, +) { + const propName = needleProp.key.name; + const foundProp = props.some(prop => prop.key.name === propName); + if (foundProp) { + throw new Error(`A prop was already defined with the name ${propName}`); + } +} + +function flattenProperties( + typeDefinition: $ReadOnlyArray, + types: TypeDeclarationMap, +): $ReadOnlyArray { + return typeDefinition + .map(property => { + if (property.type === 'TSPropertySignature') { + return property; + } else if (property.type === 'TSTypeReference') { + return flattenProperties( + getProperties(property.typeName.name, types), + types, + ); + } else if (property.type === 'TSExpressionWithTypeArguments') { + return flattenProperties( + getProperties(property.expression.name, types), + types, + ); + } + }) + .filter(Boolean) + .reduce((acc, item) => { + if (Array.isArray(item)) { + item.forEach(prop => { + verifyPropNotAlreadyDefined(acc, prop); + }); + return acc.concat(item); + } else { + verifyPropNotAlreadyDefined(acc, item); + acc.push(item); + return acc; + } + }, []) + .filter(Boolean); +} + +module.exports = { + getProperties, + getSchemaInfo, + getTypeAnnotation, + flattenProperties, +}; diff --git a/packages/react-native-codegen/src/parsers/typescript/components/index.js b/packages/react-native-codegen/src/parsers/typescript/components/index.js index 77258ed4b9c2db..e1838570baaf93 100644 --- a/packages/react-native-codegen/src/parsers/typescript/components/index.js +++ b/packages/react-native-codegen/src/parsers/typescript/components/index.js @@ -16,9 +16,11 @@ import type {ComponentSchemaBuilderConfig} from './schema.js'; const {getTypes} = require('../utils'); const {getCommands} = require('./commands'); const {getEvents} = require('./events'); +const {getState} = require('./states'); const {getExtendsProps, removeKnownExtends} = require('./extends'); const {getCommandOptions, getOptions} = require('./options'); -const {getPropProperties, getProps} = require('./props'); +const {getProps} = require('./props'); +const {getProperties} = require('./componentsUtils.js'); /* $FlowFixMe[missing-local-annot] The type annotation(s) required by Flow's * LTI update could not be added via codemod */ @@ -111,8 +113,33 @@ function findComponentConfig(ast) { throw new Error('codegenNativeCommands may only be called once in a file'); } + const unexportedStateTypes: Array = ast.body + .filter( + node => + node.type === 'TSInterfaceDeclaration' && + node.id.name.indexOf('NativeState') >= 0, + ) + .map(node => node.id.name); + + const exportedStateTypes: Array = namedExports + .filter( + node => + node.declaration.id && + node.declaration.id.name.indexOf('NativeState') >= 0, + ) + .map(node => node.declaration.id.name); + + const stateTypeName = exportedStateTypes.concat(unexportedStateTypes); + + if (Array.isArray(stateTypeName) && stateTypeName.length > 1) { + throw new Error( + `Found ${stateTypeName.length} NativeStates for ${foundConfig.componentName}. Each component can have only 1 NativeState`, + ); + } + return { ...foundConfig, + stateTypeName: stateTypeName.length === 1 ? stateTypeName[0] : '', commandTypeName: commandsTypeNames[0] == null ? null @@ -186,6 +213,7 @@ function buildComponentSchema(ast): ComponentSchemaBuilderConfig { const { componentName, propsTypeName, + stateTypeName, commandTypeName, commandOptionsExpression, optionsExpression, @@ -193,7 +221,7 @@ function buildComponentSchema(ast): ComponentSchemaBuilderConfig { const types = getTypes(ast); - const propProperties = getPropProperties(propsTypeName, types); + const propProperties = getProperties(propsTypeName, types); const commandOptions = getCommandOptions(commandOptionsExpression); const commandProperties = getCommandProperties( @@ -210,7 +238,7 @@ function buildComponentSchema(ast): ComponentSchemaBuilderConfig { const events = getEvents(propProperties, types); const commands = getCommands(commandProperties, types); - return { + const toRet = { filename: componentName, componentName, options, @@ -219,6 +247,17 @@ function buildComponentSchema(ast): ComponentSchemaBuilderConfig { props, commands, }; + + if (stateTypeName) { + const stateProperties = getProperties(stateTypeName, types); + const state = getState(stateProperties, types); + return { + ...toRet, + state, + }; + } + + return toRet; } module.exports = { diff --git a/packages/react-native-codegen/src/parsers/typescript/components/props.js b/packages/react-native-codegen/src/parsers/typescript/components/props.js index ca95b56b7e5047..4ad1d288f1cc15 100644 --- a/packages/react-native-codegen/src/parsers/typescript/components/props.js +++ b/packages/react-native-codegen/src/parsers/typescript/components/props.js @@ -9,601 +9,27 @@ */ 'use strict'; -import type {ASTNode} from '../utils'; - -const {getValueFromTypes} = require('../utils.js'); +const { + flattenProperties, + getSchemaInfo, + getTypeAnnotation, +} = require('./componentsUtils.js'); import type {NamedShape, PropTypeAnnotation} from '../../../CodegenSchema.js'; import type {TypeDeclarationMap} from '../utils.js'; -function getPropProperties( - propsTypeName: string, - types: TypeDeclarationMap, -): $FlowFixMe { - const alias = types[propsTypeName]; - if (!alias) { - throw new Error( - `Failed to find definition for "${propsTypeName}", please check that you have a valid codegen typescript file`, - ); - } - const aliasKind = - alias.type === 'TSInterfaceDeclaration' ? 'interface' : 'type'; - - try { - if (aliasKind === 'interface') { - return [...(alias.extends ?? []), ...alias.body.body]; - } - - return ( - alias.typeAnnotation.members || - alias.typeAnnotation.typeParameters.params[0].members || - alias.typeAnnotation.typeParameters.params - ); - } catch (e) { - throw new Error( - `Failed to find ${aliasKind} definition for "${propsTypeName}", please check that you have a valid codegen typescript file`, - ); - } -} - -function getTypeAnnotationForObjectAsArrayElement( - objectType: $FlowFixMe, - types: TypeDeclarationMap, -) { - return { - type: 'ObjectTypeAnnotation', - properties: flattenProperties( - objectType.typeParameters.params[0].members || - objectType.typeParameters.params, - types, - ) - .map(prop => buildPropSchema(prop, types)) - .filter(Boolean), - }; -} - -function getTypeAnnotationForArrayOfArrayOfObject( - typeAnnotation: $FlowFixMe, - types: TypeDeclarationMap, -) { - // We need to go yet another level deeper to resolve - // types that may be defined in a type alias - const nestedObjectType = getValueFromTypes(typeAnnotation, types); - - return { - type: 'ArrayTypeAnnotation', - elementType: getTypeAnnotationForObjectAsArrayElement( - nestedObjectType, - types, - ), - }; -} - -function getTypeAnnotationForArray( - name: string, - typeAnnotation: $FlowFixMe, - defaultValue: $FlowFixMe | null, - types: TypeDeclarationMap, -) { - if (typeAnnotation.type === 'TSParenthesizedType') { - return getTypeAnnotationForArray( - name, - typeAnnotation.typeAnnotation, - defaultValue, - types, - ); - } - - const extractedTypeAnnotation = getValueFromTypes(typeAnnotation, types); - - if ( - extractedTypeAnnotation.type === 'TSUnionType' && - extractedTypeAnnotation.types.some( - t => t.type === 'TSNullKeyword' || t.type === 'TSUndefinedKeyword', - ) - ) { - throw new Error( - 'Nested optionals such as "ReadonlyArray" are not supported, please declare optionals at the top level of value definitions as in "ReadonlyArray | null | undefined"', - ); - } - - if ( - extractedTypeAnnotation.type === 'TSTypeReference' && - extractedTypeAnnotation.typeName.name === 'WithDefault' - ) { - throw new Error( - 'Nested defaults such as "ReadonlyArray>" are not supported, please declare defaults at the top level of value definitions as in "WithDefault, false>"', - ); - } - - // Covers: T[] - if (typeAnnotation.type === 'TSArrayType') { - return getTypeAnnotationForArrayOfArrayOfObject( - typeAnnotation.elementType, - types, - ); - } - - if (extractedTypeAnnotation.type === 'TSTypeReference') { - // Resolve the type alias if it's not defined inline - const objectType = getValueFromTypes(extractedTypeAnnotation, types); - - if (objectType.typeName.name === 'Readonly') { - return getTypeAnnotationForObjectAsArrayElement(objectType, types); - } - - // Covers: ReadonlyArray - if (objectType.typeName.name === 'ReadonlyArray') { - return getTypeAnnotationForArrayOfArrayOfObject( - objectType.typeParameters.params[0], - types, - ); - } - } - - const type = - extractedTypeAnnotation.elementType === 'TSTypeReference' - ? extractedTypeAnnotation.elementType.typeName.name - : extractedTypeAnnotation.elementType?.type || - extractedTypeAnnotation.typeName?.name || - extractedTypeAnnotation.type; - - switch (type) { - case 'TSNumberKeyword': - return { - type: 'FloatTypeAnnotation', - }; - case 'ImageSource': - return { - type: 'ReservedPropTypeAnnotation', - name: 'ImageSourcePrimitive', - }; - case 'ColorValue': - case 'ProcessedColorValue': - return { - type: 'ReservedPropTypeAnnotation', - name: 'ColorPrimitive', - }; - case 'PointValue': - return { - type: 'ReservedPropTypeAnnotation', - name: 'PointPrimitive', - }; - case 'EdgeInsetsValue': - return { - type: 'ReservedPropTypeAnnotation', - name: 'EdgeInsetsPrimitive', - }; - case 'Stringish': - return { - type: 'StringTypeAnnotation', - }; - case 'Int32': - return { - type: 'Int32TypeAnnotation', - }; - case 'Double': - return { - type: 'DoubleTypeAnnotation', - }; - case 'Float': - return { - type: 'FloatTypeAnnotation', - }; - case 'TSBooleanKeyword': - return { - type: 'BooleanTypeAnnotation', - }; - case 'TSStringKeyword': - return { - type: 'StringTypeAnnotation', - }; - case 'TSUnionType': - typeAnnotation.types.reduce((lastType, currType) => { - const lastFlattenedType = - lastType && lastType.type === 'TSLiteralType' - ? lastType.literal.type - : lastType.type; - const currFlattenedType = - currType.type === 'TSLiteralType' - ? currType.literal.type - : currType.type; - - if (lastFlattenedType && currFlattenedType !== lastFlattenedType) { - throw new Error(`Mixed types are not supported (see "${name}")`); - } - return currType; - }); - - if (defaultValue === null) { - throw new Error(`A default enum value is required for "${name}"`); - } - - const unionType = typeAnnotation.types[0].type; - if ( - unionType === 'TSLiteralType' && - typeAnnotation.types[0].literal?.type === 'StringLiteral' - ) { - return { - type: 'StringEnumTypeAnnotation', - default: (defaultValue: string), - options: typeAnnotation.types.map(option => option.literal.value), - }; - } else if ( - unionType === 'TSLiteralType' && - typeAnnotation.types[0].literal?.type === 'NumericLiteral' - ) { - throw new Error( - `Arrays of int enums are not supported (see: "${name}")`, - ); - } else { - throw new Error( - `Unsupported union type for "${name}", received "${ - unionType === 'TSLiteralType' - ? typeAnnotation.types[0].literal?.type - : unionType - }"`, - ); - } - default: - (type: empty); - throw new Error(`Unknown prop type for "${name}": ${type}`); - } -} - -function getTypeAnnotation( - name: string, - annotation: $FlowFixMe | ASTNode, - defaultValue: $FlowFixMe | null, - withNullDefault: boolean, - types: TypeDeclarationMap, -) { - const typeAnnotation = getValueFromTypes(annotation, types); - - // Covers: (T) - if (typeAnnotation.type === 'TSParenthesizedType') { - return getTypeAnnotation( - name, - typeAnnotation.typeAnnotation, - defaultValue, - withNullDefault, - types, - ); - } - - // Covers: readonly T[] - if ( - typeAnnotation.type === 'TSTypeOperator' && - typeAnnotation.operator === 'readonly' && - typeAnnotation.typeAnnotation.type === 'TSArrayType' - ) { - return { - type: 'ArrayTypeAnnotation', - elementType: getTypeAnnotationForArray( - name, - typeAnnotation.typeAnnotation.elementType, - defaultValue, - types, - ), - }; - } - - // Covers: ReadonlyArray - if ( - typeAnnotation.type === 'TSTypeReference' && - typeAnnotation.typeName.name === 'ReadonlyArray' - ) { - return { - type: 'ArrayTypeAnnotation', - elementType: getTypeAnnotationForArray( - name, - typeAnnotation.typeParameters.params[0], - defaultValue, - types, - ), - }; - } - - // Covers: Readonly - if ( - typeAnnotation.type === 'TSTypeReference' && - typeAnnotation.typeName?.name === 'Readonly' && - typeAnnotation.typeParameters.type === 'TSTypeParameterInstantiation' && - typeAnnotation.typeParameters.params[0].type === 'TSArrayType' - ) { - return { - type: 'ArrayTypeAnnotation', - elementType: getTypeAnnotationForArray( - name, - typeAnnotation.typeParameters.params[0], - defaultValue, - types, - ), - }; - } - - if ( - (typeAnnotation.type === 'TSTypeReference' || - typeAnnotation.type === 'TSTypeLiteral') && - typeAnnotation.typeName?.name === 'Readonly' - ) { - const rawProperties = - typeAnnotation.typeParameters.params[0].members || - (typeAnnotation.typeParameters.params[0].types && - typeAnnotation.typeParameters.params[0].types[0].members) || - typeAnnotation.typeParameters.params; - - const flattenedProperties = flattenProperties(rawProperties, types); - - const properties = flattenedProperties - .map(prop => buildPropSchema(prop, types)) - .filter(Boolean); - - return { - type: 'ObjectTypeAnnotation', - properties, - }; - } - - const type = - typeAnnotation.type === 'TSTypeReference' || - typeAnnotation.type === 'TSTypeAliasDeclaration' - ? typeAnnotation.typeName.name - : typeAnnotation.type; - - switch (type) { - case 'ImageSource': - return { - type: 'ReservedPropTypeAnnotation', - name: 'ImageSourcePrimitive', - }; - case 'ColorValue': - case 'ProcessedColorValue': - return { - type: 'ReservedPropTypeAnnotation', - name: 'ColorPrimitive', - }; - case 'ColorArrayValue': - return { - type: 'ArrayTypeAnnotation', - elementType: { - type: 'ReservedPropTypeAnnotation', - name: 'ColorPrimitive', - }, - }; - case 'PointValue': - return { - type: 'ReservedPropTypeAnnotation', - name: 'PointPrimitive', - }; - case 'EdgeInsetsValue': - return { - type: 'ReservedPropTypeAnnotation', - name: 'EdgeInsetsPrimitive', - }; - case 'Int32': - return { - type: 'Int32TypeAnnotation', - default: ((defaultValue ? defaultValue : 0): number), - }; - case 'Double': - return { - type: 'DoubleTypeAnnotation', - default: ((defaultValue ? defaultValue : 0): number), - }; - case 'Float': - return { - type: 'FloatTypeAnnotation', - default: withNullDefault - ? (defaultValue: number | null) - : ((defaultValue ? defaultValue : 0): number), - }; - case 'TSBooleanKeyword': - return { - type: 'BooleanTypeAnnotation', - default: withNullDefault - ? (defaultValue: boolean | null) - : ((defaultValue == null ? false : defaultValue): boolean), - }; - case 'TSStringKeyword': - if (typeof defaultValue !== 'undefined') { - return { - type: 'StringTypeAnnotation', - default: (defaultValue: string | null), - }; - } - throw new Error(`A default string (or null) is required for "${name}"`); - case 'Stringish': - if (typeof defaultValue !== 'undefined') { - return { - type: 'StringTypeAnnotation', - default: (defaultValue: string | null), - }; - } - throw new Error(`A default string (or null) is required for "${name}"`); - case 'TSUnionType': - typeAnnotation.types.reduce((lastType, currType) => { - const lastFlattenedType = - lastType && lastType.type === 'TSLiteralType' - ? lastType.literal.type - : lastType.type; - const currFlattenedType = - currType.type === 'TSLiteralType' - ? currType.literal.type - : currType.type; - - if (lastFlattenedType && currFlattenedType !== lastFlattenedType) { - throw new Error(`Mixed types are not supported (see "${name}")`); - } - return currType; - }); - - if (defaultValue === null) { - throw new Error(`A default enum value is required for "${name}"`); - } - - const unionType = typeAnnotation.types[0].type; - if ( - unionType === 'TSLiteralType' && - typeAnnotation.types[0].literal?.type === 'StringLiteral' - ) { - return { - type: 'StringEnumTypeAnnotation', - default: (defaultValue: string), - options: typeAnnotation.types.map(option => option.literal.value), - }; - } else if ( - unionType === 'TSLiteralType' && - typeAnnotation.types[0].literal?.type === 'NumericLiteral' - ) { - return { - type: 'Int32EnumTypeAnnotation', - default: (defaultValue: number), - options: typeAnnotation.types.map(option => option.literal.value), - }; - } else { - throw new Error( - `Unsupported union type for "${name}", received "${ - unionType === 'TSLiteralType' - ? typeAnnotation.types[0].literal?.type - : unionType - }"`, - ); - } - case 'TSNumberKeyword': - throw new Error( - `Cannot use "${type}" type annotation for "${name}": must use a specific numeric type like Int32, Double, or Float`, - ); - default: - (type: empty); - throw new Error(`Unknown prop type for "${name}": "${type}"`); - } -} - -function findProp( - name: string, - typeAnnotation: $FlowFixMe, - optionalType: boolean, -) { - switch (typeAnnotation.type) { - // Check for (T) - case 'TSParenthesizedType': - return findProp(name, typeAnnotation.typeAnnotation, optionalType); - - // Check for optional type in union e.g. T | null | undefined - case 'TSUnionType': - return findProp( - name, - typeAnnotation.types.filter( - t => t.type !== 'TSNullKeyword' && t.type !== 'TSUndefinedKeyword', - )[0], - optionalType || - typeAnnotation.types.some( - t => t.type === 'TSNullKeyword' || t.type === 'TSUndefinedKeyword', - ), - ); - - case 'TSTypeReference': - // Check against optional type inside `WithDefault` - if (typeAnnotation.typeName.name === 'WithDefault' && optionalType) { - throw new Error( - 'WithDefault<> is optional and does not need to be marked as optional. Please remove the union of undefined and/or null', - ); - } - // Remove unwanted types - if ( - typeAnnotation.typeName.name === 'DirectEventHandler' || - typeAnnotation.typeName.name === 'BubblingEventHandler' - ) { - return null; - } - if ( - name === 'style' && - typeAnnotation.type === 'GenericTypeAnnotation' && - typeAnnotation.typeName.name === 'ViewStyleProp' - ) { - return null; - } - return {typeAnnotation, optionalType}; - default: - return {typeAnnotation, optionalType}; - } -} +// $FlowFixMe[unclear-type] there's no flowtype for ASTs +type PropAST = Object; function buildPropSchema( property: PropAST, types: TypeDeclarationMap, ): ?NamedShape { - const name = property.key.name; - - const value = getValueFromTypes( - property.typeAnnotation.typeAnnotation, - types, - ); - - const foundProp = findProp(name, value, false); - if (!foundProp) { + const info = getSchemaInfo(property, types); + if (info == null) { return null; } - let {typeAnnotation, optionalType} = foundProp; - let optional = property.optional || optionalType; - - // example: Readonly<{prop: string} | null | undefined>; - if ( - value.type === 'TSTypeReference' && - typeAnnotation.typeParameters?.params[0].type === 'TSUnionType' && - typeAnnotation.typeParameters?.params[0].types.some( - element => - element.type === 'TSNullKeyword' || - element.type === 'TSUndefinedKeyword', - ) - ) { - optional = true; - } - - if ( - !property.optional && - value.type === 'TSTypeReference' && - typeAnnotation.typeName.name === 'WithDefault' - ) { - throw new Error( - `key ${name} must be optional if used with WithDefault<> annotation`, - ); - } - - let type = typeAnnotation.type; - let defaultValue = null; - let withNullDefault = false; - if ( - type === 'TSTypeReference' && - typeAnnotation.typeName.name === 'WithDefault' - ) { - if (typeAnnotation.typeParameters.params.length === 1) { - throw new Error( - `WithDefault requires two parameters, did you forget to provide a default value for "${name}"?`, - ); - } - - let defaultValueType = typeAnnotation.typeParameters.params[1].type; - defaultValue = typeAnnotation.typeParameters.params[1].value; - - if (defaultValueType === 'TSLiteralType') { - defaultValueType = typeAnnotation.typeParameters.params[1].literal.type; - defaultValue = typeAnnotation.typeParameters.params[1].literal.value; - } - - if (defaultValueType === 'TSNullKeyword') { - defaultValue = null; - withNullDefault = true; - } - - typeAnnotation = typeAnnotation.typeParameters.params[0]; - type = - typeAnnotation.type === 'TSTypeReference' - ? typeAnnotation.typeName.name - : typeAnnotation.type; - } - + const {name, optional, typeAnnotation, defaultValue, withNullDefault} = info; return { name, optional, @@ -613,72 +39,20 @@ function buildPropSchema( defaultValue, withNullDefault, types, + buildPropSchema, ), }; } -// $FlowFixMe[unclear-type] TODO(T108222691): Use flow-types for @babel/parser -type PropAST = Object; - -function verifyPropNotAlreadyDefined( - props: $ReadOnlyArray, - needleProp: PropAST, -) { - const propName = needleProp.key.name; - const foundProp = props.some(prop => prop.key.name === propName); - if (foundProp) { - throw new Error(`A prop was already defined with the name ${propName}`); - } -} - -function flattenProperties( - typeDefinition: $ReadOnlyArray, - types: TypeDeclarationMap, -) { - return typeDefinition - .map(property => { - if (property.type === 'TSPropertySignature') { - return property; - } else if (property.type === 'TSTypeReference') { - return flattenProperties( - getPropProperties(property.typeName.name, types), - types, - ); - } else if (property.type === 'TSExpressionWithTypeArguments') { - return flattenProperties( - getPropProperties(property.expression.name, types), - types, - ); - } - }) - .filter(Boolean) - .reduce((acc, item) => { - if (Array.isArray(item)) { - item.forEach(prop => { - verifyPropNotAlreadyDefined(acc, prop); - }); - return acc.concat(item); - } else { - verifyPropNotAlreadyDefined(acc, item); - acc.push(item); - return acc; - } - }, []) - .filter(Boolean); -} - function getProps( typeDefinition: $ReadOnlyArray, types: TypeDeclarationMap, ): $ReadOnlyArray> { return flattenProperties(typeDefinition, types) - .map(property => { - return buildPropSchema(property, types); - }) + .map(property => buildPropSchema(property, types)) .filter(Boolean); } module.exports = { getProps, - getPropProperties, }; diff --git a/packages/react-native-codegen/src/parsers/typescript/components/schema.js b/packages/react-native-codegen/src/parsers/typescript/components/schema.js index ed6223c3347b50..e7bff107dbeba4 100644 --- a/packages/react-native-codegen/src/parsers/typescript/components/schema.js +++ b/packages/react-native-codegen/src/parsers/typescript/components/schema.js @@ -15,6 +15,7 @@ import type { NamedShape, CommandTypeAnnotation, PropTypeAnnotation, + StateTypeAnnotation, ExtendsPropsShape, SchemaType, OptionsShape, @@ -27,6 +28,7 @@ export type ComponentSchemaBuilderConfig = $ReadOnly<{ events: $ReadOnlyArray, props: $ReadOnlyArray>, commands: $ReadOnlyArray>, + state?: $ReadOnlyArray>, options?: ?OptionsShape, }>; @@ -36,6 +38,7 @@ function wrapComponentSchema({ extendsProps, events, props, + state, options, commands, }: ComponentSchemaBuilderConfig): SchemaType { @@ -50,6 +53,7 @@ function wrapComponentSchema({ events, props, commands, + state, }, }, }, diff --git a/packages/react-native-codegen/src/parsers/typescript/components/states.js b/packages/react-native-codegen/src/parsers/typescript/components/states.js new file mode 100644 index 00000000000000..60eeda52942f95 --- /dev/null +++ b/packages/react-native-codegen/src/parsers/typescript/components/states.js @@ -0,0 +1,58 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow strict-local + * @format + */ + +'use strict'; +const { + flattenProperties, + getSchemaInfo, + getTypeAnnotation, +} = require('./componentsUtils.js'); + +import type {StateTypeAnnotation, NamedShape} from '../../../CodegenSchema.js'; +import type {TypeDeclarationMap} from '../utils.js'; + +// $FlowFixMe[unclear-type] there's no flowtype for ASTs +type PropAST = Object; + +function buildStateSchema( + property: PropAST, + types: TypeDeclarationMap, +): ?NamedShape { + const info = getSchemaInfo(property, types); + if (info == null) { + return null; + } + const {name, optional, typeAnnotation, defaultValue, withNullDefault} = info; + return { + name, + optional, + typeAnnotation: getTypeAnnotation( + name, + typeAnnotation, + defaultValue, + withNullDefault, + types, + buildStateSchema, + ), + }; +} + +function getState( + typeDefinition: $ReadOnlyArray, + types: TypeDeclarationMap, +): $ReadOnlyArray> { + return flattenProperties(typeDefinition, types) + .map(property => buildStateSchema(property, types)) + .filter(Boolean); +} + +module.exports = { + getState, +};