From e98a835bfc7b01bccb1b7cdee94db248a0a90607 Mon Sep 17 00:00:00 2001 From: Samuel Susla Date: Fri, 15 Jul 2022 06:42:50 -0700 Subject: [PATCH 0001/1165] Fix default value for scrollView.contentInsetAdjustmentBehavior Summary: Changelog: [internal] The dafault UIKit value of `UIScrollView.contentInsetAdjustmentBehavior` is automatic. Fabric had incorrect value never. source: https://developer.apple.com/documentation/uikit/uiscrollview/2902261-contentinsetadjustmentbehavior?language=objc This was causing bug for one navigation library that's migrating to Fabric: https://github.com/reactwg/react-native-new-architecture/discussions/43#discussioncomment-2885450 Reviewed By: javache Differential Revision: D37881453 fbshipit-source-id: 290ae428a720f00ed61f2a3e5c2c9bbf54e1ac6e --- .../react/renderer/components/scrollview/ScrollViewProps.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ReactCommon/react/renderer/components/scrollview/ScrollViewProps.h b/ReactCommon/react/renderer/components/scrollview/ScrollViewProps.h index bd53bc4bb22d..8c5876d999b4 100644 --- a/ReactCommon/react/renderer/components/scrollview/ScrollViewProps.h +++ b/ReactCommon/react/renderer/components/scrollview/ScrollViewProps.h @@ -63,7 +63,7 @@ class ScrollViewProps final : public ViewProps { bool snapToStart{true}; bool snapToEnd{true}; ContentInsetAdjustmentBehavior contentInsetAdjustmentBehavior{ - ContentInsetAdjustmentBehavior::Never}; + ContentInsetAdjustmentBehavior::Automatic}; bool scrollToOverflowEnabled{false}; #pragma mark - DebugStringConvertible From 191eb62edb58bc8e934226f4cbd4829c88958455 Mon Sep 17 00:00:00 2001 From: Garrett Forbes Monroe Date: Fri, 15 Jul 2022 08:20:20 -0700 Subject: [PATCH 0002/1165] Revert D37801394: Multisect successfully blamed D37801394 for test or build failures Summary: This diff is reverting D37801394 (https://github.com/facebook/react-native/commit/51f49ca9982f24de08f5a5654a5210e547bb5b86) D37801394 (https://github.com/facebook/react-native/commit/51f49ca9982f24de08f5a5654a5210e547bb5b86) has been identified to be causing the following test or build failures: Tests affected: - https://www.internalfb.com/intern/test/844424989736255/ Here's the Multisect link: https://www.internalfb.com/intern/testinfra/multisect/1062919 Here are the tasks that are relevant to this breakage: T116036972: 105 tests started failing for oncall bridgeless_jest_e2e_tests in the last 2 weeks We're generating a revert to back out the changes in this diff, please note the backout may land if someone accepts it. **To Address Land blocker from previous version (see pic):** {F752642767} ``` Changelog: [General][Change] - Revert breaking change in MPay order creation screen (user input in duplicated, and then not deletable. See T126127801 for more details) ``` Reviewed By: philIip Differential Revision: D37863306 fbshipit-source-id: 24f2448d7bc9761ec31edd6f6b97c668171027d3 --- Libraries/Components/TextInput/TextInput.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/Libraries/Components/TextInput/TextInput.js b/Libraries/Components/TextInput/TextInput.js index cb71d97bd1d4..8fa117192fa0 100644 --- a/Libraries/Components/TextInput/TextInput.js +++ b/Libraries/Components/TextInput/TextInput.js @@ -976,8 +976,6 @@ function InternalTextInput(props: Props): React.Node { const text = typeof props.value === 'string' ? props.value - : typeof lastNativeText === 'string' - ? lastNativeText : typeof props.defaultValue === 'string' ? props.defaultValue : ''; From bf54f1cae955df553d2c86083878621005a63af4 Mon Sep 17 00:00:00 2001 From: Samuel Susla Date: Fri, 15 Jul 2022 09:54:35 -0700 Subject: [PATCH 0003/1165] Back out "Fix default value for scrollView.contentInsetAdjustmentBehavior" Summary: changelog: [internal] Original commit changeset: 290ae428a720 Original Phabricator Diff: D37881453 (https://github.com/facebook/react-native/commit/e98a835bfc7b01bccb1b7cdee94db248a0a90607) in the original diff I made a mistake. The default value for RN is never, we override it in one of our subclasses. Reviewed By: cortinico Differential Revision: D37884715 fbshipit-source-id: 3c5b5ef5550120034e33ae9047292f38159dea3e --- .../react/renderer/components/scrollview/ScrollViewProps.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ReactCommon/react/renderer/components/scrollview/ScrollViewProps.h b/ReactCommon/react/renderer/components/scrollview/ScrollViewProps.h index 8c5876d999b4..bd53bc4bb22d 100644 --- a/ReactCommon/react/renderer/components/scrollview/ScrollViewProps.h +++ b/ReactCommon/react/renderer/components/scrollview/ScrollViewProps.h @@ -63,7 +63,7 @@ class ScrollViewProps final : public ViewProps { bool snapToStart{true}; bool snapToEnd{true}; ContentInsetAdjustmentBehavior contentInsetAdjustmentBehavior{ - ContentInsetAdjustmentBehavior::Automatic}; + ContentInsetAdjustmentBehavior::Never}; bool scrollToOverflowEnabled{false}; #pragma mark - DebugStringConvertible From 9ecd203eec97e7d21d10311d950c9f8f30c7a4b1 Mon Sep 17 00:00:00 2001 From: "Zihan Chen (MSFT)" <53799235+ZihanChen-MSFT@users.noreply.github.com> Date: Fri, 15 Jul 2022 20:38:16 -0700 Subject: [PATCH 0004/1165] Accept TypeScript type T | null | undefined as a maybe type of T in turbo module (#34158) Summary: According Flow's document, a maybe type of T means `T | null | undefined`, instead of `T | null | void`. I think keeping TypeScript and Flow being consistent to each other is better. ## Changelog [General] [Changed] - Accept TypeScript type `T | null | undefined` as a maybe type of T in turbo module. Pull Request resolved: https://github.com/facebook/react-native/pull/34158 Test Plan: `yarn jest` passed in `packages/react-native-codegen` Reviewed By: yungsters Differential Revision: D37731169 Pulled By: philIip fbshipit-source-id: b6d9b7e8991f60e12c1004bed5b937b34fb02c47 --- .../components/__test_fixtures__/failures.js | 4 +- .../components/__test_fixtures__/fixtures.js | 170 +++++++++--------- .../parsers/typescript/components/events.js | 14 +- .../parsers/typescript/components/props.js | 15 +- .../modules/__test_fixtures__/failures.js | 4 +- .../modules/__test_fixtures__/fixtures.js | 4 +- .../src/parsers/typescript/utils.js | 6 +- 7 files changed, 109 insertions(+), 108 deletions(-) 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 e473d9a3d82e..eefd9e316f18 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 @@ -141,7 +141,7 @@ import type {ViewProps} from 'ViewPropTypes'; import type {HostComponent} from 'react-native'; interface NativeCommands { - readonly hotspotUpdate: (viewRef: React.Ref<'RCTView'> | null | void, x: Int32, y: Int32) => void; + readonly hotspotUpdate: (viewRef: React.Ref<'RCTView'> | null | undefined, x: Int32, y: Int32) => void; } export interface ModuleProps extends ViewProps { @@ -249,7 +249,7 @@ import type {ViewProps} from 'ViewPropTypes'; import type {HostComponent} from 'react-native'; export interface ModuleProps extends ViewProps { - nullable_with_default: WithDefault | null | void; + nullable_with_default: WithDefault | null | undefined; } export default codegenNativeComponent( 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 136a95e48ce8..cb1357c40127 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 @@ -15,33 +15,33 @@ const EVENT_DEFINITION = ` boolean_required: boolean; boolean_optional_key?: boolean; - boolean_optional_value: boolean | null | void; - boolean_optional_both?: boolean | null | void; + boolean_optional_value: boolean | null | undefined; + boolean_optional_both?: boolean | null | undefined; string_required: string; string_optional_key?: string; - string_optional_value: string | null | void; - string_optional_both?: string | null | void; + string_optional_value: string | null | undefined; + string_optional_both?: string | null | undefined; double_required: Double; double_optional_key?: Double; - double_optional_value: Double | null | void; - double_optional_both?: Double | null | void; + double_optional_value: Double | null | undefined; + double_optional_both?: Double | null | undefined; float_required: Float; float_optional_key?: Float; - float_optional_value: Float | null | void; - float_optional_both?: Float | null | void; + float_optional_value: Float | null | undefined; + float_optional_both?: Float | null | undefined; int32_required: Int32; int32_optional_key?: Int32; - int32_optional_value: Int32 | null | void; - int32_optional_both?: Int32 | null | void; + int32_optional_value: Int32 | null | undefined; + int32_optional_both?: Int32 | null | undefined; enum_required: 'small' | 'large'; enum_optional_key?: 'small' | 'large'; - enum_optional_value: ('small' | 'large') | null | void; - enum_optional_both?: ('small' | 'large') | null | void; + enum_optional_value: ('small' | 'large') | null | undefined; + enum_optional_both?: ('small' | 'large') | null | undefined; object_required: { boolean_required: boolean; @@ -52,21 +52,21 @@ const EVENT_DEFINITION = ` }; object_optional_value: { - float_optional_value: Float | null | void; - } | null | void; + float_optional_value: Float | null | undefined; + } | null | undefined; object_optional_both?: { - int32_optional_both?: Int32 | null | void; - } | null | void; + int32_optional_both?: Int32 | null | undefined; + } | null | undefined; object_required_nested_2_layers: { object_optional_nested_1_layer?: { boolean_required: Int32; string_optional_key?: string; - double_optional_value: Double | null | void; - float_optional_value: Float | null | void; - int32_optional_both?: Int32 | null | void; - } | null | void; + double_optional_value: Double | null | undefined; + float_optional_value: Float | null | undefined; + int32_optional_both?: Int32 | null | undefined; + } | null | undefined; }; object_readonly_required: Readonly<{ @@ -78,12 +78,12 @@ const EVENT_DEFINITION = ` }>; object_readonly_optional_value: Readonly<{ - float_optional_value: Float | null | void; - }> | null | void; + float_optional_value: Float | null | undefined; + }> | null | undefined; object_readonly_optional_both?: Readonly<{ - int32_optional_both?: Int32 | null | void; - }> | null | void; + int32_optional_both?: Int32 | null | undefined; + }> | null | undefined; `; const ONE_OF_EACH_PROP_EVENT_DEFAULT_AND_OPTIONS = ` @@ -265,43 +265,43 @@ export interface ModuleProps extends ViewProps { // Object props object_optional_key?: Readonly<{prop: string}>; - object_optional_both?: Readonly<{prop: string} | null | void>; - object_optional_value: Readonly<{prop: string} | null | void>; + 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 | void; - image_optional_both?: ImageSource | null | void; + 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 | void; - color_optional_both?: ColorValue | null | void; + 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 | void; - color_array_optional_both?: ColorArrayValue | null | void; + 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 | void; - processed_color_optional_both?: ProcessedColorValue | null | void; + 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 | void; - point_optional_both?: PointValue | null | void; + 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 | void; - insets_optional_both?: EdgeInsetsValue | null | void; + insets_optional_value: EdgeInsetsValue | null | undefined; + insets_optional_both?: EdgeInsetsValue | null | undefined; } export default codegenNativeComponent( @@ -342,32 +342,32 @@ export interface ModuleProps extends ViewProps { // Boolean props array_boolean_required: ReadonlyArray; array_boolean_optional_key?: ReadonlyArray; - array_boolean_optional_value: ReadonlyArray | null | void; - array_boolean_optional_both?: ReadonlyArray | null | void; + 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 | void; - array_string_optional_both?: ReadonlyArray | null | void; + 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 | void; - array_double_optional_both?: ReadonlyArray | null | void; + 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 | void; - array_float_optional_both?: ReadonlyArray | null | void; + 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 | void; - array_int32_optional_both?: ReadonlyArray | null | void; + array_int32_optional_value: ReadonlyArray | null | undefined; + array_int32_optional_both?: ReadonlyArray | null | undefined; // String enum props array_enum_optional_key?: WithDefault< @@ -382,32 +382,32 @@ export interface ModuleProps extends ViewProps { // ImageSource props array_image_required: ReadonlyArray; array_image_optional_key?: ReadonlyArray; - array_image_optional_value: ReadonlyArray | null | void; - array_image_optional_both?: ReadonlyArray | null | void; + 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 | void; - array_color_optional_both?: ReadonlyArray | null | void; + 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 | void; - array_point_optional_both?: ReadonlyArray | null | void; + 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 | void; - array_insets_optional_both?: ReadonlyArray | null | void; + 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 | void; - array_object_optional_both?: ReadonlyArray | null | void; + array_object_optional_value: ArrayObjectType | null | undefined; + array_object_optional_both?: ReadonlyArray | null | undefined; // Nested array object types array_of_array_object_required: ReadonlyArray< @@ -426,18 +426,18 @@ export interface ModuleProps extends ViewProps { Readonly<{ // This needs to be the same name as the top level array above array_object_optional_value: ReadonlyArray< - Readonly<{prop: string | null | void}> + Readonly<{prop: string | null | undefined}> >; }> - > | null | void; + > | 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 | void}> + Readonly<{prop?: string | null | undefined}> >; }> - > | null | void; + > | null | undefined; // Nested array of array of object types array_of_array_of_object_required: ReadonlyArray< @@ -514,46 +514,46 @@ export interface ModuleProps extends ViewProps { // ImageSource props image_required: Readonly<{prop: ImageSource}>; image_optional_key: Readonly<{prop?: ImageSource}>; - image_optional_value: Readonly<{prop: ImageSource | null | void}>; - image_optional_both: Readonly<{prop?: ImageSource | null | void}>; + 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 | void}>; - color_optional_both: Readonly<{prop?: ColorValue | null | void}>; + 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 | void; + prop: ProcessedColorValue | null | undefined; }>; processed_color_optional_both: Readonly<{ - prop?: ProcessedColorValue | null | void; + prop?: ProcessedColorValue | null | undefined; }>; // PointValue props point_required: Readonly<{prop: PointValue}>; point_optional_key: Readonly<{prop?: PointValue}>; - point_optional_value: Readonly<{prop: PointValue | null | void}>; - point_optional_both: Readonly<{prop?: PointValue | null | void}>; + 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 | void}>; - insets_optional_both: Readonly<{prop?: EdgeInsetsValue | null | void}>; + 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 | void; + }> | null | undefined; object_optional_both?: Readonly<{ prop: Readonly<{nestedProp: string}>; - }> | null | void; + }> | null | undefined; } export default codegenNativeComponent( @@ -642,20 +642,20 @@ export interface ModuleProps extends ViewProps { Readonly<{ ${EVENT_DEFINITION} }> - > | null | void; + > | null | undefined; onDirectEventDefinedInlineOptionalBoth?: DirectEventHandler< Readonly<{ ${EVENT_DEFINITION} }> - > | null | void; + > | null | undefined; onDirectEventDefinedInlineWithPaperName?: DirectEventHandler< Readonly<{ ${EVENT_DEFINITION} }>, 'paperDirectEventDefinedInlineWithPaperName' - > | null | void; + > | null | undefined; onBubblingEventDefinedInline: BubblingEventHandler< Readonly<{ @@ -673,20 +673,20 @@ export interface ModuleProps extends ViewProps { Readonly<{ ${EVENT_DEFINITION} }> - > | null | void; + > | null | undefined; onBubblingEventDefinedInlineOptionalBoth?: BubblingEventHandler< Readonly<{ ${EVENT_DEFINITION} }> - > | null | void; + > | null | undefined; onBubblingEventDefinedInlineWithPaperName?: BubblingEventHandler< Readonly<{ ${EVENT_DEFINITION} }>, 'paperBubblingEventDefinedInlineWithPaperName' - > | null | void; + > | null | undefined; } export default codegenNativeComponent( @@ -718,21 +718,21 @@ export interface ModuleProps extends ViewProps { // Events defined inline onDirectEventDefinedInlineNull: DirectEventHandler; onDirectEventDefinedInlineNullOptionalKey?: DirectEventHandler; - onDirectEventDefinedInlineNullOptionalValue: DirectEventHandler | null | void; + onDirectEventDefinedInlineNullOptionalValue: DirectEventHandler | null | undefined; onDirectEventDefinedInlineNullOptionalBoth?: DirectEventHandler; onDirectEventDefinedInlineNullWithPaperName?: DirectEventHandler< null, 'paperDirectEventDefinedInlineNullWithPaperName' - > | null | void; + > | null | undefined; onBubblingEventDefinedInlineNull: BubblingEventHandler; onBubblingEventDefinedInlineNullOptionalKey?: BubblingEventHandler; - onBubblingEventDefinedInlineNullOptionalValue: BubblingEventHandler | null | void; - onBubblingEventDefinedInlineNullOptionalBoth?: BubblingEventHandler | null | void; + onBubblingEventDefinedInlineNullOptionalValue: BubblingEventHandler | null | undefined; + onBubblingEventDefinedInlineNullOptionalBoth?: BubblingEventHandler | null | undefined; onBubblingEventDefinedInlineNullWithPaperName?: BubblingEventHandler< null, 'paperBubblingEventDefinedInlineNullWithPaperName' - > | null | void; + > | null | undefined; } export default codegenNativeComponent( diff --git a/packages/react-native-codegen/src/parsers/typescript/components/events.js b/packages/react-native-codegen/src/parsers/typescript/components/events.js index 6f05b5059e97..39649de38eba 100644 --- a/packages/react-native-codegen/src/parsers/typescript/components/events.js +++ b/packages/react-native-codegen/src/parsers/typescript/components/events.js @@ -89,17 +89,17 @@ function getPropertyType( }; case 'TSUnionType': - // Check for + // Check for if ( typeAnnotation.types.some( - t => t.type === 'TSNullKeyword' || t.type === 'TSVoidKeyword', + t => t.type === 'TSNullKeyword' || t.type === 'TSUndefinedKeyword', ) ) { const optionalType = typeAnnotation.types.filter( - t => t.type !== 'TSNullKeyword' && t.type !== 'TSVoidKeyword', + t => t.type !== 'TSNullKeyword' && t.type !== 'TSUndefinedKeyword', )[0]; - // Check for <(T | T2) | null | void> + // Check for <(T | T2) | null | undefined> if (optionalType.type === 'TSParenthesizedType') { return getPropertyType(name, true, optionalType.typeAnnotation); } @@ -201,15 +201,15 @@ function buildEventSchema( let optional = property.optional || false; let typeAnnotation = property.typeAnnotation.typeAnnotation; - // Check for T | null | void + // Check for T | null | undefined if ( typeAnnotation.type === 'TSUnionType' && typeAnnotation.types.some( - t => t.type === 'TSNullKeyword' || t.type === 'TSVoidKeyword', + t => t.type === 'TSNullKeyword' || t.type === 'TSUndefinedKeyword', ) ) { typeAnnotation = typeAnnotation.types.filter( - t => t.type !== 'TSNullKeyword' && t.type !== 'TSVoidKeyword', + t => t.type !== 'TSNullKeyword' && t.type !== 'TSUndefinedKeyword', )[0]; optional = true; } 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 1d58f0d2445a..74659ff0dc6e 100644 --- a/packages/react-native-codegen/src/parsers/typescript/components/props.js +++ b/packages/react-native-codegen/src/parsers/typescript/components/props.js @@ -52,11 +52,11 @@ function getTypeAnnotationForArray( if ( extractedTypeAnnotation.type === 'TSUnionType' && extractedTypeAnnotation.types.some( - t => t.type === 'TSNullKeyword' || t.type === 'TSVoidKeyword', + 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 | void"', + 'Nested optionals such as "ReadonlyArray" are not supported, please declare optionals at the top level of value definitions as in "ReadonlyArray | null | undefined"', ); } @@ -452,15 +452,15 @@ function buildPropSchema( let typeAnnotation = value; let optional = property.optional || false; - // Check for optional type in union e.g. T | null | void + // Check for optional type in union e.g. T | null | undefined if ( typeAnnotation.type === 'TSUnionType' && typeAnnotation.types.some( - t => t.type === 'TSNullKeyword' || t.type === 'TSVoidKeyword', + t => t.type === 'TSNullKeyword' || t.type === 'TSUndefinedKeyword', ) ) { typeAnnotation = typeAnnotation.types.filter( - t => t.type !== 'TSNullKeyword' && t.type !== 'TSVoidKeyword', + t => t.type !== 'TSNullKeyword' && t.type !== 'TSUndefinedKeyword', )[0]; optional = true; @@ -483,13 +483,14 @@ function buildPropSchema( optional = true; } - // example: Readonly<{prop: string} | null | void>; + // 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 === 'TSVoidKeyword', + element.type === 'TSNullKeyword' || + element.type === 'TSUndefinedKeyword', ) ) { optional = true; diff --git a/packages/react-native-codegen/src/parsers/typescript/modules/__test_fixtures__/failures.js b/packages/react-native-codegen/src/parsers/typescript/modules/__test_fixtures__/failures.js index 3015bd715751..f25e8b3d1034 100644 --- a/packages/react-native-codegen/src/parsers/typescript/modules/__test_fixtures__/failures.js +++ b/packages/react-native-codegen/src/parsers/typescript/modules/__test_fixtures__/failures.js @@ -148,11 +148,11 @@ import type {TurboModule} from '../RCTExport'; import * as TurboModuleRegistry from '../TurboModuleRegistry'; export interface Spec extends TurboModule { - readonly getSth: (a: number | null | void) => void; + readonly getSth: (a: number | null | undefined) => void; } export interface Spec2 extends TurboModule { - readonly getSth: (a: number | null | void) => void; + readonly getSth: (a: number | null | undefined) => void; } `; diff --git a/packages/react-native-codegen/src/parsers/typescript/modules/__test_fixtures__/fixtures.js b/packages/react-native-codegen/src/parsers/typescript/modules/__test_fixtures__/fixtures.js index 4530bfe08969..39956142c70e 100644 --- a/packages/react-native-codegen/src/parsers/typescript/modules/__test_fixtures__/fixtures.js +++ b/packages/react-native-codegen/src/parsers/typescript/modules/__test_fixtures__/fixtures.js @@ -84,7 +84,7 @@ export interface Spec extends TurboModule { major: number; minor: number; patch?: number; - prerelease: number | null | void; + prerelease: number | null | undefined; }; forceTouchAvailable: boolean; osVersion: string; @@ -295,7 +295,7 @@ import type {TurboModule} from 'react-native/Libraries/TurboModule/RCTExport'; import * as TurboModuleRegistry from 'react-native/Libraries/TurboModule/TurboModuleRegistry'; export interface Spec extends TurboModule { - readonly voidFunc: (arg: string | null | void) => void; + readonly voidFunc: (arg: string | null | undefined) => void; } export default TurboModuleRegistry.getEnforcing('SampleTurboModule'); diff --git a/packages/react-native-codegen/src/parsers/typescript/utils.js b/packages/react-native-codegen/src/parsers/typescript/utils.js index fc435d259fff..685e6b50390b 100644 --- a/packages/react-native-codegen/src/parsers/typescript/utils.js +++ b/packages/react-native-codegen/src/parsers/typescript/utils.js @@ -75,15 +75,15 @@ function resolveTypeAnnotation( }; for (;;) { - // Check for optional type in union e.g. T | null | void + // Check for optional type in union e.g. T | null | undefined if ( node.type === 'TSUnionType' && node.types.some( - t => t.type === 'TSNullKeyword' || t.type === 'TSVoidKeyword', + t => t.type === 'TSNullKeyword' || t.type === 'TSUndefinedKeyword', ) ) { node = node.types.filter( - t => t.type !== 'TSNullKeyword' && t.type !== 'TSVoidKeyword', + t => t.type !== 'TSNullKeyword' && t.type !== 'TSUndefinedKeyword', )[0]; nullable = true; } else if (node.type === 'TSTypeReference') { From f3db6cc52792e3006a16408df4ae40f3aee19a86 Mon Sep 17 00:00:00 2001 From: Brad Zacher Date: Sat, 16 Jul 2022 01:41:27 -0700 Subject: [PATCH 0005/1165] update to ESLint v8 Summary: Changelog: [internal] - Upgrade ESLint version to the latest - Upgrade ESLint plugin versions to the latest to ensure compatibility - Switch from eslint-plugin-flowtype to eslint-plugin-ft-flow - Updates lint suppressions - all `flowtype/` rules to `ft-flow/` ### `flowtype` vs `ft-flow` `eslint-plugin-flowtype` is well out of date and no-longer maintained. It's been abandoned by its owner. This means it crashes on ESLint v8. `eslint-plugin-ft-flow` is a fork of the above and is maintained by the same people that own the `flow-typed` project. Reviewed By: jacdebug Differential Revision: D37727177 fbshipit-source-id: 516be42f947fec9c886526c182a608b3311c0b50 --- .eslintrc.js | 2 - .../index.js | 8 +- .../package.json | 20 +- .../yarn.lock | 808 +++++++++--------- repo-config/package.json | 22 +- template/package.json | 2 +- yarn.lock | 741 +++++++++------- 7 files changed, 856 insertions(+), 747 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 3d0dad11dfcd..8c7d0470630a 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -26,8 +26,6 @@ module.exports = { // These rules are not required with hermes-eslint 'ft-flow/define-flow-type': 0, 'ft-flow/use-flow-type': 0, - 'flowtype/define-flow-type': 0, - 'flowtype/use-flow-type': 0, // flow handles this check for us, so it's not required 'no-undef': 0, }, diff --git a/packages/eslint-config-react-native-community/index.js b/packages/eslint-config-react-native-community/index.js index 09af8a2395b0..563a400c02ab 100644 --- a/packages/eslint-config-react-native-community/index.js +++ b/packages/eslint-config-react-native-community/index.js @@ -37,13 +37,13 @@ module.exports = { { files: ['*.js'], parser: '@babel/eslint-parser', - plugins: ['flowtype'], + plugins: ['ft-flow'], rules: { // Flow Plugin - // The following rules are made available via `eslint-plugin-flowtype` + // The following rules are made available via `eslint-plugin-ft-flow` - 'flowtype/define-flow-type': 1, - 'flowtype/use-flow-type': 1, + 'ft-flow/define-flow-type': 1, + 'ft-flow/use-flow-type': 1, }, }, { diff --git a/packages/eslint-config-react-native-community/package.json b/packages/eslint-config-react-native-community/package.json index 244273c114c3..8d74bb7eb48b 100644 --- a/packages/eslint-config-react-native-community/package.json +++ b/packages/eslint-config-react-native-community/package.json @@ -14,23 +14,23 @@ "@babel/core": "^7.14.0", "@babel/eslint-parser": "^7.18.2", "@react-native-community/eslint-plugin": "^1.1.0", - "@typescript-eslint/eslint-plugin": "^5.15.0", - "@typescript-eslint/parser": "^5.15.0", - "eslint-config-prettier": "^8.3.0", + "@typescript-eslint/eslint-plugin": "^5.30.5", + "@typescript-eslint/parser": "^5.30.5", + "eslint-config-prettier": "^8.5.0", "eslint-plugin-eslint-comments": "^3.2.0", - "eslint-plugin-flowtype": "^8.0.0", - "eslint-plugin-jest": "^25.2.4", - "eslint-plugin-prettier": "^4.0.0", - "eslint-plugin-react": "^7.26.1", - "eslint-plugin-react-hooks": "^4.2.0", - "eslint-plugin-react-native": "^3.11.0" + "eslint-plugin-ft-flow": "^2.0.1", + "eslint-plugin-jest": "^26.5.3", + "eslint-plugin-prettier": "^4.2.1", + "eslint-plugin-react": "^7.30.1", + "eslint-plugin-react-hooks": "^4.6.0", + "eslint-plugin-react-native": "^4.0.0" }, "peerDependencies": { "eslint": ">=7", "prettier": ">=2" }, "devDependencies": { - "eslint": "^7.32.0", + "eslint": "^8.19.0", "prettier": "^2.4.1" } } diff --git a/packages/eslint-config-react-native-community/yarn.lock b/packages/eslint-config-react-native-community/yarn.lock index 3ae4af19ec0d..54b7d2e98212 100644 --- a/packages/eslint-config-react-native-community/yarn.lock +++ b/packages/eslint-config-react-native-community/yarn.lock @@ -10,13 +10,6 @@ "@jridgewell/gen-mapping" "^0.1.0" "@jridgewell/trace-mapping" "^0.3.9" -"@babel/code-frame@7.12.11": - version "7.12.11" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.11.tgz#f4ad435aa263db935b8f10f2c552d23fb716a63f" - integrity sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw== - dependencies: - "@babel/highlight" "^7.10.4" - "@babel/code-frame@^7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.7.tgz#44416b6bd7624b998f5b1af5d470856c40138789" @@ -152,7 +145,7 @@ "@babel/traverse" "^7.18.2" "@babel/types" "^7.18.2" -"@babel/highlight@^7.10.4", "@babel/highlight@^7.16.7": +"@babel/highlight@^7.16.7": version "7.17.12" resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.17.12.tgz#257de56ee5afbd20451ac0a75686b6b404257351" integrity sha512-7yykMVF3hfZY2jsHZEEgLc+3x4o1O+fYyULu11GynEUQNwB6lua+IIQn1FiJxNucd5UlyJryrwsOh8PL9Sn8Qg== @@ -199,31 +192,31 @@ "@babel/helper-validator-identifier" "^7.16.7" to-fast-properties "^2.0.0" -"@eslint/eslintrc@^0.4.3": - version "0.4.3" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.4.3.tgz#9e42981ef035beb3dd49add17acb96e8ff6f394c" - integrity sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw== +"@eslint/eslintrc@^1.3.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.3.0.tgz#29f92c30bb3e771e4a2048c95fa6855392dfac4f" + integrity sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw== dependencies: ajv "^6.12.4" - debug "^4.1.1" - espree "^7.3.0" - globals "^13.9.0" - ignore "^4.0.6" + debug "^4.3.2" + espree "^9.3.2" + globals "^13.15.0" + ignore "^5.2.0" import-fresh "^3.2.1" - js-yaml "^3.13.1" - minimatch "^3.0.4" + js-yaml "^4.1.0" + minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@humanwhocodes/config-array@^0.5.0": - version "0.5.0" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.5.0.tgz#1407967d4c6eecd7388f83acf1eaf4d0c6e58ef9" - integrity sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg== +"@humanwhocodes/config-array@^0.9.2": + version "0.9.5" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.9.5.tgz#2cbaf9a89460da24b5ca6531b8bbfc23e1df50c7" + integrity sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw== dependencies: - "@humanwhocodes/object-schema" "^1.2.0" + "@humanwhocodes/object-schema" "^1.2.1" debug "^4.1.1" minimatch "^3.0.4" -"@humanwhocodes/object-schema@^1.2.0": +"@humanwhocodes/object-schema@^1.2.1": version "1.2.1" resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== @@ -299,141 +292,95 @@ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d" integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ== -"@typescript-eslint/eslint-plugin@^5.15.0": - version "5.17.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.17.0.tgz#704eb4e75039000531255672bf1c85ee85cf1d67" - integrity sha512-qVstvQilEd89HJk3qcbKt/zZrfBZ+9h2ynpAGlWjWiizA7m/MtLT9RoX6gjtpE500vfIg8jogAkDzdCxbsFASQ== +"@typescript-eslint/eslint-plugin@^5.30.5": + version "5.30.6" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.30.6.tgz#9c6017b6c1d04894141b4a87816388967f64c359" + integrity sha512-J4zYMIhgrx4MgnZrSDD7sEnQp7FmhKNOaqaOpaoQ/SfdMfRB/0yvK74hTnvH+VQxndZynqs5/Hn4t+2/j9bADg== dependencies: - "@typescript-eslint/scope-manager" "5.17.0" - "@typescript-eslint/type-utils" "5.17.0" - "@typescript-eslint/utils" "5.17.0" - debug "^4.3.2" + "@typescript-eslint/scope-manager" "5.30.6" + "@typescript-eslint/type-utils" "5.30.6" + "@typescript-eslint/utils" "5.30.6" + debug "^4.3.4" functional-red-black-tree "^1.0.1" - ignore "^5.1.8" + ignore "^5.2.0" regexpp "^3.2.0" - semver "^7.3.5" + semver "^7.3.7" tsutils "^3.21.0" -"@typescript-eslint/experimental-utils@^5.0.0": - version "5.3.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-5.3.1.tgz#bbd8f9b67b4d5fdcb9d2f90297d8fcda22561e05" - integrity sha512-RgFn5asjZ5daUhbK5Sp0peq0SSMytqcrkNfU4pnDma2D8P3ElZ6JbYjY8IMSFfZAJ0f3x3tnO3vXHweYg0g59w== - dependencies: - "@types/json-schema" "^7.0.9" - "@typescript-eslint/scope-manager" "5.3.1" - "@typescript-eslint/types" "5.3.1" - "@typescript-eslint/typescript-estree" "5.3.1" - eslint-scope "^5.1.1" - eslint-utils "^3.0.0" - -"@typescript-eslint/parser@^5.15.0": - version "5.17.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.17.0.tgz#7def77d5bcd8458d12d52909118cf3f0a45f89d5" - integrity sha512-aRzW9Jg5Rlj2t2/crzhA2f23SIYFlF9mchGudyP0uiD6SenIxzKoLjwzHbafgHn39dNV/TV7xwQkLfFTZlJ4ig== - dependencies: - "@typescript-eslint/scope-manager" "5.17.0" - "@typescript-eslint/types" "5.17.0" - "@typescript-eslint/typescript-estree" "5.17.0" - debug "^4.3.2" - -"@typescript-eslint/scope-manager@5.17.0": - version "5.17.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.17.0.tgz#4cea7d0e0bc0e79eb60cad431c89120987c3f952" - integrity sha512-062iCYQF/doQ9T2WWfJohQKKN1zmmXVfAcS3xaiialiw8ZUGy05Em6QVNYJGO34/sU1a7a+90U3dUNfqUDHr3w== +"@typescript-eslint/parser@^5.30.5": + version "5.30.6" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.30.6.tgz#add440db038fa9d777e4ebdaf66da9e7fb7abe92" + integrity sha512-gfF9lZjT0p2ZSdxO70Xbw8w9sPPJGfAdjK7WikEjB3fcUI/yr9maUVEdqigBjKincUYNKOmf7QBMiTf719kbrA== dependencies: - "@typescript-eslint/types" "5.17.0" - "@typescript-eslint/visitor-keys" "5.17.0" + "@typescript-eslint/scope-manager" "5.30.6" + "@typescript-eslint/types" "5.30.6" + "@typescript-eslint/typescript-estree" "5.30.6" + debug "^4.3.4" -"@typescript-eslint/scope-manager@5.3.1": - version "5.3.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.3.1.tgz#3cfbfbcf5488fb2a9a6fbbe97963ee1e8d419269" - integrity sha512-XksFVBgAq0Y9H40BDbuPOTUIp7dn4u8oOuhcgGq7EoDP50eqcafkMVGrypyVGvDYHzjhdUCUwuwVUK4JhkMAMg== +"@typescript-eslint/scope-manager@5.30.6": + version "5.30.6" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.30.6.tgz#ce1b49ff5ce47f55518d63dbe8fc9181ddbd1a33" + integrity sha512-Hkq5PhLgtVoW1obkqYH0i4iELctEKixkhWLPTYs55doGUKCASvkjOXOd/pisVeLdO24ZX9D6yymJ/twqpJiG3g== dependencies: - "@typescript-eslint/types" "5.3.1" - "@typescript-eslint/visitor-keys" "5.3.1" + "@typescript-eslint/types" "5.30.6" + "@typescript-eslint/visitor-keys" "5.30.6" -"@typescript-eslint/type-utils@5.17.0": - version "5.17.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.17.0.tgz#1c4549d68c89877662224aabb29fbbebf5fc9672" - integrity sha512-3hU0RynUIlEuqMJA7dragb0/75gZmwNwFf/QJokWzPehTZousP/MNifVSgjxNcDCkM5HI2K22TjQWUmmHUINSg== +"@typescript-eslint/type-utils@5.30.6": + version "5.30.6" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.30.6.tgz#a64aa9acbe609ab77f09f53434a6af2b9685f3af" + integrity sha512-GFVVzs2j0QPpM+NTDMXtNmJKlF842lkZKDSanIxf+ArJsGeZUIaeT4jGg+gAgHt7AcQSFwW7htzF/rbAh2jaVA== dependencies: - "@typescript-eslint/utils" "5.17.0" - debug "^4.3.2" + "@typescript-eslint/utils" "5.30.6" + debug "^4.3.4" tsutils "^3.21.0" -"@typescript-eslint/types@5.17.0": - version "5.17.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.17.0.tgz#861ec9e669ffa2aa9b873dd4d28d9b1ce26d216f" - integrity sha512-AgQ4rWzmCxOZLioFEjlzOI3Ch8giDWx8aUDxyNw9iOeCvD3GEYAB7dxWGQy4T/rPVe8iPmu73jPHuaSqcjKvxw== - -"@typescript-eslint/types@5.3.1": - version "5.3.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.3.1.tgz#afaa715b69ebfcfde3af8b0403bf27527912f9b7" - integrity sha512-bG7HeBLolxKHtdHG54Uac750eXuQQPpdJfCYuw4ZI3bZ7+GgKClMWM8jExBtp7NSP4m8PmLRM8+lhzkYnSmSxQ== +"@typescript-eslint/types@5.30.6": + version "5.30.6" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.30.6.tgz#86369d0a7af8c67024115ac1da3e8fb2d38907e1" + integrity sha512-HdnP8HioL1F7CwVmT4RaaMX57RrfqsOMclZc08wGMiDYJBsLGBM7JwXM4cZJmbWLzIR/pXg1kkrBBVpxTOwfUg== -"@typescript-eslint/typescript-estree@5.17.0": - version "5.17.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.17.0.tgz#a7cba7dfc8f9cc2ac78c18584e684507df4f2488" - integrity sha512-X1gtjEcmM7Je+qJRhq7ZAAaNXYhTgqMkR10euC4Si6PIjb+kwEQHSxGazXUQXFyqfEXdkGf6JijUu5R0uceQzg== +"@typescript-eslint/typescript-estree@5.30.6": + version "5.30.6" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.30.6.tgz#a84a0d6a486f9b54042da1de3d671a2c9f14484e" + integrity sha512-Z7TgPoeYUm06smfEfYF0RBkpF8csMyVnqQbLYiGgmUSTaSXTP57bt8f0UFXstbGxKIreTwQCujtaH0LY9w9B+A== dependencies: - "@typescript-eslint/types" "5.17.0" - "@typescript-eslint/visitor-keys" "5.17.0" - debug "^4.3.2" - globby "^11.0.4" + "@typescript-eslint/types" "5.30.6" + "@typescript-eslint/visitor-keys" "5.30.6" + debug "^4.3.4" + globby "^11.1.0" is-glob "^4.0.3" - semver "^7.3.5" + semver "^7.3.7" tsutils "^3.21.0" -"@typescript-eslint/typescript-estree@5.3.1": - version "5.3.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.3.1.tgz#50cc4bfb93dc31bc75e08ae52e29fcb786d606ec" - integrity sha512-PwFbh/PKDVo/Wct6N3w+E4rLZxUDgsoII/GrWM2A62ETOzJd4M6s0Mu7w4CWsZraTbaC5UQI+dLeyOIFF1PquQ== - dependencies: - "@typescript-eslint/types" "5.3.1" - "@typescript-eslint/visitor-keys" "5.3.1" - debug "^4.3.2" - globby "^11.0.4" - is-glob "^4.0.3" - semver "^7.3.5" - tsutils "^3.21.0" - -"@typescript-eslint/utils@5.17.0": - version "5.17.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.17.0.tgz#549a9e1d491c6ccd3624bc3c1b098f5cfb45f306" - integrity sha512-DVvndq1QoxQH+hFv+MUQHrrWZ7gQ5KcJzyjhzcqB1Y2Xes1UQQkTRPUfRpqhS8mhTWsSb2+iyvDW1Lef5DD7vA== +"@typescript-eslint/utils@5.30.6", "@typescript-eslint/utils@^5.10.0": + version "5.30.6" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.30.6.tgz#1de2da14f678e7d187daa6f2e4cdb558ed0609dc" + integrity sha512-xFBLc/esUbLOJLk9jKv0E9gD/OH966M40aY9jJ8GiqpSkP2xOV908cokJqqhVd85WoIvHVHYXxSFE4cCSDzVvA== dependencies: "@types/json-schema" "^7.0.9" - "@typescript-eslint/scope-manager" "5.17.0" - "@typescript-eslint/types" "5.17.0" - "@typescript-eslint/typescript-estree" "5.17.0" + "@typescript-eslint/scope-manager" "5.30.6" + "@typescript-eslint/types" "5.30.6" + "@typescript-eslint/typescript-estree" "5.30.6" eslint-scope "^5.1.1" eslint-utils "^3.0.0" -"@typescript-eslint/visitor-keys@5.17.0": - version "5.17.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.17.0.tgz#52daae45c61b0211b4c81b53a71841911e479128" - integrity sha512-6K/zlc4OfCagUu7Am/BD5k8PSWQOgh34Nrv9Rxe2tBzlJ7uOeJ/h7ugCGDCeEZHT6k2CJBhbk9IsbkPI0uvUkA== - dependencies: - "@typescript-eslint/types" "5.17.0" - eslint-visitor-keys "^3.0.0" - -"@typescript-eslint/visitor-keys@5.3.1": - version "5.3.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.3.1.tgz#c2860ff22939352db4f3806f34b21d8ad00588ba" - integrity sha512-3cHUzUuVTuNHx0Gjjt5pEHa87+lzyqOiHXy/Gz+SJOCW1mpw9xQHIIEwnKn+Thph1mgWyZ90nboOcSuZr/jTTQ== +"@typescript-eslint/visitor-keys@5.30.6": + version "5.30.6" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.30.6.tgz#94dd10bb481c8083378d24de1742a14b38a2678c" + integrity sha512-41OiCjdL2mCaSDi2SvYbzFLlqqlm5v1ZW9Ym55wXKL/Rx6OOB1IbuFGo71Fj6Xy90gJDFTlgOS+vbmtGHPTQQA== dependencies: - "@typescript-eslint/types" "5.3.1" - eslint-visitor-keys "^3.0.0" + "@typescript-eslint/types" "5.30.6" + eslint-visitor-keys "^3.3.0" -acorn-jsx@^5.3.1: +acorn-jsx@^5.3.2: version "5.3.2" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== -acorn@^7.4.0: - version "7.4.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" - integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== +acorn@^8.7.1: + version "8.7.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.1.tgz#0197122c843d1bf6d0a5e83220a788f278f63c30" + integrity sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A== ajv@^6.10.0, ajv@^6.12.4: version "6.12.6" @@ -445,21 +392,6 @@ ajv@^6.10.0, ajv@^6.12.4: json-schema-traverse "^0.4.1" uri-js "^4.2.2" -ajv@^8.0.1: - version "8.7.1" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.7.1.tgz#52be6f1736b076074798124293618f132ad07a7e" - integrity sha512-gPpOObTO1QjbnN1sVMjJcp1TF9nggMfO4MBR5uQl6ZVTOaEPq5i4oq/6R9q2alMMPB3eg53wFv1RuJBLuxf3Hw== - dependencies: - fast-deep-equal "^3.1.1" - json-schema-traverse "^1.0.0" - require-from-string "^2.0.2" - uri-js "^4.2.2" - -ansi-colors@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" - integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== - ansi-regex@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" @@ -472,19 +404,17 @@ ansi-styles@^3.2.1: dependencies: color-convert "^1.9.0" -ansi-styles@^4.0.0, ansi-styles@^4.1.0: +ansi-styles@^4.1.0: version "4.3.0" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== dependencies: color-convert "^2.0.1" -argparse@^1.0.7: - version "1.0.10" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" - integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== - dependencies: - sprintf-js "~1.0.2" +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== array-includes@^3.1.3: version "3.1.4" @@ -497,24 +427,31 @@ array-includes@^3.1.3: get-intrinsic "^1.1.1" is-string "^1.0.7" +array-includes@^3.1.5: + version "3.1.5" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.5.tgz#2c320010db8d31031fd2a5f6b3bbd4b1aad31bdb" + integrity sha512-iSDYZMMyTPkiFasVqfuAQnWAYcvO/SeBSCGKePoEthjp4LEMTe4uLc7b025o4jAZpHhihh8xPo99TNWUWWkGDQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.19.5" + get-intrinsic "^1.1.1" + is-string "^1.0.7" + array-union@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== -array.prototype.flatmap@^1.2.4: - version "1.2.5" - resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.2.5.tgz#908dc82d8a406930fdf38598d51e7411d18d4446" - integrity sha512-08u6rVyi1Lj7oqWbS9nUxliETrtIROT4XGTA4D/LWGten6E3ocm7cy9SIrmNHOL5XVbVuckUp3X6Xyg8/zpvHA== +array.prototype.flatmap@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.0.tgz#a7e8ed4225f4788a70cd910abcf0791e76a5534f" + integrity sha512-PZC9/8TKAIxcWKdyeb77EzULHPrIX/tIZebLJUQOMR1OwYosT8yggdfWScfTBCDj5utONvOuPQQumYsU2ULbkg== dependencies: - call-bind "^1.0.0" + call-bind "^1.0.2" define-properties "^1.1.3" - es-abstract "^1.19.0" - -astral-regex@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" - integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== + es-abstract "^1.19.2" + es-shim-unscopables "^1.0.0" balanced-match@^1.0.0: version "1.0.0" @@ -529,7 +466,7 @@ brace-expansion@^1.1.7: balanced-match "^1.0.0" concat-map "0.0.1" -braces@^3.0.1: +braces@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== @@ -561,9 +498,9 @@ callsites@^3.0.0: integrity sha512-tWnkwu9YEq2uzlBDI4RcLn8jrFvF9AOi8PxDNU3hZZjJcjkcRAq3vCI+vZcg1SuxISDYe86k9VZFwAxDiJGoAw== caniuse-lite@^1.0.30001349: - version "1.0.30001355" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001355.tgz#e240b7177443ed0198c737a7f609536976701c77" - integrity sha512-Sd6pjJHF27LzCB7pT7qs+kuX2ndurzCzkpJl6Qct7LPSZ9jn0bkOA8mdgMgmqnQAWLVOOGjLpc+66V57eLtb1g== + version "1.0.30001364" + resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001364.tgz" + integrity sha512-9O0xzV3wVyX0SlegIQ6knz+okhBB5pE0PC40MNdwcipjwpxoUEHL24uJ+gG42cgklPjfO5ZjZPme9FTSN3QT2Q== chalk@^2.0.0: version "2.4.2" @@ -627,13 +564,20 @@ cross-spawn@^7.0.2: shebang-command "^2.0.0" which "^2.0.1" -debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.2: +debug@^4.1.0, debug@^4.1.1, debug@^4.3.2: version "4.3.2" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b" integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw== dependencies: ms "2.1.2" +debug@^4.3.4: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + deep-is@^0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" @@ -646,6 +590,14 @@ define-properties@^1.1.3: dependencies: object-keys "^1.0.12" +define-properties@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.4.tgz#0b14d7bd7fbeb2f3572c3a7eda80ea5d57fb05b1" + integrity sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA== + dependencies: + has-property-descriptors "^1.0.0" + object-keys "^1.1.1" + dir-glob@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" @@ -672,18 +624,6 @@ electron-to-chromium@^1.4.147: resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.160.tgz#da54e24fddeaca52f37965c7bec1bd964c97d487" integrity sha512-O1Z12YfyeX2LXYO7MdHIPazGXzLzQnr1ADW55U2ARQsJBPgfpJz3u+g3Mo2l1wSyfOCdiGqaX9qtV4XKZ0HNRA== -emoji-regex@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" - integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== - -enquirer@^2.3.5: - version "2.3.6" - resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d" - integrity sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg== - dependencies: - ansi-colors "^4.1.1" - es-abstract@^1.19.0, es-abstract@^1.19.1: version "1.19.1" resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.19.1.tgz#d4885796876916959de78edaa0df456627115ec3" @@ -710,6 +650,42 @@ es-abstract@^1.19.0, es-abstract@^1.19.1: string.prototype.trimstart "^1.0.4" unbox-primitive "^1.0.1" +es-abstract@^1.19.2, es-abstract@^1.19.5: + version "1.20.1" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.20.1.tgz#027292cd6ef44bd12b1913b828116f54787d1814" + integrity sha512-WEm2oBhfoI2sImeM4OF2zE2V3BYdSF+KnSi9Sidz51fQHd7+JuF8Xgcj9/0o+OWeIeIS/MiuNnlruQrJf16GQA== + dependencies: + call-bind "^1.0.2" + es-to-primitive "^1.2.1" + function-bind "^1.1.1" + function.prototype.name "^1.1.5" + get-intrinsic "^1.1.1" + get-symbol-description "^1.0.0" + has "^1.0.3" + has-property-descriptors "^1.0.0" + has-symbols "^1.0.3" + internal-slot "^1.0.3" + is-callable "^1.2.4" + is-negative-zero "^2.0.2" + is-regex "^1.1.4" + is-shared-array-buffer "^1.0.2" + is-string "^1.0.7" + is-weakref "^1.0.2" + object-inspect "^1.12.0" + object-keys "^1.1.1" + object.assign "^4.1.2" + regexp.prototype.flags "^1.4.3" + string.prototype.trimend "^1.0.5" + string.prototype.trimstart "^1.0.5" + unbox-primitive "^1.0.2" + +es-shim-unscopables@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz#702e632193201e3edf8713635d083d378e510241" + integrity sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w== + dependencies: + has "^1.0.3" + es-to-primitive@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" @@ -734,10 +710,10 @@ escape-string-regexp@^4.0.0: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== -eslint-config-prettier@^8.3.0: - version "8.3.0" - resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.3.0.tgz#f7471b20b6fe8a9a9254cc684454202886a2dd7a" - integrity sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew== +eslint-config-prettier@^8.5.0: + version "8.5.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz#5a81680ec934beca02c7b1a61cf8ca34b66feab1" + integrity sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q== eslint-plugin-eslint-comments@^3.2.0: version "3.2.0" @@ -747,65 +723,65 @@ eslint-plugin-eslint-comments@^3.2.0: escape-string-regexp "^1.0.5" ignore "^5.0.5" -eslint-plugin-flowtype@^8.0.0: - version "8.0.3" - resolved "https://registry.yarnpkg.com/eslint-plugin-flowtype/-/eslint-plugin-flowtype-8.0.3.tgz#e1557e37118f24734aa3122e7536a038d34a4912" - integrity sha512-dX8l6qUL6O+fYPtpNRideCFSpmWOUVx5QcaGLVqe/vlDiBSe4vYljDWDETwnyFzpl7By/WVIu6rcrniCgH9BqQ== +eslint-plugin-ft-flow@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-ft-flow/-/eslint-plugin-ft-flow-2.0.1.tgz#57d9a12ef02b7af8f9bd6ccd6bd8fa4034809716" + integrity sha512-dGBnCo+ok6H9p6Vw2oPFEM4vA9IEclRXQQAA/Zws51/L5zr3FDl9FxQiWGfaw0WaTIX5biiAxp/q1W5bGXjlVA== dependencies: lodash "^4.17.21" string-natural-compare "^3.0.1" -eslint-plugin-jest@^25.2.4: - version "25.2.4" - resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-25.2.4.tgz#bb9f6a0bd1fd524ffb0b8b7a159cd70a58a1a793" - integrity sha512-HRyinpgmEdkVr7pNPaYPHCoGqEzpgk79X8pg/xCeoAdurbyQjntJQ4pTzHl7BiVEBlam/F1Qsn+Dk0HtJO7Aaw== +eslint-plugin-jest@^26.5.3: + version "26.5.3" + resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-26.5.3.tgz#a3ceeaf4a757878342b8b00eca92379b246e5505" + integrity sha512-sICclUqJQnR1bFRZGLN2jnSVsYOsmPYYnroGCIMVSvTS3y8XR3yjzy1EcTQmk6typ5pRgyIWzbjqxK6cZHEZuQ== dependencies: - "@typescript-eslint/experimental-utils" "^5.0.0" + "@typescript-eslint/utils" "^5.10.0" -eslint-plugin-prettier@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-4.0.0.tgz#8b99d1e4b8b24a762472b4567992023619cb98e0" - integrity sha512-98MqmCJ7vJodoQK359bqQWaxOE0CS8paAz/GgjaZLyex4TTk3g9HugoO89EqWCrFiOqn9EVvcoo7gZzONCWVwQ== +eslint-plugin-prettier@^4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz#651cbb88b1dab98bfd42f017a12fa6b2d993f94b" + integrity sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ== dependencies: prettier-linter-helpers "^1.0.0" -eslint-plugin-react-hooks@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.2.0.tgz#8c229c268d468956334c943bb45fc860280f5556" - integrity sha512-623WEiZJqxR7VdxFCKLI6d6LLpwJkGPYKODnkH3D7WpOG5KM8yWueBd8TLsNAetEJNF5iJmolaAKO3F8yzyVBQ== +eslint-plugin-react-hooks@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz#4c3e697ad95b77e93f8646aaa1630c1ba607edd3" + integrity sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g== eslint-plugin-react-native-globals@^0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/eslint-plugin-react-native-globals/-/eslint-plugin-react-native-globals-0.1.2.tgz#ee1348bc2ceb912303ce6bdbd22e2f045ea86ea2" integrity sha512-9aEPf1JEpiTjcFAmmyw8eiIXmcNZOqaZyHO77wgm0/dWfT/oxC1SrIq8ET38pMxHYrcB6Uew+TzUVsBeczF88g== -eslint-plugin-react-native@^3.11.0: - version "3.11.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-react-native/-/eslint-plugin-react-native-3.11.0.tgz#c73b0886abb397867e5e6689d3a6a418682e6bac" - integrity sha512-7F3OTwrtQPfPFd+VygqKA2VZ0f2fz0M4gJmry/TRE18JBb94/OtMxwbL7Oqwu7FGyrdeIOWnXQbBAveMcSTZIA== +eslint-plugin-react-native@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-react-native/-/eslint-plugin-react-native-4.0.0.tgz#eec41984abe4970bdd7c6082dff7a98a5e34d0bb" + integrity sha512-kMmdxrSY7A1WgdqaGC+rY/28rh7kBGNBRsk48ovqkQmdg5j4K+DaFmegENDzMrdLkoufKGRNkKX6bgSwQTCAxQ== dependencies: "@babel/traverse" "^7.7.4" eslint-plugin-react-native-globals "^0.1.1" -eslint-plugin-react@^7.26.1: - version "7.26.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.26.1.tgz#41bcfe3e39e6a5ac040971c1af94437c80daa40e" - integrity sha512-Lug0+NOFXeOE+ORZ5pbsh6mSKjBKXDXItUD2sQoT+5Yl0eoT82DqnXeTMfUare4QVCn9QwXbfzO/dBLjLXwVjQ== +eslint-plugin-react@^7.30.1: + version "7.30.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.30.1.tgz#2be4ab23ce09b5949c6631413ba64b2810fd3e22" + integrity sha512-NbEvI9jtqO46yJA3wcRF9Mo0lF9T/jhdHqhCHXiXtD+Zcb98812wvokjWpU7Q4QH5edo6dmqrukxVvWWXHlsUg== dependencies: - array-includes "^3.1.3" - array.prototype.flatmap "^1.2.4" + array-includes "^3.1.5" + array.prototype.flatmap "^1.3.0" doctrine "^2.1.0" - estraverse "^5.2.0" + estraverse "^5.3.0" jsx-ast-utils "^2.4.1 || ^3.0.0" - minimatch "^3.0.4" - object.entries "^1.1.4" - object.fromentries "^2.0.4" - object.hasown "^1.0.0" - object.values "^1.1.4" - prop-types "^15.7.2" + minimatch "^3.1.2" + object.entries "^1.1.5" + object.fromentries "^2.0.5" + object.hasown "^1.1.1" + object.values "^1.1.5" + prop-types "^15.8.1" resolve "^2.0.0-next.3" semver "^6.3.0" - string.prototype.matchall "^4.0.5" + string.prototype.matchall "^4.0.7" eslint-scope@^5.1.1: version "5.1.1" @@ -815,12 +791,13 @@ eslint-scope@^5.1.1: esrecurse "^4.3.0" estraverse "^4.1.1" -eslint-utils@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27" - integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg== +eslint-scope@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.1.1.tgz#fff34894c2f65e5226d3041ac480b4513a163642" + integrity sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw== dependencies: - eslint-visitor-keys "^1.1.0" + esrecurse "^4.3.0" + estraverse "^5.2.0" eslint-utils@^3.0.0: version "3.0.0" @@ -829,80 +806,65 @@ eslint-utils@^3.0.0: dependencies: eslint-visitor-keys "^2.0.0" -eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" - integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== - eslint-visitor-keys@^2.0.0, eslint-visitor-keys@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== -eslint-visitor-keys@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.1.0.tgz#eee4acea891814cda67a7d8812d9647dd0179af2" - integrity sha512-yWJFpu4DtjsWKkt5GeNBBuZMlNcYVs6vRCLoCVEJrTjaSB6LC98gFipNK/erM2Heg/E8mIK+hXG/pJMLK+eRZA== +eslint-visitor-keys@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826" + integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== -eslint@^7.32.0: - version "7.32.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.32.0.tgz#c6d328a14be3fb08c8d1d21e12c02fdb7a2a812d" - integrity sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA== +eslint@^8.19.0: + version "8.19.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.19.0.tgz#7342a3cbc4fbc5c106a1eefe0fd0b50b6b1a7d28" + integrity sha512-SXOPj3x9VKvPe81TjjUJCYlV4oJjQw68Uek+AM0X4p+33dj2HY5bpTZOgnQHcG2eAm1mtCU9uNMnJi7exU/kYw== dependencies: - "@babel/code-frame" "7.12.11" - "@eslint/eslintrc" "^0.4.3" - "@humanwhocodes/config-array" "^0.5.0" + "@eslint/eslintrc" "^1.3.0" + "@humanwhocodes/config-array" "^0.9.2" ajv "^6.10.0" chalk "^4.0.0" cross-spawn "^7.0.2" - debug "^4.0.1" + debug "^4.3.2" doctrine "^3.0.0" - enquirer "^2.3.5" escape-string-regexp "^4.0.0" - eslint-scope "^5.1.1" - eslint-utils "^2.1.0" - eslint-visitor-keys "^2.0.0" - espree "^7.3.1" + eslint-scope "^7.1.1" + eslint-utils "^3.0.0" + eslint-visitor-keys "^3.3.0" + espree "^9.3.2" esquery "^1.4.0" esutils "^2.0.2" fast-deep-equal "^3.1.3" file-entry-cache "^6.0.1" functional-red-black-tree "^1.0.1" - glob-parent "^5.1.2" - globals "^13.6.0" - ignore "^4.0.6" + glob-parent "^6.0.1" + globals "^13.15.0" + ignore "^5.2.0" import-fresh "^3.0.0" imurmurhash "^0.1.4" is-glob "^4.0.0" - js-yaml "^3.13.1" + js-yaml "^4.1.0" json-stable-stringify-without-jsonify "^1.0.1" levn "^0.4.1" lodash.merge "^4.6.2" - minimatch "^3.0.4" + minimatch "^3.1.2" natural-compare "^1.4.0" optionator "^0.9.1" - progress "^2.0.0" - regexpp "^3.1.0" - semver "^7.2.1" - strip-ansi "^6.0.0" + regexpp "^3.2.0" + strip-ansi "^6.0.1" strip-json-comments "^3.1.0" - table "^6.0.9" text-table "^0.2.0" v8-compile-cache "^2.0.3" -espree@^7.3.0, espree@^7.3.1: - version "7.3.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-7.3.1.tgz#f2df330b752c6f55019f8bd89b7660039c1bbbb6" - integrity sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g== +espree@^9.3.2: + version "9.3.2" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.3.2.tgz#f58f77bd334731182801ced3380a8cc859091596" + integrity sha512-D211tC7ZwouTIuY5x9XnS0E9sWNChB7IYKX/Xp5eQj3nFXhqmiUDB9q27y76oFl8jTg3pXcQx/bpxMfs3CIZbA== dependencies: - acorn "^7.4.0" - acorn-jsx "^5.3.1" - eslint-visitor-keys "^1.3.0" - -esprima@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" - integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + acorn "^8.7.1" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^3.3.0" esquery@^1.4.0: version "1.4.0" @@ -928,6 +890,11 @@ estraverse@^5.1.0, estraverse@^5.2.0: resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.2.0.tgz#307df42547e6cc7324d3cf03c155d5cdb8c53880" integrity sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ== +estraverse@^5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + esutils@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" @@ -943,17 +910,16 @@ fast-diff@^1.1.2: resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03" integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w== -fast-glob@^3.1.1: - version "3.2.5" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.5.tgz#7939af2a656de79a4f1901903ee8adcaa7cb9661" - integrity sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg== +fast-glob@^3.2.9: + version "3.2.11" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.11.tgz#a1172ad95ceb8a16e20caa5c5e56480e5129c1d9" + integrity sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew== dependencies: "@nodelib/fs.stat" "^2.0.2" "@nodelib/fs.walk" "^1.2.3" - glob-parent "^5.1.0" + glob-parent "^5.1.2" merge2 "^1.3.0" - micromatch "^4.0.2" - picomatch "^2.2.1" + micromatch "^4.0.4" fast-json-stable-stringify@^2.0.0: version "2.0.0" @@ -1009,11 +975,26 @@ function-bind@^1.1.1: resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== +function.prototype.name@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.5.tgz#cce0505fe1ffb80503e6f9e46cc64e46a12a9621" + integrity sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.0" + functions-have-names "^1.2.2" + functional-red-black-tree@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= +functions-have-names@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" + integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== + gensync@^1.0.0-beta.2: version "1.0.0-beta.2" resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" @@ -1036,13 +1017,20 @@ get-symbol-description@^1.0.0: call-bind "^1.0.2" get-intrinsic "^1.1.1" -glob-parent@^5.1.0, glob-parent@^5.1.2: +glob-parent@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== dependencies: is-glob "^4.0.1" +glob-parent@^6.0.1: + version "6.0.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + glob@^7.1.3: version "7.1.6" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" @@ -1060,23 +1048,23 @@ globals@^11.1.0: resolved "https://registry.yarnpkg.com/globals/-/globals-11.11.0.tgz#dcf93757fa2de5486fbeed7118538adf789e9c2e" integrity sha512-WHq43gS+6ufNOEqlrDBxVEbb8ntfXrfAUU2ZOpCxrBdGKW3gyv8mCxAfIBD0DroPKGrJ2eSsXsLtY9MPntsyTw== -globals@^13.6.0, globals@^13.9.0: - version "13.12.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-13.12.0.tgz#4d733760304230a0082ed96e21e5c565f898089e" - integrity sha512-uS8X6lSKN2JumVoXrbUz+uG4BYG+eiawqm3qFcT7ammfbUHeCBoJMlHcec/S3krSk73/AE/f0szYFmgAA3kYZg== +globals@^13.15.0: + version "13.16.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.16.0.tgz#9be4aca28f311aaeb974ea54978ebbb5e35ce46a" + integrity sha512-A1lrQfpNF+McdPOnnFqY3kSN0AFTy485bTi1bkLk4mVPODIUEcSfhHgRqA+QdXPksrSTTztYXx37NFV+GpGk3Q== dependencies: type-fest "^0.20.2" -globby@^11.0.4: - version "11.0.4" - resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.4.tgz#2cbaff77c2f2a62e71e9b2813a67b97a3a3001a5" - integrity sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg== +globby@^11.1.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" + integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== dependencies: array-union "^2.1.0" dir-glob "^3.0.1" - fast-glob "^3.1.1" - ignore "^5.1.4" - merge2 "^1.3.0" + fast-glob "^3.2.9" + ignore "^5.2.0" + merge2 "^1.4.1" slash "^3.0.0" has-bigints@^1.0.1: @@ -1084,6 +1072,11 @@ has-bigints@^1.0.1: resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.1.tgz#64fe6acb020673e3b78db035a5af69aa9d07b113" integrity sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA== +has-bigints@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" + integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ== + has-flag@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" @@ -1094,11 +1087,23 @@ has-flag@^4.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== +has-property-descriptors@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz#610708600606d36961ed04c196193b6a607fa861" + integrity sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ== + dependencies: + get-intrinsic "^1.1.1" + has-symbols@^1.0.1, has-symbols@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.2.tgz#165d3070c00309752a1236a479331e3ac56f1423" integrity sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw== +has-symbols@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" + integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== + has-tostringtag@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" @@ -1113,12 +1118,7 @@ has@^1.0.3: dependencies: function-bind "^1.1.1" -ignore@^4.0.6: - version "4.0.6" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" - integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== - -ignore@^5.0.5, ignore@^5.1.4, ignore@^5.1.8: +ignore@^5.0.5, ignore@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== @@ -1195,11 +1195,6 @@ is-extglob@^2.1.1: resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= -is-fullwidth-code-point@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" - integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== - is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" @@ -1212,6 +1207,11 @@ is-negative-zero@^2.0.1: resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.1.tgz#3de746c18dda2319241a53675908d8f766f11c24" integrity sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w== +is-negative-zero@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" + integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== + is-number-object@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.6.tgz#6a7aaf838c7f0686a50b4553f7e54a96494e89f0" @@ -1237,6 +1237,13 @@ is-shared-array-buffer@^1.0.1: resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz#97b0c85fbdacb59c9c446fe653b82cf2b5b7cfe6" integrity sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA== +is-shared-array-buffer@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79" + integrity sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA== + dependencies: + call-bind "^1.0.2" + is-string@^1.0.5, is-string@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" @@ -1258,6 +1265,13 @@ is-weakref@^1.0.1: dependencies: call-bind "^1.0.0" +is-weakref@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" + integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== + dependencies: + call-bind "^1.0.2" + isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" @@ -1268,13 +1282,12 @@ isexe@^2.0.0: resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== -js-yaml@^3.13.1: - version "3.13.1" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" - integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw== +js-yaml@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== dependencies: - argparse "^1.0.7" - esprima "^4.0.0" + argparse "^2.0.1" jsesc@^2.5.1: version "2.5.2" @@ -1286,11 +1299,6 @@ json-schema-traverse@^0.4.1: resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== -json-schema-traverse@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" - integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== - json-stable-stringify-without-jsonify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" @@ -1322,11 +1330,6 @@ lodash.merge@^4.6.2: resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== -lodash.truncate@^4.4.2: - version "4.4.2" - resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193" - integrity sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM= - lodash@^4.17.21: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" @@ -1346,18 +1349,18 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" -merge2@^1.3.0: +merge2@^1.3.0, merge2@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== -micromatch@^4.0.2: - version "4.0.4" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.4.tgz#896d519dfe9db25fce94ceb7a500919bf881ebf9" - integrity sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg== +micromatch@^4.0.4: + version "4.0.5" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" + integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== dependencies: - braces "^3.0.1" - picomatch "^2.2.3" + braces "^3.0.2" + picomatch "^2.3.1" minimatch@^3.0.4: version "3.0.4" @@ -1366,6 +1369,13 @@ minimatch@^3.0.4: dependencies: brace-expansion "^1.1.7" +minimatch@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + ms@2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" @@ -1391,6 +1401,11 @@ object-inspect@^1.11.0, object-inspect@^1.9.0: resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.11.0.tgz#9dceb146cedd4148a0d9e51ab88d34cf509922b1" integrity sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg== +object-inspect@^1.12.0: + version "1.12.2" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.2.tgz#c0641f26394532f28ab8d796ab954e43c009a8ea" + integrity sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ== + object-keys@^1.0.12, object-keys@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" @@ -1406,7 +1421,7 @@ object.assign@^4.1.2: has-symbols "^1.0.1" object-keys "^1.1.1" -object.entries@^1.1.4: +object.entries@^1.1.5: version "1.1.5" resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.5.tgz#e1acdd17c4de2cd96d5a08487cfb9db84d881861" integrity sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g== @@ -1415,7 +1430,7 @@ object.entries@^1.1.4: define-properties "^1.1.3" es-abstract "^1.19.1" -object.fromentries@^2.0.4: +object.fromentries@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.5.tgz#7b37b205109c21e741e605727fe8b0ad5fa08251" integrity sha512-CAyG5mWQRRiBU57Re4FKoTBjXfDoNwdFVH2Y1tS9PqCsfUTymAohOkEMSG3aRNKmv4lV3O7p1et7c187q6bynw== @@ -1424,15 +1439,15 @@ object.fromentries@^2.0.4: define-properties "^1.1.3" es-abstract "^1.19.1" -object.hasown@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/object.hasown/-/object.hasown-1.1.0.tgz#7232ed266f34d197d15cac5880232f7a4790afe5" - integrity sha512-MhjYRfj3GBlhSkDHo6QmvgjRLXQ2zndabdf3nX0yTyZK9rPfxb6uRpAac8HXNLy1GpqWtZ81Qh4v3uOls2sRAg== +object.hasown@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object.hasown/-/object.hasown-1.1.1.tgz#ad1eecc60d03f49460600430d97f23882cf592a3" + integrity sha512-LYLe4tivNQzq4JdaWW6WO3HMZZJWzkkH8fnI6EebWl0VZth2wL2Lovm74ep2/gZzlaTdV62JZHEqHQ2yVn8Q/A== dependencies: - define-properties "^1.1.3" - es-abstract "^1.19.1" + define-properties "^1.1.4" + es-abstract "^1.19.5" -object.values@^1.1.4: +object.values@^1.1.5: version "1.1.5" resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.5.tgz#959f63e3ce9ef108720333082131e4a459b716ac" integrity sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg== @@ -1492,10 +1507,10 @@ picocolors@^1.0.0: resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== -picomatch@^2.2.1, picomatch@^2.2.3: - version "2.2.3" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.3.tgz#465547f359ccc206d3c48e46a1bcb89bf7ee619d" - integrity sha512-KpELjfwcCDUb9PeigTs2mBJzXUPzAuP2oPcA989He8Rte0+YUAjw1JVedDhuTKPkHjSYzMN3npC9luThGYEKdg== +picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== prelude-ls@^1.2.1: version "1.2.1" @@ -1514,19 +1529,14 @@ prettier@^2.4.1: resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.4.1.tgz#671e11c89c14a4cfc876ce564106c4a6726c9f5c" integrity sha512-9fbDAXSBcc6Bs1mZrDYb3XKzDLm4EXXL9sC1LqKP5rZkT6KRr/rf9amVUcODVXgguK/isJz0d0hP72WeaKWsvA== -progress@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" - integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== - -prop-types@^15.7.2: - version "15.7.2" - resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" - integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== +prop-types@^15.8.1: + version "15.8.1" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" + integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== dependencies: loose-envify "^1.4.0" object-assign "^4.1.1" - react-is "^16.8.1" + react-is "^16.13.1" punycode@^2.1.0: version "2.1.1" @@ -1538,29 +1548,25 @@ queue-microtask@^1.2.2: resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== -react-is@^16.8.1: - version "16.8.4" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.8.4.tgz#90f336a68c3a29a096a3d648ab80e87ec61482a2" - integrity sha512-PVadd+WaUDOAciICm/J1waJaSvgq+4rHE/K70j0PFqKhkTBsPv/82UGQJNXAngz1fOQLLxI6z1sEDmJDQhCTAA== +react-is@^16.13.1: + version "16.13.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" + integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== -regexp.prototype.flags@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz#7ef352ae8d159e758c0eadca6f8fcb4eef07be26" - integrity sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA== +regexp.prototype.flags@^1.4.1, regexp.prototype.flags@^1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz#87cab30f80f66660181a3bb7bf5981a872b367ac" + integrity sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA== dependencies: call-bind "^1.0.2" define-properties "^1.1.3" + functions-have-names "^1.2.2" -regexpp@^3.1.0, regexpp@^3.2.0: +regexpp@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== -require-from-string@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" - integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== - resolve-from@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" @@ -1603,10 +1609,10 @@ semver@^6.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== -semver@^7.2.1, semver@^7.3.5: - version "7.3.5" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" - integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== +semver@^7.3.7: + version "7.3.7" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f" + integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g== dependencies: lru-cache "^6.0.0" @@ -1636,46 +1642,23 @@ slash@^3.0.0: resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== -slice-ansi@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" - integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ== - dependencies: - ansi-styles "^4.0.0" - astral-regex "^2.0.0" - is-fullwidth-code-point "^3.0.0" - -sprintf-js@~1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" - integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= - string-natural-compare@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/string-natural-compare/-/string-natural-compare-3.0.1.tgz#7a42d58474454963759e8e8b7ae63d71c1e7fdf4" integrity sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw== -string-width@^4.2.3: - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -string.prototype.matchall@^4.0.5: - version "4.0.6" - resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.6.tgz#5abb5dabc94c7b0ea2380f65ba610b3a544b15fa" - integrity sha512-6WgDX8HmQqvEd7J+G6VtAahhsQIssiZ8zl7zKh1VDMFyL3hRTJP4FTNA3RbIp2TOQ9AYNDcc7e3fH0Qbup+DBg== +string.prototype.matchall@^4.0.7: + version "4.0.7" + resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.7.tgz#8e6ecb0d8a1fb1fda470d81acecb2dba057a481d" + integrity sha512-f48okCX7JiwVi1NXCVWcFnZgADDC/n2vePlQ/KUCNqCikLLilQvwjMO8+BHVKvgzH0JB0J9LEPgxOGT02RoETg== dependencies: call-bind "^1.0.2" define-properties "^1.1.3" es-abstract "^1.19.1" get-intrinsic "^1.1.1" - has-symbols "^1.0.2" + has-symbols "^1.0.3" internal-slot "^1.0.3" - regexp.prototype.flags "^1.3.1" + regexp.prototype.flags "^1.4.1" side-channel "^1.0.4" string.prototype.trimend@^1.0.4: @@ -1686,6 +1669,15 @@ string.prototype.trimend@^1.0.4: call-bind "^1.0.2" define-properties "^1.1.3" +string.prototype.trimend@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz#914a65baaab25fbdd4ee291ca7dde57e869cb8d0" + integrity sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.19.5" + string.prototype.trimstart@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz#b36399af4ab2999b4c9c648bd7a3fb2bb26feeed" @@ -1694,7 +1686,16 @@ string.prototype.trimstart@^1.0.4: call-bind "^1.0.2" define-properties "^1.1.3" -strip-ansi@^6.0.0, strip-ansi@^6.0.1: +string.prototype.trimstart@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz#5466d93ba58cfa2134839f81d7f42437e8c01fef" + integrity sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.19.5" + +strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -1720,17 +1721,6 @@ supports-color@^7.1.0: dependencies: has-flag "^4.0.0" -table@^6.0.9: - version "6.7.3" - resolved "https://registry.yarnpkg.com/table/-/table-6.7.3.tgz#255388439715a738391bd2ee4cbca89a4d05a9b7" - integrity sha512-5DkIxeA7XERBqMwJq0aHZOdMadBx4e6eDoFRuyT5VR82J0Ycg2DwM6GfA/EQAhJ+toRTaS1lIdSQCqgrmhPnlw== - dependencies: - ajv "^8.0.1" - lodash.truncate "^4.4.2" - slice-ansi "^4.0.0" - string-width "^4.2.3" - strip-ansi "^6.0.1" - text-table@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" @@ -1782,6 +1772,16 @@ unbox-primitive@^1.0.1: has-symbols "^1.0.2" which-boxed-primitive "^1.0.2" +unbox-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e" + integrity sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw== + dependencies: + call-bind "^1.0.2" + has-bigints "^1.0.2" + has-symbols "^1.0.3" + which-boxed-primitive "^1.0.2" + uri-js@^4.2.2: version "4.2.2" resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" diff --git a/repo-config/package.json b/repo-config/package.json index b332353dfebc..b28f4e453a0e 100644 --- a/repo-config/package.json +++ b/repo-config/package.json @@ -20,20 +20,18 @@ "clang-format": "^1.2.4", "connect": "^3.6.5", "coveralls": "^3.1.1", - "eslint": "^7.32.0", - "eslint-config-fb-strict": "^26.0.0", - "eslint-config-fbjs": "^3.1.1", - "eslint-config-prettier": "^8.3.0", + "eslint": "^8.19.0", + "eslint-config-prettier": "^8.5.0", "eslint-plugin-babel": "^5.3.1", "eslint-plugin-eslint-comments": "^3.2.0", - "eslint-plugin-flowtype": "^7.0.0", - "eslint-plugin-jest": "^25.2.4", - "eslint-plugin-jsx-a11y": "^6.4.1", - "eslint-plugin-prettier": "^4.0.0", - "eslint-plugin-react": "^7.26.1", - "eslint-plugin-react-hooks": "^4.2.0", - "eslint-plugin-react-native": "^3.11.0", - "eslint-plugin-relay": "^1.8.2", + "eslint-plugin-ft-flow": "^2.0.1", + "eslint-plugin-jest": "^26.5.3", + "eslint-plugin-jsx-a11y": "^6.6.0", + "eslint-plugin-prettier": "^4.2.1", + "eslint-plugin-react": "^7.30.1", + "eslint-plugin-react-hooks": "^4.6.0", + "eslint-plugin-react-native": "^4.0.0", + "eslint-plugin-relay": "^1.8.3", "flow-bin": "^0.182.0", "inquirer": "^7.1.0", "jest": "^26.6.3", diff --git a/template/package.json b/template/package.json index 32c8110e38ab..17116fe088e7 100644 --- a/template/package.json +++ b/template/package.json @@ -18,7 +18,7 @@ "@babel/runtime": "^7.12.5", "@react-native-community/eslint-config": "^2.0.0", "babel-jest": "^26.6.3", - "eslint": "^7.32.0", + "eslint": "^8.19.0", "jest": "^26.6.3", "metro-react-native-babel-preset": "^0.71.3", "react-test-renderer": "18.1.0" diff --git a/yarn.lock b/yarn.lock index 0adb083d6c98..78882cf943f2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11,13 +11,6 @@ "@jridgewell/trace-mapping" "^0.2.2" sourcemap-codec "1.4.8" -"@babel/code-frame@7.12.11": - version "7.12.11" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.11.tgz#f4ad435aa263db935b8f10f2c552d23fb716a63f" - integrity sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw== - dependencies: - "@babel/highlight" "^7.10.4" - "@babel/code-frame@^7.0.0", "@babel/code-frame@^7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.7.tgz#44416b6bd7624b998f5b1af5d470856c40138789" @@ -276,7 +269,7 @@ "@babel/traverse" "^7.17.0" "@babel/types" "^7.17.0" -"@babel/highlight@^7.10.4", "@babel/highlight@^7.16.7": +"@babel/highlight@^7.16.7": version "7.16.10" resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.16.10.tgz#744f2eb81579d6eea753c227b0f570ad785aba88" integrity sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw== @@ -745,13 +738,20 @@ core-js-pure "^3.19.0" regenerator-runtime "^0.13.4" -"@babel/runtime@^7.0.0", "@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.8.4": +"@babel/runtime@^7.0.0", "@babel/runtime@^7.10.2", "@babel/runtime@^7.8.4": version "7.17.9" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.9.tgz#d19fbf802d01a8cb6cf053a64e472d42c434ba72" integrity sha512-lSiBBvodq29uShpWGNbgFdKYNiFDo5/HIYsaCEY9ff4sb10x9jizo2+pRrSyF4jKZCXqgzuqBOQKbUm90gQwJg== dependencies: regenerator-runtime "^0.13.4" +"@babel/runtime@^7.18.3": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.18.6.tgz#6a1ef59f838debd670421f8c7f2cbb8da9751580" + integrity sha512-t9wi7/AW6XtKahAe20Yw0/mMljKq0B1r2fPdvaAdV/KPDZewFXdaaa6K7lxmZBZ8FBNpCiAT6iHPmd6QO9bKfQ== + dependencies: + regenerator-runtime "^0.13.4" + "@babel/template@^7.0.0", "@babel/template@^7.16.7", "@babel/template@^7.3.3": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.16.7.tgz#8d126c8701fde4d66b264b3eba3d96f07666d155" @@ -798,19 +798,19 @@ exec-sh "^0.3.2" minimist "^1.2.0" -"@eslint/eslintrc@^0.4.3": - version "0.4.3" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.4.3.tgz#9e42981ef035beb3dd49add17acb96e8ff6f394c" - integrity sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw== +"@eslint/eslintrc@^1.3.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.3.0.tgz#29f92c30bb3e771e4a2048c95fa6855392dfac4f" + integrity sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw== dependencies: ajv "^6.12.4" - debug "^4.1.1" - espree "^7.3.0" - globals "^13.9.0" - ignore "^4.0.6" + debug "^4.3.2" + espree "^9.3.2" + globals "^13.15.0" + ignore "^5.2.0" import-fresh "^3.2.1" - js-yaml "^3.13.1" - minimatch "^3.0.4" + js-yaml "^4.1.0" + minimatch "^3.1.2" strip-json-comments "^3.1.1" "@hapi/hoek@^9.0.0": @@ -825,16 +825,16 @@ dependencies: "@hapi/hoek" "^9.0.0" -"@humanwhocodes/config-array@^0.5.0": - version "0.5.0" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.5.0.tgz#1407967d4c6eecd7388f83acf1eaf4d0c6e58ef9" - integrity sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg== +"@humanwhocodes/config-array@^0.9.2": + version "0.9.5" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.9.5.tgz#2cbaf9a89460da24b5ca6531b8bbfc23e1df50c7" + integrity sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw== dependencies: - "@humanwhocodes/object-schema" "^1.2.0" + "@humanwhocodes/object-schema" "^1.2.1" debug "^4.1.1" minimatch "^3.0.4" -"@humanwhocodes/object-schema@^1.2.0": +"@humanwhocodes/object-schema@^1.2.1": version "1.2.1" resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== @@ -1419,51 +1419,51 @@ dependencies: "@types/yargs-parser" "*" -"@typescript-eslint/experimental-utils@^5.0.0": - version "5.3.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-5.3.1.tgz#bbd8f9b67b4d5fdcb9d2f90297d8fcda22561e05" - integrity sha512-RgFn5asjZ5daUhbK5Sp0peq0SSMytqcrkNfU4pnDma2D8P3ElZ6JbYjY8IMSFfZAJ0f3x3tnO3vXHweYg0g59w== +"@typescript-eslint/scope-manager@5.30.5": + version "5.30.5" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.30.5.tgz#7f90b9d6800552c856a5f3644f5e55dd1469d964" + integrity sha512-NJ6F+YHHFT/30isRe2UTmIGGAiXKckCyMnIV58cE3JkHmaD6e5zyEYm5hBDv0Wbin+IC0T1FWJpD3YqHUG/Ydg== dependencies: - "@types/json-schema" "^7.0.9" - "@typescript-eslint/scope-manager" "5.3.1" - "@typescript-eslint/types" "5.3.1" - "@typescript-eslint/typescript-estree" "5.3.1" - eslint-scope "^5.1.1" - eslint-utils "^3.0.0" - -"@typescript-eslint/scope-manager@5.3.1": - version "5.3.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.3.1.tgz#3cfbfbcf5488fb2a9a6fbbe97963ee1e8d419269" - integrity sha512-XksFVBgAq0Y9H40BDbuPOTUIp7dn4u8oOuhcgGq7EoDP50eqcafkMVGrypyVGvDYHzjhdUCUwuwVUK4JhkMAMg== - dependencies: - "@typescript-eslint/types" "5.3.1" - "@typescript-eslint/visitor-keys" "5.3.1" + "@typescript-eslint/types" "5.30.5" + "@typescript-eslint/visitor-keys" "5.30.5" -"@typescript-eslint/types@5.3.1": - version "5.3.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.3.1.tgz#afaa715b69ebfcfde3af8b0403bf27527912f9b7" - integrity sha512-bG7HeBLolxKHtdHG54Uac750eXuQQPpdJfCYuw4ZI3bZ7+GgKClMWM8jExBtp7NSP4m8PmLRM8+lhzkYnSmSxQ== +"@typescript-eslint/types@5.30.5": + version "5.30.5" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.30.5.tgz#36a0c05a72af3623cdf9ee8b81ea743b7de75a98" + integrity sha512-kZ80w/M2AvsbRvOr3PjaNh6qEW1LFqs2pLdo2s5R38B2HYXG8Z0PP48/4+j1QHJFL3ssHIbJ4odPRS8PlHrFfw== -"@typescript-eslint/typescript-estree@5.3.1": - version "5.3.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.3.1.tgz#50cc4bfb93dc31bc75e08ae52e29fcb786d606ec" - integrity sha512-PwFbh/PKDVo/Wct6N3w+E4rLZxUDgsoII/GrWM2A62ETOzJd4M6s0Mu7w4CWsZraTbaC5UQI+dLeyOIFF1PquQ== +"@typescript-eslint/typescript-estree@5.30.5": + version "5.30.5" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.30.5.tgz#c520e4eba20551c4ec76af8d344a42eb6c9767bb" + integrity sha512-qGTc7QZC801kbYjAr4AgdOfnokpwStqyhSbiQvqGBLixniAKyH+ib2qXIVo4P9NgGzwyfD9I0nlJN7D91E1VpQ== dependencies: - "@typescript-eslint/types" "5.3.1" - "@typescript-eslint/visitor-keys" "5.3.1" - debug "^4.3.2" - globby "^11.0.4" + "@typescript-eslint/types" "5.30.5" + "@typescript-eslint/visitor-keys" "5.30.5" + debug "^4.3.4" + globby "^11.1.0" is-glob "^4.0.3" - semver "^7.3.5" + semver "^7.3.7" tsutils "^3.21.0" -"@typescript-eslint/visitor-keys@5.3.1": - version "5.3.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.3.1.tgz#c2860ff22939352db4f3806f34b21d8ad00588ba" - integrity sha512-3cHUzUuVTuNHx0Gjjt5pEHa87+lzyqOiHXy/Gz+SJOCW1mpw9xQHIIEwnKn+Thph1mgWyZ90nboOcSuZr/jTTQ== +"@typescript-eslint/utils@^5.10.0": + version "5.30.5" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.30.5.tgz#3999cbd06baad31b9e60d084f20714d1b2776765" + integrity sha512-o4SSUH9IkuA7AYIfAvatldovurqTAHrfzPApOZvdUq01hHojZojCFXx06D/aFpKCgWbMPRdJBWAC3sWp3itwTA== + dependencies: + "@types/json-schema" "^7.0.9" + "@typescript-eslint/scope-manager" "5.30.5" + "@typescript-eslint/types" "5.30.5" + "@typescript-eslint/typescript-estree" "5.30.5" + eslint-scope "^5.1.1" + eslint-utils "^3.0.0" + +"@typescript-eslint/visitor-keys@5.30.5": + version "5.30.5" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.30.5.tgz#d4bb969202019d5d5d849a0aaedc7370cc044b14" + integrity sha512-D+xtGo9HUMELzWIUqcQc0p2PO4NyvTrgIOK/VnSH083+8sq0tiLozNRKuLarwHYGRuA6TVBQSuuLwJUDWd3aaA== dependencies: - "@typescript-eslint/types" "5.3.1" - eslint-visitor-keys "^3.0.0" + "@typescript-eslint/types" "5.30.5" + eslint-visitor-keys "^3.3.0" abab@^2.0.3, abab@^2.0.5: version "2.0.5" @@ -1498,7 +1498,7 @@ acorn-globals@^6.0.0: acorn "^7.1.1" acorn-walk "^7.1.1" -acorn-jsx@^5.3.1: +acorn-jsx@^5.3.2: version "5.3.2" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== @@ -1508,7 +1508,7 @@ acorn-walk@^7.1.1: resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc" integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA== -acorn@^7.1.1, acorn@^7.4.0: +acorn@^7.1.1: version "7.4.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== @@ -1518,6 +1518,11 @@ acorn@^8.2.4: resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.0.tgz#90951fde0f8f09df93549481e5fc141445b791cf" integrity sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ== +acorn@^8.7.1: + version "8.7.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.1.tgz#0197122c843d1bf6d0a5e83220a788f278f63c30" + integrity sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A== + agent-base@6: version "6.0.2" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" @@ -1535,26 +1540,11 @@ ajv@^6.10.0, ajv@^6.12.3, ajv@^6.12.4: json-schema-traverse "^0.4.1" uri-js "^4.2.2" -ajv@^8.0.1: - version "8.9.0" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.9.0.tgz#738019146638824dea25edcf299dcba1b0e7eb18" - integrity sha512-qOKJyNj/h+OWx7s5DePL6Zu1KeM9jPZhwBqs+7DzP6bGOvqzVCSf0xueYmVuaC/oQ/VtS2zLMLHdQFbkka+XDQ== - dependencies: - fast-deep-equal "^3.1.1" - json-schema-traverse "^1.0.0" - require-from-string "^2.0.2" - uri-js "^4.2.2" - anser@^1.4.9: version "1.4.9" resolved "https://registry.yarnpkg.com/anser/-/anser-1.4.9.tgz#1f85423a5dcf8da4631a341665ff675b96845760" integrity sha512-AI+BjTeGt2+WFk4eWcqbQ7snZpDBt8SaLlj0RT2h5xfdWaiy51OjYvqwMrNzJLGy8iOAL6nKDITWO+rd4MkYEA== -ansi-colors@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" - integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== - ansi-escapes@^4.2.1: version "4.3.1" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.1.tgz#a5c47cc43181f1f38ffd7076837700d395522a61" @@ -1624,6 +1614,11 @@ argparse@^1.0.7: dependencies: sprintf-js "~1.0.2" +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + aria-query@^4.2.2: version "4.2.2" resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-4.2.2.tgz#0d2ca6c9aceb56b8977e9fed6aed7e15bbd2f83b" @@ -1647,7 +1642,7 @@ arr-union@^3.1.0: resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= -array-includes@^3.1.1, array-includes@^3.1.3: +array-includes@^3.1.3: version "3.1.4" resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.4.tgz#f5b493162c760f3539631f005ba2bb46acb45ba9" integrity sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw== @@ -1658,6 +1653,17 @@ array-includes@^3.1.1, array-includes@^3.1.3: get-intrinsic "^1.1.1" is-string "^1.0.7" +array-includes@^3.1.5: + version "3.1.5" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.5.tgz#2c320010db8d31031fd2a5f6b3bbd4b1aad31bdb" + integrity sha512-iSDYZMMyTPkiFasVqfuAQnWAYcvO/SeBSCGKePoEthjp4LEMTe4uLc7b025o4jAZpHhihh8xPo99TNWUWWkGDQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.19.5" + get-intrinsic "^1.1.1" + is-string "^1.0.7" + array-union@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" @@ -1668,14 +1674,15 @@ array-unique@^0.3.2: resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= -array.prototype.flatmap@^1.2.4: - version "1.2.5" - resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.2.5.tgz#908dc82d8a406930fdf38598d51e7411d18d4446" - integrity sha512-08u6rVyi1Lj7oqWbS9nUxliETrtIROT4XGTA4D/LWGten6E3ocm7cy9SIrmNHOL5XVbVuckUp3X6Xyg8/zpvHA== +array.prototype.flatmap@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.0.tgz#a7e8ed4225f4788a70cd910abcf0791e76a5534f" + integrity sha512-PZC9/8TKAIxcWKdyeb77EzULHPrIX/tIZebLJUQOMR1OwYosT8yggdfWScfTBCDj5utONvOuPQQumYsU2ULbkg== dependencies: - call-bind "^1.0.0" + call-bind "^1.0.2" define-properties "^1.1.3" - es-abstract "^1.19.0" + es-abstract "^1.19.2" + es-shim-unscopables "^1.0.0" asap@~2.0.6: version "2.0.6" @@ -1716,11 +1723,6 @@ astral-regex@^1.0.0: resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== -astral-regex@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" - integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== - async-limiter@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8" @@ -1756,10 +1758,10 @@ aws4@^1.8.0: resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59" integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA== -axe-core@^4.0.2: - version "4.3.5" - resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.3.5.tgz#78d6911ba317a8262bfee292aeafcc1e04b49cc5" - integrity sha512-WKTW1+xAzhMS5dJsxWkliixlO/PqC4VhmO9T4juNYcaTg9jzWiJsou6m5pxWYGfigWbwzJWeFY6z47a+4neRXA== +axe-core@^4.4.2: + version "4.4.2" + resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.4.2.tgz#dcf7fb6dea866166c3eab33d68208afe4d5f670c" + integrity sha512-LVAaGp/wkkgYJcjmHsoKx4juT1aQvJyPcW09MLCjVTh3V2cc6PnyempiLMNH5iMdfIX/zdbjUx2KDjMLCTdPeA== axobject-query@^2.2.0: version "2.2.0" @@ -2075,9 +2077,9 @@ camelcase@^6.0.0: integrity sha512-8KMDF1Vz2gzOq54ONPJS65IvTUaB1cHJ2DMM7MbPmLZljDH1qpzzLsWdiN9pHh6qvkRVDTi/07+eNGch/oLU4w== caniuse-lite@^1.0.30001286: - version "1.0.30001300" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001300.tgz#11ab6c57d3eb6f964cba950401fd00a146786468" - integrity sha512-cVjiJHWGcNlJi8TZVKNMnvMid3Z3TTdDHmLDzlOdIiZq138Exvo0G+G0wTdVYolxKb4AYwC+38pxodiInVtJSA== + version "1.0.30001364" + resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001364.tgz" + integrity sha512-9O0xzV3wVyX0SlegIQ6knz+okhBB5pE0PC40MNdwcipjwpxoUEHL24uJ+gG42cgklPjfO5ZjZPme9FTSN3QT2Q== capture-exit@^2.0.0: version "2.0.0" @@ -2394,10 +2396,10 @@ cssstyle@^2.3.0: dependencies: cssom "~0.3.6" -damerau-levenshtein@^1.0.6: - version "1.0.7" - resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.7.tgz#64368003512a1a6992593741a09a9d31a836f55d" - integrity sha512-VvdQIPGdWP0SqFXghj79Wf/5LArmreyMsGLa6FG6iC4t3j7j5s71TrwWmT/4akbDQIqjfACkLZmjXhA7g2oUZw== +damerau-levenshtein@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz#b43d286ccbd36bc5b2f7ed41caf2d0aba1f8a6e7" + integrity sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA== dashdash@^1.12.0: version "1.14.1" @@ -2427,13 +2429,20 @@ debug@2.6.9, debug@^2.2.0, debug@^2.3.3: dependencies: ms "2.0.0" -debug@4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.2: +debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.2: version "4.3.3" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== dependencies: ms "2.1.2" +debug@^4.3.4: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + decamelize@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" @@ -2478,6 +2487,14 @@ define-properties@^1.1.3: dependencies: object-keys "^1.0.12" +define-properties@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.4.tgz#0b14d7bd7fbeb2f3572c3a7eda80ea5d57fb05b1" + integrity sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA== + dependencies: + has-property-descriptors "^1.0.0" + object-keys "^1.1.1" + define-property@^0.2.5: version "0.2.5" resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" @@ -2586,7 +2603,7 @@ emoji-regex@^8.0.0: resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== -emoji-regex@^9.0.0: +emoji-regex@^9.2.2: version "9.2.2" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== @@ -2603,13 +2620,6 @@ end-of-stream@^1.1.0: dependencies: once "^1.4.0" -enquirer@^2.3.5: - version "2.3.6" - resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d" - integrity sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg== - dependencies: - ansi-colors "^4.1.1" - envinfo@^7.7.2: version "7.7.3" resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.7.3.tgz#4b2d8622e3e7366afb8091b23ed95569ea0208cc" @@ -2663,6 +2673,42 @@ es-abstract@^1.19.0, es-abstract@^1.19.1: string.prototype.trimstart "^1.0.4" unbox-primitive "^1.0.1" +es-abstract@^1.19.2, es-abstract@^1.19.5: + version "1.20.1" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.20.1.tgz#027292cd6ef44bd12b1913b828116f54787d1814" + integrity sha512-WEm2oBhfoI2sImeM4OF2zE2V3BYdSF+KnSi9Sidz51fQHd7+JuF8Xgcj9/0o+OWeIeIS/MiuNnlruQrJf16GQA== + dependencies: + call-bind "^1.0.2" + es-to-primitive "^1.2.1" + function-bind "^1.1.1" + function.prototype.name "^1.1.5" + get-intrinsic "^1.1.1" + get-symbol-description "^1.0.0" + has "^1.0.3" + has-property-descriptors "^1.0.0" + has-symbols "^1.0.3" + internal-slot "^1.0.3" + is-callable "^1.2.4" + is-negative-zero "^2.0.2" + is-regex "^1.1.4" + is-shared-array-buffer "^1.0.2" + is-string "^1.0.7" + is-weakref "^1.0.2" + object-inspect "^1.12.0" + object-keys "^1.1.1" + object.assign "^4.1.2" + regexp.prototype.flags "^1.4.3" + string.prototype.trimend "^1.0.5" + string.prototype.trimstart "^1.0.5" + unbox-primitive "^1.0.2" + +es-shim-unscopables@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz#702e632193201e3edf8713635d083d378e510241" + integrity sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w== + dependencies: + has "^1.0.3" + es-to-primitive@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" @@ -2709,22 +2755,10 @@ escodegen@^2.0.0: optionalDependencies: source-map "~0.6.1" -eslint-config-fb-strict@^26.0.0: - version "26.0.0" - resolved "https://registry.yarnpkg.com/eslint-config-fb-strict/-/eslint-config-fb-strict-26.0.0.tgz#a1d03fc53131d002d7ebcaad29eb84f1f260cb58" - integrity sha512-CjtTjz3QvDyoHAMjQfs+RjE5WJWBGyCRTRmzu1BTTefLi/fbbixt9j27eq2z+B7my9ooxZqlDcBbqcDFx6gR/A== - dependencies: - eslint-config-fbjs "^3.1.1" - -eslint-config-fbjs@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/eslint-config-fbjs/-/eslint-config-fbjs-3.1.1.tgz#f5b4c1df888693672116f000527a8df25d61b888" - integrity sha512-Vpyqz+ZcyLyiUGUdUfiQmZnxiQ4Nj/KDRKed/Y5qSm+xHbQJ5zcZUQwLUMWHQicpDHewsdXwlpUAblvy1DtGvg== - -eslint-config-prettier@^8.3.0: - version "8.3.0" - resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.3.0.tgz#f7471b20b6fe8a9a9254cc684454202886a2dd7a" - integrity sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew== +eslint-config-prettier@^8.5.0: + version "8.5.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz#5a81680ec934beca02c7b1a61cf8ca34b66feab1" + integrity sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q== eslint-plugin-babel@^5.3.1: version "5.3.1" @@ -2741,87 +2775,89 @@ eslint-plugin-eslint-comments@^3.2.0: escape-string-regexp "^1.0.5" ignore "^5.0.5" -eslint-plugin-flowtype@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-flowtype/-/eslint-plugin-flowtype-7.0.0.tgz#da07684b5f0caf7c42ed013c2d0c04dbaf2960f4" - integrity sha512-kW3eipG2Vth6e0apYqmFs05IHhFklJJNokYNiNEO5AIjm7H29oTDybYNB2bMULUYcf7iX7Wf3GdRhfBORKcT1g== +eslint-plugin-ft-flow@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-ft-flow/-/eslint-plugin-ft-flow-2.0.1.tgz#57d9a12ef02b7af8f9bd6ccd6bd8fa4034809716" + integrity sha512-dGBnCo+ok6H9p6Vw2oPFEM4vA9IEclRXQQAA/Zws51/L5zr3FDl9FxQiWGfaw0WaTIX5biiAxp/q1W5bGXjlVA== dependencies: lodash "^4.17.21" string-natural-compare "^3.0.1" -eslint-plugin-jest@^25.2.4: - version "25.2.4" - resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-25.2.4.tgz#bb9f6a0bd1fd524ffb0b8b7a159cd70a58a1a793" - integrity sha512-HRyinpgmEdkVr7pNPaYPHCoGqEzpgk79X8pg/xCeoAdurbyQjntJQ4pTzHl7BiVEBlam/F1Qsn+Dk0HtJO7Aaw== +eslint-plugin-jest@^26.5.3: + version "26.5.3" + resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-26.5.3.tgz#a3ceeaf4a757878342b8b00eca92379b246e5505" + integrity sha512-sICclUqJQnR1bFRZGLN2jnSVsYOsmPYYnroGCIMVSvTS3y8XR3yjzy1EcTQmk6typ5pRgyIWzbjqxK6cZHEZuQ== dependencies: - "@typescript-eslint/experimental-utils" "^5.0.0" + "@typescript-eslint/utils" "^5.10.0" -eslint-plugin-jsx-a11y@^6.4.1: - version "6.4.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.4.1.tgz#a2d84caa49756942f42f1ffab9002436391718fd" - integrity sha512-0rGPJBbwHoGNPU73/QCLP/vveMlM1b1Z9PponxO87jfr6tuH5ligXbDT6nHSSzBC8ovX2Z+BQu7Bk5D/Xgq9zg== +eslint-plugin-jsx-a11y@^6.6.0: + version "6.6.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.6.0.tgz#2c5ac12e013eb98337b9aa261c3b355275cc6415" + integrity sha512-kTeLuIzpNhXL2CwLlc8AHI0aFRwWHcg483yepO9VQiHzM9bZwJdzTkzBszbuPrbgGmq2rlX/FaT2fJQsjUSHsw== dependencies: - "@babel/runtime" "^7.11.2" + "@babel/runtime" "^7.18.3" aria-query "^4.2.2" - array-includes "^3.1.1" + array-includes "^3.1.5" ast-types-flow "^0.0.7" - axe-core "^4.0.2" + axe-core "^4.4.2" axobject-query "^2.2.0" - damerau-levenshtein "^1.0.6" - emoji-regex "^9.0.0" + damerau-levenshtein "^1.0.8" + emoji-regex "^9.2.2" has "^1.0.3" - jsx-ast-utils "^3.1.0" + jsx-ast-utils "^3.3.1" language-tags "^1.0.5" + minimatch "^3.1.2" + semver "^6.3.0" -eslint-plugin-prettier@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-4.0.0.tgz#8b99d1e4b8b24a762472b4567992023619cb98e0" - integrity sha512-98MqmCJ7vJodoQK359bqQWaxOE0CS8paAz/GgjaZLyex4TTk3g9HugoO89EqWCrFiOqn9EVvcoo7gZzONCWVwQ== +eslint-plugin-prettier@^4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz#651cbb88b1dab98bfd42f017a12fa6b2d993f94b" + integrity sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ== dependencies: prettier-linter-helpers "^1.0.0" -eslint-plugin-react-hooks@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.2.0.tgz#8c229c268d468956334c943bb45fc860280f5556" - integrity sha512-623WEiZJqxR7VdxFCKLI6d6LLpwJkGPYKODnkH3D7WpOG5KM8yWueBd8TLsNAetEJNF5iJmolaAKO3F8yzyVBQ== +eslint-plugin-react-hooks@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz#4c3e697ad95b77e93f8646aaa1630c1ba607edd3" + integrity sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g== eslint-plugin-react-native-globals@^0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/eslint-plugin-react-native-globals/-/eslint-plugin-react-native-globals-0.1.2.tgz#ee1348bc2ceb912303ce6bdbd22e2f045ea86ea2" integrity sha512-9aEPf1JEpiTjcFAmmyw8eiIXmcNZOqaZyHO77wgm0/dWfT/oxC1SrIq8ET38pMxHYrcB6Uew+TzUVsBeczF88g== -eslint-plugin-react-native@^3.11.0: - version "3.11.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-react-native/-/eslint-plugin-react-native-3.11.0.tgz#c73b0886abb397867e5e6689d3a6a418682e6bac" - integrity sha512-7F3OTwrtQPfPFd+VygqKA2VZ0f2fz0M4gJmry/TRE18JBb94/OtMxwbL7Oqwu7FGyrdeIOWnXQbBAveMcSTZIA== +eslint-plugin-react-native@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-react-native/-/eslint-plugin-react-native-4.0.0.tgz#eec41984abe4970bdd7c6082dff7a98a5e34d0bb" + integrity sha512-kMmdxrSY7A1WgdqaGC+rY/28rh7kBGNBRsk48ovqkQmdg5j4K+DaFmegENDzMrdLkoufKGRNkKX6bgSwQTCAxQ== dependencies: "@babel/traverse" "^7.7.4" eslint-plugin-react-native-globals "^0.1.1" -eslint-plugin-react@^7.26.1: - version "7.26.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.26.1.tgz#41bcfe3e39e6a5ac040971c1af94437c80daa40e" - integrity sha512-Lug0+NOFXeOE+ORZ5pbsh6mSKjBKXDXItUD2sQoT+5Yl0eoT82DqnXeTMfUare4QVCn9QwXbfzO/dBLjLXwVjQ== +eslint-plugin-react@^7.30.1: + version "7.30.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.30.1.tgz#2be4ab23ce09b5949c6631413ba64b2810fd3e22" + integrity sha512-NbEvI9jtqO46yJA3wcRF9Mo0lF9T/jhdHqhCHXiXtD+Zcb98812wvokjWpU7Q4QH5edo6dmqrukxVvWWXHlsUg== dependencies: - array-includes "^3.1.3" - array.prototype.flatmap "^1.2.4" + array-includes "^3.1.5" + array.prototype.flatmap "^1.3.0" doctrine "^2.1.0" - estraverse "^5.2.0" + estraverse "^5.3.0" jsx-ast-utils "^2.4.1 || ^3.0.0" - minimatch "^3.0.4" - object.entries "^1.1.4" - object.fromentries "^2.0.4" - object.hasown "^1.0.0" - object.values "^1.1.4" - prop-types "^15.7.2" + minimatch "^3.1.2" + object.entries "^1.1.5" + object.fromentries "^2.0.5" + object.hasown "^1.1.1" + object.values "^1.1.5" + prop-types "^15.8.1" resolve "^2.0.0-next.3" semver "^6.3.0" - string.prototype.matchall "^4.0.5" + string.prototype.matchall "^4.0.7" -eslint-plugin-relay@^1.8.2: - version "1.8.2" - resolved "https://registry.yarnpkg.com/eslint-plugin-relay/-/eslint-plugin-relay-1.8.2.tgz#925f59231e39dfc076b3cbb39ef793c13381579e" - integrity sha512-bqIfXJnPMd6iHPitONSi8JqxrWQWaX4Rqk1shusKDlUu5vswUgoqOEGgqE8nDu6SmejBUZMz0vY+ROvq5wqOsw== +eslint-plugin-relay@^1.8.3: + version "1.8.3" + resolved "https://registry.yarnpkg.com/eslint-plugin-relay/-/eslint-plugin-relay-1.8.3.tgz#3f320b79259c14c8112909568b208a08e7a9ebae" + integrity sha512-awyrwntUTZ7Z+lJUnniTCnJdZYr1dY2djQDARMx1P1y2BFMsBjtTljBK0lBEM7yiTHPBwVnE2OSnXxcD4yMb0A== dependencies: graphql "^14.0.0 || ^15.0.0" @@ -2838,12 +2874,13 @@ eslint-scope@^5.1.1: esrecurse "^4.3.0" estraverse "^4.1.1" -eslint-utils@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27" - integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg== +eslint-scope@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.1.1.tgz#fff34894c2f65e5226d3041ac480b4513a163642" + integrity sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw== dependencies: - eslint-visitor-keys "^1.1.0" + esrecurse "^4.3.0" + estraverse "^5.2.0" eslint-utils@^3.0.0: version "3.0.0" @@ -2852,75 +2889,65 @@ eslint-utils@^3.0.0: dependencies: eslint-visitor-keys "^2.0.0" -eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" - integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== - eslint-visitor-keys@^2.0.0, eslint-visitor-keys@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== -eslint-visitor-keys@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.1.0.tgz#eee4acea891814cda67a7d8812d9647dd0179af2" - integrity sha512-yWJFpu4DtjsWKkt5GeNBBuZMlNcYVs6vRCLoCVEJrTjaSB6LC98gFipNK/erM2Heg/E8mIK+hXG/pJMLK+eRZA== +eslint-visitor-keys@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826" + integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== -eslint@^7.32.0: - version "7.32.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.32.0.tgz#c6d328a14be3fb08c8d1d21e12c02fdb7a2a812d" - integrity sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA== +eslint@^8.19.0: + version "8.19.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.19.0.tgz#7342a3cbc4fbc5c106a1eefe0fd0b50b6b1a7d28" + integrity sha512-SXOPj3x9VKvPe81TjjUJCYlV4oJjQw68Uek+AM0X4p+33dj2HY5bpTZOgnQHcG2eAm1mtCU9uNMnJi7exU/kYw== dependencies: - "@babel/code-frame" "7.12.11" - "@eslint/eslintrc" "^0.4.3" - "@humanwhocodes/config-array" "^0.5.0" + "@eslint/eslintrc" "^1.3.0" + "@humanwhocodes/config-array" "^0.9.2" ajv "^6.10.0" chalk "^4.0.0" cross-spawn "^7.0.2" - debug "^4.0.1" + debug "^4.3.2" doctrine "^3.0.0" - enquirer "^2.3.5" escape-string-regexp "^4.0.0" - eslint-scope "^5.1.1" - eslint-utils "^2.1.0" - eslint-visitor-keys "^2.0.0" - espree "^7.3.1" + eslint-scope "^7.1.1" + eslint-utils "^3.0.0" + eslint-visitor-keys "^3.3.0" + espree "^9.3.2" esquery "^1.4.0" esutils "^2.0.2" fast-deep-equal "^3.1.3" file-entry-cache "^6.0.1" functional-red-black-tree "^1.0.1" - glob-parent "^5.1.2" - globals "^13.6.0" - ignore "^4.0.6" + glob-parent "^6.0.1" + globals "^13.15.0" + ignore "^5.2.0" import-fresh "^3.0.0" imurmurhash "^0.1.4" is-glob "^4.0.0" - js-yaml "^3.13.1" + js-yaml "^4.1.0" json-stable-stringify-without-jsonify "^1.0.1" levn "^0.4.1" lodash.merge "^4.6.2" - minimatch "^3.0.4" + minimatch "^3.1.2" natural-compare "^1.4.0" optionator "^0.9.1" - progress "^2.0.0" - regexpp "^3.1.0" - semver "^7.2.1" - strip-ansi "^6.0.0" + regexpp "^3.2.0" + strip-ansi "^6.0.1" strip-json-comments "^3.1.0" - table "^6.0.9" text-table "^0.2.0" v8-compile-cache "^2.0.3" -espree@^7.3.0, espree@^7.3.1: - version "7.3.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-7.3.1.tgz#f2df330b752c6f55019f8bd89b7660039c1bbbb6" - integrity sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g== +espree@^9.3.2: + version "9.3.2" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.3.2.tgz#f58f77bd334731182801ced3380a8cc859091596" + integrity sha512-D211tC7ZwouTIuY5x9XnS0E9sWNChB7IYKX/Xp5eQj3nFXhqmiUDB9q27y76oFl8jTg3pXcQx/bpxMfs3CIZbA== dependencies: - acorn "^7.4.0" - acorn-jsx "^5.3.1" - eslint-visitor-keys "^1.3.0" + acorn "^8.7.1" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^3.3.0" esprima@^4.0.0, esprima@^4.0.1, esprima@~4.0.0: version "4.0.1" @@ -2951,6 +2978,11 @@ estraverse@^5.1.0, estraverse@^5.2.0: resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.2.0.tgz#307df42547e6cc7324d3cf03c155d5cdb8c53880" integrity sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ== +estraverse@^5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + esutils@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" @@ -3092,10 +3124,10 @@ fast-diff@^1.1.2: resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03" integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w== -fast-glob@^3.1.1: - version "3.2.7" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.7.tgz#fd6cb7a2d7e9aa7a7846111e85a196d6b2f766a1" - integrity sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q== +fast-glob@^3.2.9: + version "3.2.11" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.11.tgz#a1172ad95ceb8a16e20caa5c5e56480e5129c1d9" + integrity sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew== dependencies: "@nodelib/fs.stat" "^2.0.2" "@nodelib/fs.walk" "^1.2.3" @@ -3296,11 +3328,26 @@ function-bind@^1.1.1: resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== +function.prototype.name@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.5.tgz#cce0505fe1ffb80503e6f9e46cc64e46a12a9621" + integrity sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.0" + functions-have-names "^1.2.2" + functional-red-black-tree@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= +functions-have-names@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" + integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== + gensync@^1.0.0-beta.2: version "1.0.0-beta.2" resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" @@ -3366,6 +3413,13 @@ glob-parent@^5.1.2: dependencies: is-glob "^4.0.1" +glob-parent@^6.0.1: + version "6.0.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + glob@^7.0.0, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4: version "7.2.0" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" @@ -3383,23 +3437,23 @@ globals@^11.1.0: resolved "https://registry.yarnpkg.com/globals/-/globals-11.8.0.tgz#c1ef45ee9bed6badf0663c5cb90e8d1adec1321d" integrity sha512-io6LkyPVuzCHBSQV9fmOwxZkUk6nIaGmxheLDgmuFv89j0fm2aqDbIXKAGfzCMHqz3HLF2Zf8WSG6VqMh2qFmA== -globals@^13.6.0, globals@^13.9.0: - version "13.12.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-13.12.0.tgz#4d733760304230a0082ed96e21e5c565f898089e" - integrity sha512-uS8X6lSKN2JumVoXrbUz+uG4BYG+eiawqm3qFcT7ammfbUHeCBoJMlHcec/S3krSk73/AE/f0szYFmgAA3kYZg== +globals@^13.15.0: + version "13.16.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.16.0.tgz#9be4aca28f311aaeb974ea54978ebbb5e35ce46a" + integrity sha512-A1lrQfpNF+McdPOnnFqY3kSN0AFTy485bTi1bkLk4mVPODIUEcSfhHgRqA+QdXPksrSTTztYXx37NFV+GpGk3Q== dependencies: type-fest "^0.20.2" -globby@^11.0.4: - version "11.0.4" - resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.4.tgz#2cbaff77c2f2a62e71e9b2813a67b97a3a3001a5" - integrity sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg== +globby@^11.1.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" + integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== dependencies: array-union "^2.1.0" dir-glob "^3.0.1" - fast-glob "^3.1.1" - ignore "^5.1.4" - merge2 "^1.3.0" + fast-glob "^3.2.9" + ignore "^5.2.0" + merge2 "^1.4.1" slash "^3.0.0" graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.3, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@^4.2.0, graceful-fs@^4.2.4: @@ -3435,6 +3489,11 @@ has-bigints@^1.0.1: resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.1.tgz#64fe6acb020673e3b78db035a5af69aa9d07b113" integrity sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA== +has-bigints@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" + integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ== + has-flag@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" @@ -3445,11 +3504,23 @@ has-flag@^4.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== +has-property-descriptors@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz#610708600606d36961ed04c196193b6a607fa861" + integrity sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ== + dependencies: + get-intrinsic "^1.1.1" + has-symbols@^1.0.1, has-symbols@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.2.tgz#165d3070c00309752a1236a479331e3ac56f1423" integrity sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw== +has-symbols@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" + integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== + has-tostringtag@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" @@ -3605,16 +3676,16 @@ ieee754@^1.1.13: resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== -ignore@^4.0.6: - version "4.0.6" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" - integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== - -ignore@^5.0.5, ignore@^5.1.4: +ignore@^5.0.5: version "5.1.9" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.9.tgz#9ec1a5cbe8e1446ec60d4420060d43aa6e7382fb" integrity sha512-2zeMQpbKz5dhZ9IwL0gbxSW5w0NK/MSAMtNuhgIHEPmaU3vPdKPL0UdvUCXs5SS4JAwsBxysK5sFMW8ocFiVjQ== +ignore@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" + integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== + image-size@^0.6.0: version "0.6.3" resolved "https://registry.yarnpkg.com/image-size/-/image-size-0.6.3.tgz#e7e5c65bb534bd7cdcedd6cb5166272a85f75fb2" @@ -3866,6 +3937,11 @@ is-negative-zero@^2.0.1: resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.1.tgz#3de746c18dda2319241a53675908d8f766f11c24" integrity sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w== +is-negative-zero@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" + integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== + is-number-object@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.6.tgz#6a7aaf838c7f0686a50b4553f7e54a96494e89f0" @@ -3910,6 +3986,13 @@ is-shared-array-buffer@^1.0.1: resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz#97b0c85fbdacb59c9c446fe653b82cf2b5b7cfe6" integrity sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA== +is-shared-array-buffer@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79" + integrity sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA== + dependencies: + call-bind "^1.0.2" + is-stream@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" @@ -3951,6 +4034,13 @@ is-weakref@^1.0.1: dependencies: call-bind "^1.0.0" +is-weakref@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" + integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== + dependencies: + call-bind "^1.0.2" + is-windows@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" @@ -4531,6 +4621,13 @@ js-yaml@^3.13.0, js-yaml@^3.13.1: argparse "^1.0.7" esprima "^4.0.0" +js-yaml@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + jsbn@~0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" @@ -4624,11 +4721,6 @@ json-schema-traverse@^0.4.1: resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== -json-schema-traverse@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" - integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== - json-schema@0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.4.0.tgz#f7de4cf6efab838ebaeb3236474cbba5a1930ab5" @@ -4675,7 +4767,7 @@ jsprim@^1.2.2: json-schema "0.4.0" verror "1.10.0" -"jsx-ast-utils@^2.4.1 || ^3.0.0", jsx-ast-utils@^3.1.0: +"jsx-ast-utils@^2.4.1 || ^3.0.0": version "3.2.1" resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.2.1.tgz#720b97bfe7d901b927d87c3773637ae8ea48781b" integrity sha512-uP5vu8xfy2F9A6LGC22KO7e2/vGTS1MhP+18f++ZNlf0Ohaxbc9nIEwHAsejlJKyzfZzU5UIhe5ItYkitcZnZA== @@ -4683,6 +4775,14 @@ jsprim@^1.2.2: array-includes "^3.1.3" object.assign "^4.1.2" +jsx-ast-utils@^3.3.1: + version "3.3.2" + resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.3.2.tgz#afe5efe4332cd3515c065072bd4d6b0aa22152bd" + integrity sha512-4ZCADZHRkno244xlNnn4AOG6sRQ7iBZ5BbgZ4vW4y5IZw7cVUD1PPeblm1xx/nfmMxPdt/LHsXZW8z/j58+l9Q== + dependencies: + array-includes "^3.1.5" + object.assign "^4.1.2" + kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: version "3.2.2" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" @@ -4792,11 +4892,6 @@ lodash.throttle@^4.1.1: resolved "https://registry.yarnpkg.com/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4" integrity sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ= -lodash.truncate@^4.4.2: - version "4.4.2" - resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193" - integrity sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM= - lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.21, lodash@^4.7.0: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" @@ -4882,7 +4977,7 @@ merge-stream@^2.0.0: resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== -merge2@^1.3.0: +merge2@^1.3.0, merge2@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== @@ -5320,6 +5415,13 @@ minimatch@^3.0.2, minimatch@^3.0.4: dependencies: brace-expansion "^1.1.7" +minimatch@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + minimist@0.0.8: version "0.0.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" @@ -5526,6 +5628,11 @@ object-inspect@^1.11.0, object-inspect@^1.9.0: resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.11.0.tgz#9dceb146cedd4148a0d9e51ab88d34cf509922b1" integrity sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg== +object-inspect@^1.12.0: + version "1.12.2" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.2.tgz#c0641f26394532f28ab8d796ab954e43c009a8ea" + integrity sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ== + object-keys@^1.0.12, object-keys@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" @@ -5548,7 +5655,7 @@ object.assign@^4.1.0, object.assign@^4.1.2: has-symbols "^1.0.1" object-keys "^1.1.1" -object.entries@^1.1.4: +object.entries@^1.1.5: version "1.1.5" resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.5.tgz#e1acdd17c4de2cd96d5a08487cfb9db84d881861" integrity sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g== @@ -5557,7 +5664,7 @@ object.entries@^1.1.4: define-properties "^1.1.3" es-abstract "^1.19.1" -object.fromentries@^2.0.4: +object.fromentries@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.5.tgz#7b37b205109c21e741e605727fe8b0ad5fa08251" integrity sha512-CAyG5mWQRRiBU57Re4FKoTBjXfDoNwdFVH2Y1tS9PqCsfUTymAohOkEMSG3aRNKmv4lV3O7p1et7c187q6bynw== @@ -5566,13 +5673,13 @@ object.fromentries@^2.0.4: define-properties "^1.1.3" es-abstract "^1.19.1" -object.hasown@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/object.hasown/-/object.hasown-1.1.0.tgz#7232ed266f34d197d15cac5880232f7a4790afe5" - integrity sha512-MhjYRfj3GBlhSkDHo6QmvgjRLXQ2zndabdf3nX0yTyZK9rPfxb6uRpAac8HXNLy1GpqWtZ81Qh4v3uOls2sRAg== +object.hasown@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object.hasown/-/object.hasown-1.1.1.tgz#ad1eecc60d03f49460600430d97f23882cf592a3" + integrity sha512-LYLe4tivNQzq4JdaWW6WO3HMZZJWzkkH8fnI6EebWl0VZth2wL2Lovm74ep2/gZzlaTdV62JZHEqHQ2yVn8Q/A== dependencies: - define-properties "^1.1.3" - es-abstract "^1.19.1" + define-properties "^1.1.4" + es-abstract "^1.19.5" object.pick@^1.3.0: version "1.3.0" @@ -5581,7 +5688,7 @@ object.pick@^1.3.0: dependencies: isobject "^3.0.1" -object.values@^1.1.4: +object.values@^1.1.5: version "1.1.5" resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.5.tgz#959f63e3ce9ef108720333082131e4a459b716ac" integrity sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg== @@ -5884,11 +5991,6 @@ process-nextick-args@~2.0.0: resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" integrity sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw== -progress@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.0.tgz#8a1be366bf8fc23db2bd23f10c6fe920b4389d1f" - integrity sha1-ihvjZr+Pwj2yvSPxDG/pILQ4nR8= - promise@^8.0.3: version "8.0.3" resolved "https://registry.yarnpkg.com/promise/-/promise-8.0.3.tgz#f592e099c6cddc000d538ee7283bb190452b0bf6" @@ -5904,14 +6006,14 @@ prompts@^2.0.1, prompts@^2.4.0: kleur "^3.0.3" sisteransi "^1.0.5" -prop-types@^15.7.2: - version "15.7.2" - resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" - integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== +prop-types@^15.8.1: + version "15.8.1" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" + integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== dependencies: loose-envify "^1.4.0" object-assign "^4.1.1" - react-is "^16.8.1" + react-is "^16.13.1" psl@^1.1.28, psl@^1.1.33: version "1.8.0" @@ -5959,7 +6061,7 @@ react-devtools-core@4.24.0: resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.1.0.tgz#61aaed3096d30eacf2a2127118b5b41387d32a67" integrity sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg== -react-is@^16.8.1, react-is@^16.8.4: +react-is@^16.13.1, react-is@^16.8.4: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== @@ -6094,18 +6196,19 @@ regex-not@^1.0.0, regex-not@^1.0.2: extend-shallow "^3.0.2" safe-regex "^1.1.0" -regexp.prototype.flags@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz#7ef352ae8d159e758c0eadca6f8fcb4eef07be26" - integrity sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA== +regexp.prototype.flags@^1.4.1, regexp.prototype.flags@^1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz#87cab30f80f66660181a3bb7bf5981a872b367ac" + integrity sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA== dependencies: call-bind "^1.0.2" define-properties "^1.1.3" + functions-have-names "^1.2.2" -regexpp@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.1.0.tgz#206d0ad0a5648cffbdb8ae46438f3dc51c9f78e2" - integrity sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q== +regexpp@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" + integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== regexpu-core@^5.0.1: version "5.0.1" @@ -6177,11 +6280,6 @@ require-directory@^2.1.1: resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= -require-from-string@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" - integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== - require-main-filename@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" @@ -6358,13 +6456,20 @@ semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== -semver@^7.2.1, semver@^7.3.2, semver@^7.3.5: +semver@^7.3.2: version "7.3.5" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== dependencies: lru-cache "^6.0.0" +semver@^7.3.7: + version "7.3.7" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f" + integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g== + dependencies: + lru-cache "^6.0.0" + send@0.16.2: version "0.16.2" resolved "https://registry.yarnpkg.com/send/-/send-0.16.2.tgz#6ecca1e0f8c156d141597559848df64730a6bbc1" @@ -6517,15 +6622,6 @@ slice-ansi@^2.0.0: astral-regex "^1.0.0" is-fullwidth-code-point "^2.0.0" -slice-ansi@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" - integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ== - dependencies: - ansi-styles "^4.0.0" - astral-regex "^2.0.0" - is-fullwidth-code-point "^3.0.0" - snapdragon-node@^2.0.1: version "2.1.1" resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" @@ -6713,7 +6809,7 @@ string-natural-compare@^3.0.1: resolved "https://registry.yarnpkg.com/string-natural-compare/-/string-natural-compare-3.0.1.tgz#7a42d58474454963759e8e8b7ae63d71c1e7fdf4" integrity sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw== -string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: +string-width@^4.1.0, string-width@^4.2.0: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -6722,18 +6818,18 @@ string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" -string.prototype.matchall@^4.0.5: - version "4.0.6" - resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.6.tgz#5abb5dabc94c7b0ea2380f65ba610b3a544b15fa" - integrity sha512-6WgDX8HmQqvEd7J+G6VtAahhsQIssiZ8zl7zKh1VDMFyL3hRTJP4FTNA3RbIp2TOQ9AYNDcc7e3fH0Qbup+DBg== +string.prototype.matchall@^4.0.7: + version "4.0.7" + resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.7.tgz#8e6ecb0d8a1fb1fda470d81acecb2dba057a481d" + integrity sha512-f48okCX7JiwVi1NXCVWcFnZgADDC/n2vePlQ/KUCNqCikLLilQvwjMO8+BHVKvgzH0JB0J9LEPgxOGT02RoETg== dependencies: call-bind "^1.0.2" define-properties "^1.1.3" es-abstract "^1.19.1" get-intrinsic "^1.1.1" - has-symbols "^1.0.2" + has-symbols "^1.0.3" internal-slot "^1.0.3" - regexp.prototype.flags "^1.3.1" + regexp.prototype.flags "^1.4.1" side-channel "^1.0.4" string.prototype.trimend@^1.0.4: @@ -6744,6 +6840,15 @@ string.prototype.trimend@^1.0.4: call-bind "^1.0.2" define-properties "^1.1.3" +string.prototype.trimend@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz#914a65baaab25fbdd4ee291ca7dde57e869cb8d0" + integrity sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.19.5" + string.prototype.trimstart@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz#b36399af4ab2999b4c9c648bd7a3fb2bb26feeed" @@ -6752,6 +6857,15 @@ string.prototype.trimstart@^1.0.4: call-bind "^1.0.2" define-properties "^1.1.3" +string.prototype.trimstart@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz#5466d93ba58cfa2134839f81d7f42437e8c01fef" + integrity sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.19.5" + string_decoder@^1.1.1: version "1.3.0" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" @@ -6844,17 +6958,6 @@ symbol-tree@^3.2.4: resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== -table@^6.0.9: - version "6.7.3" - resolved "https://registry.yarnpkg.com/table/-/table-6.7.3.tgz#255388439715a738391bd2ee4cbca89a4d05a9b7" - integrity sha512-5DkIxeA7XERBqMwJq0aHZOdMadBx4e6eDoFRuyT5VR82J0Ycg2DwM6GfA/EQAhJ+toRTaS1lIdSQCqgrmhPnlw== - dependencies: - ajv "^8.0.1" - lodash.truncate "^4.4.2" - slice-ansi "^4.0.0" - string-width "^4.2.3" - strip-ansi "^6.0.1" - temp@0.8.3: version "0.8.3" resolved "https://registry.yarnpkg.com/temp/-/temp-0.8.3.tgz#e0c6bc4d26b903124410e4fed81103014dfc1f59" @@ -7076,6 +7179,16 @@ unbox-primitive@^1.0.1: has-symbols "^1.0.2" which-boxed-primitive "^1.0.2" +unbox-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e" + integrity sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw== + dependencies: + call-bind "^1.0.2" + has-bigints "^1.0.2" + has-symbols "^1.0.3" + which-boxed-primitive "^1.0.2" + unicode-canonical-property-names-ecmascript@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz#301acdc525631670d39f6146e0e77ff6bbdebddc" From 966f800b7cdc12b34e49cd1ac81e09c9430fff2e Mon Sep 17 00:00:00 2001 From: Vincent Riemer Date: Mon, 18 Jul 2022 14:12:25 -0700 Subject: [PATCH 0006/1165] Add key modifier properties to the PointerEvent interface Summary: Changelog: [iOS][Internal] - Add key modifier properties to the PointerEvent interface This diff adds implementations of the `ctrlKey`, `shiftKey`, `altKey`, and `metaKey` properties on the PointerEvent interface for iOS. Reviewed By: lunaleaps Differential Revision: D37869377 fbshipit-source-id: b187bae93fbfc97b6ca1d8d9786ad85343484b3d --- React/Fabric/RCTSurfaceTouchHandler.mm | 46 +++++++++++++++---- .../renderer/components/view/PointerEvent.cpp | 4 ++ .../renderer/components/view/PointerEvent.h | 16 +++++++ .../components/view/TouchEventEmitter.cpp | 4 ++ 4 files changed, 62 insertions(+), 8 deletions(-) diff --git a/React/Fabric/RCTSurfaceTouchHandler.mm b/React/Fabric/RCTSurfaceTouchHandler.mm index d60caf186205..d748a99641c5 100644 --- a/React/Fabric/RCTSurfaceTouchHandler.mm +++ b/React/Fabric/RCTSurfaceTouchHandler.mm @@ -83,6 +83,11 @@ typedef NS_ENUM(NSInteger, RCTTouchEventType) { */ UIEventButtonMask buttonMask; + /* + * The bit mask of modifier flags in the gesture represented by the receiver. + */ + UIKeyModifierFlags modifierFlags; + /* * A component view on which the touch was begun. */ @@ -178,8 +183,10 @@ static void UpdateActiveTouchWithUITouch( activeTouch.azimuthAngle = [uiTouch azimuthAngleInView:nil]; if (@available(iOS 13.4, *)) { activeTouch.buttonMask = uiEvent.buttonMask; + activeTouch.modifierFlags = uiEvent.modifierFlags; } else { activeTouch.buttonMask = 0; + activeTouch.modifierFlags = 0; } } @@ -248,6 +255,21 @@ static SharedTouchEventEmitter GetTouchEmitterFromView(UIView *componentView, CG } } +static void UpdatePointerEventModifierFlags(PointerEvent &event, UIKeyModifierFlags flags) +{ + if (@available(iOS 13.4, *)) { + event.ctrlKey = (flags & UIKeyModifierControl) != 0; + event.shiftKey = (flags & UIKeyModifierShift) != 0; + event.altKey = (flags & UIKeyModifierAlternate) != 0; + event.metaKey = (flags & UIKeyModifierCommand) != 0; + } else { + event.ctrlKey = false; + event.shiftKey = false; + event.altKey = false; + event.metaKey = false; + } +} + static PointerEvent CreatePointerEventFromActiveTouch(ActiveTouch activeTouch, RCTTouchEventType eventType) { Touch touch = activeTouch.touch; @@ -277,6 +299,8 @@ static PointerEvent CreatePointerEventFromActiveTouch(ActiveTouch activeTouch, R event.detail = 0; event.buttons = ButtonMaskToButtons(activeTouch.buttonMask); + UpdatePointerEventModifierFlags(event, activeTouch.modifierFlags); + // UIEvent's button mask for touch end events still marks the button as down // so this ensures it's set to 0 as per the pointer event spec if (eventType == RCTTouchEventTypeTouchEnd) { @@ -294,7 +318,7 @@ static PointerEvent CreatePointerEventFromIncompleteHoverData( CGPoint clientLocation, CGPoint screenLocation, CGPoint offsetLocation, - NSTimeInterval timestamp) + UIKeyModifierFlags modifierFlags) { PointerEvent event = {}; // "touch" events produced from a mouse cursor on iOS always have the ID 0 so @@ -312,6 +336,7 @@ static PointerEvent CreatePointerEventFromIncompleteHoverData( event.tiltY = 0; event.detail = 0; event.buttons = 0; + UpdatePointerEventModifierFlags(event, modifierFlags); event.tangentialPressure = 0.0; event.twist = 0; return event; @@ -695,9 +720,14 @@ - (void)hovering:(UIHoverGestureRecognizer *)recognizer API_AVAILABLE(ios(13.0)) CGPoint offsetLocation = [recognizer locationInView:targetView]; - NSOrderedSet *eventPathViews = GetTouchableViewsInPathToRoot(targetView); + UIKeyModifierFlags modifierFlags; + if (@available(iOS 13.4, *)) { + modifierFlags = recognizer.modifierFlags; + } else { + modifierFlags = 0; + } - NSTimeInterval timestamp = CACurrentMediaTime(); + NSOrderedSet *eventPathViews = GetTouchableViewsInPathToRoot(targetView); BOOL hasMoveListenerInEventPath = NO; @@ -707,7 +737,7 @@ - (void)hovering:(UIHoverGestureRecognizer *)recognizer API_AVAILABLE(ios(13.0)) SharedTouchEventEmitter eventEmitter = GetTouchEmitterFromView(targetView, [recognizer locationInView:targetView]); if (shouldEmitOverEvent && eventEmitter != nil) { PointerEvent event = CreatePointerEventFromIncompleteHoverData( - targetView, clientLocation, screenLocation, offsetLocation, timestamp); + targetView, clientLocation, screenLocation, offsetLocation, modifierFlags); eventEmitter->onPointerOver(event); } } @@ -730,7 +760,7 @@ - (void)hovering:(UIHoverGestureRecognizer *)recognizer API_AVAILABLE(ios(13.0)) GetTouchEmitterFromView(componentView, [recognizer locationInView:componentView]); if (eventEmitter != nil) { PointerEvent event = CreatePointerEventFromIncompleteHoverData( - componentView, clientLocation, screenLocation, offsetLocation, timestamp); + componentView, clientLocation, screenLocation, offsetLocation, modifierFlags); eventEmitter->onPointerEnter(event); } } @@ -749,7 +779,7 @@ - (void)hovering:(UIHoverGestureRecognizer *)recognizer API_AVAILABLE(ios(13.0)) SharedTouchEventEmitter eventEmitter = GetTouchEmitterFromView(targetView, [recognizer locationInView:targetView]); if (eventEmitter != nil) { PointerEvent event = CreatePointerEventFromIncompleteHoverData( - targetView, clientLocation, screenLocation, offsetLocation, timestamp); + targetView, clientLocation, screenLocation, offsetLocation, modifierFlags); eventEmitter->onPointerMove(event); } } @@ -761,7 +791,7 @@ - (void)hovering:(UIHoverGestureRecognizer *)recognizer API_AVAILABLE(ios(13.0)) GetTouchEmitterFromView(prevTargetView, [recognizer locationInView:prevTargetView]); if (shouldEmitOutEvent && eventEmitter != nil) { PointerEvent event = CreatePointerEventFromIncompleteHoverData( - prevTargetView, clientLocation, screenLocation, offsetLocation, timestamp); + prevTargetView, clientLocation, screenLocation, offsetLocation, modifierFlags); eventEmitter->onPointerOut(event); } } @@ -793,7 +823,7 @@ - (void)hovering:(UIHoverGestureRecognizer *)recognizer API_AVAILABLE(ios(13.0)) GetTouchEmitterFromView(componentView, [recognizer locationInView:componentView]); if (eventEmitter != nil) { PointerEvent event = CreatePointerEventFromIncompleteHoverData( - componentView, clientLocation, screenLocation, offsetLocation, timestamp); + componentView, clientLocation, screenLocation, offsetLocation, modifierFlags); eventEmitter->onPointerLeave(event); } } diff --git a/ReactCommon/react/renderer/components/view/PointerEvent.cpp b/ReactCommon/react/renderer/components/view/PointerEvent.cpp index 0a74065db6ff..ce0627986f91 100644 --- a/ReactCommon/react/renderer/components/view/PointerEvent.cpp +++ b/ReactCommon/react/renderer/components/view/PointerEvent.cpp @@ -35,6 +35,10 @@ std::vector getDebugProps( {"tangentialPressure", getDebugDescription(pointerEvent.tangentialPressure, options)}, {"twist", getDebugDescription(pointerEvent.twist, options)}, + {"ctrlKey", getDebugDescription(pointerEvent.ctrlKey, options)}, + {"shiftKey", getDebugDescription(pointerEvent.shiftKey, options)}, + {"altKey", getDebugDescription(pointerEvent.altKey, options)}, + {"metaKey", getDebugDescription(pointerEvent.metaKey, options)}, }; } diff --git a/ReactCommon/react/renderer/components/view/PointerEvent.h b/ReactCommon/react/renderer/components/view/PointerEvent.h index 1fc3f47d0b23..abe80ead9020 100644 --- a/ReactCommon/react/renderer/components/view/PointerEvent.h +++ b/ReactCommon/react/renderer/components/view/PointerEvent.h @@ -84,6 +84,22 @@ struct PointerEvent { * axis in degrees, with a value in the range 0 to 359. */ int twist; + /* + * Returns true if the control key was down when the event was fired. + */ + bool ctrlKey; + /* + * Returns true if the shift key was down when the event was fired. + */ + bool shiftKey; + /* + * Returns true if the alt key was down when the event was fired. + */ + bool altKey; + /* + * Returns true if the meta key was down when the event was fired. + */ + bool metaKey; }; #if RN_DEBUG_STRING_CONVERTIBLE diff --git a/ReactCommon/react/renderer/components/view/TouchEventEmitter.cpp b/ReactCommon/react/renderer/components/view/TouchEventEmitter.cpp index b6205781e5a4..8eb4bc8d1444 100644 --- a/ReactCommon/react/renderer/components/view/TouchEventEmitter.cpp +++ b/ReactCommon/react/renderer/components/view/TouchEventEmitter.cpp @@ -87,6 +87,10 @@ static jsi::Value pointerEventPayload( object.setProperty(runtime, "buttons", event.buttons); object.setProperty(runtime, "tangentialPressure", event.tangentialPressure); object.setProperty(runtime, "twist", event.twist); + object.setProperty(runtime, "ctrlKey", event.ctrlKey); + object.setProperty(runtime, "shiftKey", event.shiftKey); + object.setProperty(runtime, "altKey", event.altKey); + object.setProperty(runtime, "metaKey", event.metaKey); return object; } From 663dd9177efe94c6ead66cb4379009aefdca260c Mon Sep 17 00:00:00 2001 From: Vincent Riemer Date: Mon, 18 Jul 2022 14:12:25 -0700 Subject: [PATCH 0007/1165] Add the ability for tests to be marked as 'skipped' Summary: Changelog: [RNTester][Internal] - Add the ability for platform tests to be marked as skipped There are some properties/tests in the web platform tests that we don't want to especially priorities (especially if they aren't especially relevant to the specification and just legacy browser compat) so this adds the ability for us to mark these tests as skipped. This is so that we can ensure that our platform tests are "complete" while decreasing the noise and distraction from failing tests that don't really apply to RN. Reviewed By: lunaleaps Differential Revision: D37889470 fbshipit-source-id: 6516ac90c242d662518a95cb9ba8ce643f6bb09c --- .../Experimental/PlatformTest/README.md | 6 +- ...RNTesterPlatformTestMinimizedResultView.js | 41 ++++------ .../RNTesterPlatformTestResultView.js | 39 +++++----- .../RNTesterPlatformTestResultsText.js | 78 +++++++++++++++++++ .../PlatformTest/RNTesterPlatformTestTypes.js | 12 ++- .../PlatformTest/usePlatformTestHarness.js | 19 ++++- .../PointerEventSupport.js | 59 ++++++++++---- 7 files changed, 184 insertions(+), 70 deletions(-) create mode 100644 packages/rn-tester/js/examples/Experimental/PlatformTest/RNTesterPlatformTestResultsText.js diff --git a/packages/rn-tester/js/examples/Experimental/PlatformTest/README.md b/packages/rn-tester/js/examples/Experimental/PlatformTest/README.md index 7814ecb2405d..804e80900fb1 100644 --- a/packages/rn-tester/js/examples/Experimental/PlatformTest/README.md +++ b/packages/rn-tester/js/examples/Experimental/PlatformTest/README.md @@ -24,7 +24,7 @@ function ExampleTestCase ({ harness }) { /* ... */ } As of writting this README there are 2 different types of tests that the `harness` prop provides: -### `test(testcase: (TestContext) => void, testName: string)` +### `test(testcase: (TestContext) => void, testName: string, options?: TestOptions)` This is a method to create "regular" test reminicent of other frameworks such as Jest. These are meant to be run imperatively, and while that means that they technically could work in a `useEffect` hook as a way to run the test "on mount" — it is instead recommended to try and keep these tests in callbacks instead. A good alternative to running the test on mount would be to instead put the test in a callback and render a "Start Test" button which executes the callback. @@ -35,6 +35,10 @@ The first argument is the closure in which you will run your test and make asser * `assert_greater_than_equal(a: number, b: number, description: string): void` * `assert_less_than_equal(a: number, b: number, description: string): void` +An optional third argument can be used for specifying additional options to the test — that object currently has the following properties (all of which are optional themselves): + +* `skip: boolean`: In cases where we want the test to be registered but we don't want it to contribute to the pass/fail count. + Here's what a basic/contrived example which verifies the layout of a basic view: ```js diff --git a/packages/rn-tester/js/examples/Experimental/PlatformTest/RNTesterPlatformTestMinimizedResultView.js b/packages/rn-tester/js/examples/Experimental/PlatformTest/RNTesterPlatformTestMinimizedResultView.js index 275ede2a7105..ed9a2b2080a1 100644 --- a/packages/rn-tester/js/examples/Experimental/PlatformTest/RNTesterPlatformTestMinimizedResultView.js +++ b/packages/rn-tester/js/examples/Experimental/PlatformTest/RNTesterPlatformTestMinimizedResultView.js @@ -10,6 +10,8 @@ import type {ViewStyleProp} from 'react-native/Libraries/StyleSheet/StyleSheet'; +import RNTesterPlatformTestResultsText from './RNTesterPlatformTestResultsText'; + import * as React from 'react'; import {View, Text, StyleSheet, TouchableHighlight} from 'react-native'; @@ -18,6 +20,7 @@ type Props = $ReadOnly<{| numError: number, numPass: number, numPending: number, + numSkipped: number, onPress?: () => void, style?: ?ViewStyleProp, |}>; @@ -26,26 +29,22 @@ export default function RNTesterPlatformTestMinimizedResultView({ numError, numPass, numPending, + numSkipped, onPress, style, }: Props): React.MixedElement { return ( - - - {numPass} Pass - - - {numFail} Fail - - - {numError} Error - - - {numPending} Pending - - + + + @@ -59,12 +58,6 @@ const styles = StyleSheet.create({ marginEnd: 8, opacity: 0.5, }, - errorText: { - color: 'orange', - }, - failText: { - color: 'red', - }, innerContainer: { width: '100%', height: '100%', @@ -74,12 +67,6 @@ const styles = StyleSheet.create({ paddingHorizontal: 8, backgroundColor: 'white', }, - passText: { - color: 'green', - }, - pendingText: { - color: 'gray', - }, root: { borderTopColor: 'rgb(171, 171, 171)', borderTopWidth: StyleSheet.hairlineWidth, @@ -89,8 +76,6 @@ const styles = StyleSheet.create({ flexDirection: 'row', alignItems: 'center', justifyContent: 'flex-start', - }, - summaryText: { marginStart: 8, }, }); diff --git a/packages/rn-tester/js/examples/Experimental/PlatformTest/RNTesterPlatformTestResultView.js b/packages/rn-tester/js/examples/Experimental/PlatformTest/RNTesterPlatformTestResultView.js index fbe4696c7bb0..d33f5ba82c14 100644 --- a/packages/rn-tester/js/examples/Experimental/PlatformTest/RNTesterPlatformTestResultView.js +++ b/packages/rn-tester/js/examples/Experimental/PlatformTest/RNTesterPlatformTestResultView.js @@ -19,6 +19,7 @@ import type { } from './RNTesterPlatformTestTypes'; import RNTesterPlatformTestMinimizedResultView from './RNTesterPlatformTestMinimizedResultView'; +import RNTesterPlatformTestResultsText from './RNTesterPlatformTestResultsText'; import * as React from 'react'; import {useMemo, useState, useCallback} from 'react'; @@ -40,6 +41,7 @@ const DISPLAY_STATUS_MAPPING: {[PlatformTestResultStatus]: string} = { PASS: 'Pass', FAIL: 'Fail', ERROR: 'Error', + SKIPPED: 'Skipped', }; type FilterModalProps = $ReadOnly<{ @@ -183,7 +185,7 @@ export default function RNTesterPlatformTestResultView( ); }, [filterText, results]); - const {numPass, numFail, numError} = useMemo( + const {numPass, numFail, numError, numSkipped} = useMemo( () => filteredResults.reduce( (acc, result) => { @@ -194,12 +196,15 @@ export default function RNTesterPlatformTestResultView( return {...acc, numFail: acc.numFail + 1}; case 'ERROR': return {...acc, numError: acc.numError + 1}; + case 'SKIPPED': + return {...acc, numSkipped: acc.numSkipped + 1}; } }, { numPass: 0, numFail: 0, numError: 0, + numSkipped: 0, }, ), [filteredResults], @@ -228,6 +233,7 @@ export default function RNTesterPlatformTestResultView( numError={numError} numPass={numPass} numPending={numPending} + numSkipped={numSkipped} onPress={handleMinimizedPress} style={style} /> @@ -250,26 +256,13 @@ export default function RNTesterPlatformTestResultView( ) : null} - - {numPass} Pass - - {' '} - - {numFail} Fail - - {' '} - - {numError} Error - - {numPending > 0 ? ( - <> - {' '} - - {numPending}{' '} - Pending - - - ) : null} + @@ -399,6 +392,9 @@ const styles = StyleSheet.create({ paddingTop: 8, flex: 0, }, + skippedText: { + color: 'blue', + }, table: { flex: 1, }, @@ -446,4 +442,5 @@ const STATUS_TEXT_STYLE_MAPPING: {[PlatformTestResultStatus]: TextStyle} = { PASS: styles.passText, FAIL: styles.failText, ERROR: styles.errorText, + SKIPPED: styles.skippedText, }; diff --git a/packages/rn-tester/js/examples/Experimental/PlatformTest/RNTesterPlatformTestResultsText.js b/packages/rn-tester/js/examples/Experimental/PlatformTest/RNTesterPlatformTestResultsText.js new file mode 100644 index 000000000000..ee35d22d976c --- /dev/null +++ b/packages/rn-tester/js/examples/Experimental/PlatformTest/RNTesterPlatformTestResultsText.js @@ -0,0 +1,78 @@ +/** + * 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 + * @flow + */ + +import {Text, StyleSheet} from 'react-native'; +import * as React from 'react'; + +type Props = $ReadOnly<{ + numPass: number, + numFail: number, + numError: number, + numPending: number, + numSkipped: number, +}>; +export default function RNTesterPlatformTestResultsText( + props: Props, +): React.MixedElement { + const {numPass, numFail, numError, numPending, numSkipped} = props; + return ( + <> + + {numPass} Pass + + {' '} + + {numFail} Fail + + {numSkipped > 0 ? ( + <> + {' '} + + {numSkipped} Skipped + + + ) : null} + {numError > 0 ? ( + <> + {' '} + + {numError} Error + + + ) : null} + {numPending > 0 ? ( + <> + {' '} + + {numPending} Pending + + + ) : null} + + ); +} + +const styles = StyleSheet.create({ + errorText: { + color: 'orange', + }, + failText: { + color: 'red', + }, + passText: { + color: 'green', + }, + pendingText: { + color: 'gray', + }, + skippedText: { + color: 'blue', + }, +}); diff --git a/packages/rn-tester/js/examples/Experimental/PlatformTest/RNTesterPlatformTestTypes.js b/packages/rn-tester/js/examples/Experimental/PlatformTest/RNTesterPlatformTestTypes.js index 2097d43dd8d6..44184035bb6b 100644 --- a/packages/rn-tester/js/examples/Experimental/PlatformTest/RNTesterPlatformTestTypes.js +++ b/packages/rn-tester/js/examples/Experimental/PlatformTest/RNTesterPlatformTestTypes.js @@ -28,7 +28,7 @@ export type PlatformTestAssertionResult = | PassingPlatformTestAssertionResult | FailingPlatformTestAssertionResult; -export type PlatformTestResultStatus = 'PASS' | 'FAIL' | 'ERROR'; +export type PlatformTestResultStatus = 'PASS' | 'FAIL' | 'ERROR' | 'SKIPPED'; export type PlatformTestResult = $ReadOnly<{| name: string, @@ -50,8 +50,16 @@ export type AsyncPlatformTest = $ReadOnly<{| done(): void, |}>; +export type SyncTestOptions = $ReadOnly<{| + skip?: boolean, +|}>; + export type PlatformTestHarness = $ReadOnly<{| - test(testcase: PlatformTestCase, name: string): void, + test( + testcase: PlatformTestCase, + name: string, + options?: SyncTestOptions, + ): void, useAsyncTest(description: string, timeout?: number): AsyncPlatformTest, |}>; diff --git a/packages/rn-tester/js/examples/Experimental/PlatformTest/usePlatformTestHarness.js b/packages/rn-tester/js/examples/Experimental/PlatformTest/usePlatformTestHarness.js index 4216839d019d..b06f3298201b 100644 --- a/packages/rn-tester/js/examples/Experimental/PlatformTest/usePlatformTestHarness.js +++ b/packages/rn-tester/js/examples/Experimental/PlatformTest/usePlatformTestHarness.js @@ -16,6 +16,7 @@ import type { PlatformTestCase, PlatformTestAssertionResult, PlatformTestContext, + SyncTestOptions, } from './RNTesterPlatformTestTypes'; type AsyncTestStatus = 'NOT_RAN' | 'COMPLETED' | 'TIMED_OUT'; @@ -174,7 +175,23 @@ export default function usePlatformTestHarness(): PlatformTestHarnessHookResult }, []); const testFunction: PlatformTestHarness['test'] = useCallback( - (testCase: PlatformTestCase, name: string): void => { + ( + testCase: PlatformTestCase, + name: string, + options?: SyncTestOptions, + ): void => { + const {skip = false} = options ?? {}; + + if (skip) { + addTestResult({ + name, + status: 'SKIPPED', + assertions: [], + error: null, + }); + return; + } + const assertionResults: Array = []; const baseAssert = ( diff --git a/packages/rn-tester/js/examples/Experimental/W3CPointerEventPlatformTests/PointerEventSupport.js b/packages/rn-tester/js/examples/Experimental/W3CPointerEventPlatformTests/PointerEventSupport.js index 0fa7ceb46b5b..357109985679 100644 --- a/packages/rn-tester/js/examples/Experimental/W3CPointerEventPlatformTests/PointerEventSupport.js +++ b/packages/rn-tester/js/examples/Experimental/W3CPointerEventPlatformTests/PointerEventSupport.js @@ -14,6 +14,10 @@ import type {PointerEvent} from 'react-native/Libraries/Types/CoreEventTypes'; import {useMemo} from 'react'; +// These props are not in the specification but are present in the WPT so we keep them +// but marked as skipped so we don't prioritize them +const SKIPPED_PROPS = ['fromElement', 'toElement']; + // Check for conformance to PointerEvent interface // TA: 1.1, 1.2, 1.6, 1.7, 1.8, 1.9, 1.10, 1.11, 1.12, 1.13 // Adapted from https://github.com/web-platform-tests/wpt/blob/6c26371ea1c144dd612864a278e88b6ba2f3d883/pointerevents/pointerevent_support.js#L15 @@ -95,33 +99,54 @@ export function check_PointerEvent( const name = attr[2]; const value = attr[3]; + const skip = SKIPPED_PROPS.includes(name); + // existence check - harness.test(({assert_true}) => { - assert_true( - name in nativeEvent, - name + ' attribute in ' + eventType + ' event', - ); - }, pointerTestName + '.' + name + ' attribute exists'); + harness.test( + ({assert_true}) => { + assert_true( + name in nativeEvent, + name + ' attribute in ' + eventType + ' event', + ); + }, + pointerTestName + '.' + name + ' attribute exists', + {skip}, + ); // readonly check // TODO // type check - harness.test(({assert_true}) => { - assert_true( + harness.test( + ({assert_true}) => { + assert_true( + // $FlowFixMe + idl_type_check[type](nativeEvent[name]), + name + ' attribute of type ' + type, + ); + }, + pointerTestName + + '.' + + name + + ' IDL type ' + + type + + ' (JS type was ' + // $FlowFixMe - idl_type_check[type](nativeEvent[name]), - name + ' attribute of type ' + type, - ); - // $FlowFixMe - }, pointerTestName + '.' + name + ' IDL type ' + type + ' (JS type was ' + typeof nativeEvent[name] + ')'); + typeof nativeEvent[name] + + ')', + {skip}, + ); // value check if defined if (value !== undefined) { - harness.test(({assert_equals}) => { - // $FlowFixMe - assert_equals(nativeEvent[name], value, name + ' attribute value'); - }, pointerTestName + '.' + name + ' value is ' + String(value) + '.'); + harness.test( + ({assert_equals}) => { + // $FlowFixMe + assert_equals(nativeEvent[name], value, name + ' attribute value'); + }, + pointerTestName + '.' + name + ' value is ' + String(value) + '.', + {skip}, + ); } }); From 639daf8641b988aae80c26007c1b4a7f8ee0e17d Mon Sep 17 00:00:00 2001 From: Paige Sun Date: Mon, 18 Jul 2022 15:19:53 -0700 Subject: [PATCH 0008/1165] Minor: Rename AccessibilityInfo.sendAccessibilityEvent_unstable to sendAccessibilityEvent Summary: Changelog: [Internal] Rename AccessibilityInfo.sendAccessibilityEvent_unstable to sendAccessibilityEvent In Fabric, we want people to use `AccessibilityInfo.sendAccessibilityEvent` instead of `UIManager.sendAccessibilityEvent` for Android. The API is not unstable. There is a test in [AccessibilityExample.js](https://github.com/facebook/react-native/blob/c940eb0c49518b82a3999dcac3027aa70018c763/packages/rn-tester/js/examples/Accessibility/AccessibilityExample.js#L959) in RNTester to confirm that it works. A search for [`AccessibilityInfo.sendAccessibilityEvent_unstable` in Github](https://github.com/search?q=AccessibilityInfo.sendAccessibilityEvent_unstable&type=Code) shows that it's not being used yet, which makes sense because it's an Fabric API. Therefore it's safe to rename it. Reviewed By: sammy-SC Differential Revision: D37901006 fbshipit-source-id: 73f35b09ca8f9337f4d66a431f0a3f815da38249 --- Libraries/Components/AccessibilityInfo/AccessibilityInfo.js | 2 +- Libraries/ReactNative/BridgelessUIManager.js | 2 +- jest/setup.js | 2 +- .../rn-tester/js/examples/Accessibility/AccessibilityExample.js | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Libraries/Components/AccessibilityInfo/AccessibilityInfo.js b/Libraries/Components/AccessibilityInfo/AccessibilityInfo.js index 150635d8531a..1217cad123c2 100644 --- a/Libraries/Components/AccessibilityInfo/AccessibilityInfo.js +++ b/Libraries/Components/AccessibilityInfo/AccessibilityInfo.js @@ -315,7 +315,7 @@ const AccessibilityInfo = { /** * Send a named accessibility event to a HostComponent. */ - sendAccessibilityEvent_unstable( + sendAccessibilityEvent( handle: ElementRef>, eventType: AccessibilityEventTypes, ) { diff --git a/Libraries/ReactNative/BridgelessUIManager.js b/Libraries/ReactNative/BridgelessUIManager.js index 0b959568a372..3347b6a91bc4 100644 --- a/Libraries/ReactNative/BridgelessUIManager.js +++ b/Libraries/ReactNative/BridgelessUIManager.js @@ -146,7 +146,7 @@ module.exports = { errorMessageForMethod('setLayoutAnimationEnabledExperimental'), ); }, - // Please use AccessibilityInfo.sendAccessibilityEvent_unstable instead. + // Please use AccessibilityInfo.sendAccessibilityEvent instead. // See SetAccessibilityFocusExample in AccessibilityExample.js for a migration example. sendAccessibilityEvent: (reactTag: ?number, eventType: number): void => console.error(errorMessageForMethod('sendAccessibilityEvent')), diff --git a/jest/setup.js b/jest/setup.js index ae32f2f02eba..8a53d7e8d6ec 100644 --- a/jest/setup.js +++ b/jest/setup.js @@ -132,7 +132,7 @@ jest isScreenReaderEnabled: jest.fn(() => Promise.resolve(false)), removeEventListener: jest.fn(), setAccessibilityFocus: jest.fn(), - sendAccessibilityEvent_unstable: jest.fn(), + sendAccessibilityEvent: jest.fn(), getRecommendedTimeoutMillis: jest.fn(), }, })) diff --git a/packages/rn-tester/js/examples/Accessibility/AccessibilityExample.js b/packages/rn-tester/js/examples/Accessibility/AccessibilityExample.js index fb917d19dc32..d4b14b5b7853 100644 --- a/packages/rn-tester/js/examples/Accessibility/AccessibilityExample.js +++ b/packages/rn-tester/js/examples/Accessibility/AccessibilityExample.js @@ -956,7 +956,7 @@ function SetAccessibilityFocusExample(props: {}): React.Node { const onPress = () => { if (myRef && myRef.current) { - AccessibilityInfo.sendAccessibilityEvent_unstable(myRef.current, 'focus'); + AccessibilityInfo.sendAccessibilityEvent(myRef.current, 'focus'); } }; From 61792339657b12f43318e842aba48c7043e40168 Mon Sep 17 00:00:00 2001 From: Daniel Andersson Date: Mon, 18 Jul 2022 15:29:50 -0700 Subject: [PATCH 0009/1165] Add API for setting/getting native state Summary: Add API for setting/getting native state. When present, the internal NativeState property of an object always stores a NativeState with a pointer to a heap-allocated shared_ptr + a finalizer that simply `delete`s it. Changelog: [Internal][Added] - JSI API for setting/getting native state on a JS object Reviewed By: jpporto Differential Revision: D36499239 fbshipit-source-id: a1ff1905811db1aac99ece3f928b81d0abfb342b --- ReactCommon/jsi/JSCRuntime.cpp | 21 +++++++++++++++++++++ ReactCommon/jsi/jsi/decorator.h | 11 +++++++++++ ReactCommon/jsi/jsi/jsi-inl.h | 18 ++++++++++++++++++ ReactCommon/jsi/jsi/jsi.cpp | 2 ++ ReactCommon/jsi/jsi/jsi.h | 32 ++++++++++++++++++++++++++++++++ 5 files changed, 84 insertions(+) diff --git a/ReactCommon/jsi/JSCRuntime.cpp b/ReactCommon/jsi/JSCRuntime.cpp index 5d8487b2cd5b..9eb578a229eb 100644 --- a/ReactCommon/jsi/JSCRuntime.cpp +++ b/ReactCommon/jsi/JSCRuntime.cpp @@ -168,6 +168,12 @@ class JSCRuntime : public jsi::Runtime { const jsi::Object &) override; jsi::HostFunctionType &getHostFunction(const jsi::Function &) override; + bool hasNativeState(const jsi::Object &) override; + std::shared_ptr getNativeState( + const jsi::Object &) override; + void setNativeState(const jsi::Object &, std::shared_ptr) + override; + jsi::Value getProperty(const jsi::Object &, const jsi::String &name) override; jsi::Value getProperty(const jsi::Object &, const jsi::PropNameID &name) override; @@ -862,6 +868,21 @@ std::shared_ptr JSCRuntime::getHostObject( return metadata->hostObject; } +bool JSCRuntime::hasNativeState(const jsi::Object &) { + throw std::logic_error("Not implemented"); +} + +std::shared_ptr JSCRuntime::getNativeState( + const jsi::Object &) { + throw std::logic_error("Not implemented"); +} + +void JSCRuntime::setNativeState( + const jsi::Object &, + std::shared_ptr) { + throw std::logic_error("Not implemented"); +} + jsi::Value JSCRuntime::getProperty( const jsi::Object &obj, const jsi::String &name) { diff --git a/ReactCommon/jsi/jsi/decorator.h b/ReactCommon/jsi/jsi/decorator.h index 6f239c051b7d..5c4811ac26ba 100644 --- a/ReactCommon/jsi/jsi/decorator.h +++ b/ReactCommon/jsi/jsi/decorator.h @@ -222,6 +222,17 @@ class RuntimeDecorator : public Base, private jsi::Instrumentation { return dhf.target()->plainHF_; }; + bool hasNativeState(const Object& o) override { + return plain_.hasNativeState(o); + } + std::shared_ptr getNativeState(const Object& o) override { + return plain_.getNativeState(o); + } + void setNativeState(const Object& o, std::shared_ptr state) + override { + plain_.setNativeState(o, state); + } + Value getProperty(const Object& o, const PropNameID& name) override { return plain_.getProperty(o, name); }; diff --git a/ReactCommon/jsi/jsi/jsi-inl.h b/ReactCommon/jsi/jsi/jsi-inl.h index 3823e8b25535..992ee9f535e8 100644 --- a/ReactCommon/jsi/jsi/jsi-inl.h +++ b/ReactCommon/jsi/jsi/jsi-inl.h @@ -202,6 +202,24 @@ inline std::shared_ptr Object::getHostObject( return runtime.getHostObject(*this); } +template +inline bool Object::hasNativeState(Runtime& runtime) const { + return runtime.hasNativeState(*this) && + std::dynamic_pointer_cast(runtime.getNativeState(*this)); +} + +template +inline std::shared_ptr Object::getNativeState(Runtime& runtime) const { + assert(hasNativeState(runtime)); + return std::static_pointer_cast(runtime.getNativeState(*this)); +} + +inline void Object::setNativeState( + Runtime& runtime, + std::shared_ptr state) const { + runtime.setNativeState(*this, state); +} + inline Array Object::getPropertyNames(Runtime& runtime) const { return runtime.getPropertyNames(*this); } diff --git a/ReactCommon/jsi/jsi/jsi.cpp b/ReactCommon/jsi/jsi/jsi.cpp index 3f56d0623b0b..c8fe78379eaf 100644 --- a/ReactCommon/jsi/jsi/jsi.cpp +++ b/ReactCommon/jsi/jsi/jsi.cpp @@ -81,6 +81,8 @@ void HostObject::set(Runtime& rt, const PropNameID& name, const Value&) { HostObject::~HostObject() {} +NativeState::~NativeState() {} + Runtime::~Runtime() {} Instrumentation& Runtime::instrumentation() { diff --git a/ReactCommon/jsi/jsi/jsi.h b/ReactCommon/jsi/jsi/jsi.h index 7c1479f00682..4dc4a8fe5dc0 100644 --- a/ReactCommon/jsi/jsi/jsi.h +++ b/ReactCommon/jsi/jsi/jsi.h @@ -128,6 +128,13 @@ class JSI_EXPORT HostObject { virtual std::vector getPropertyNames(Runtime& rt); }; +/// Native state (and destructor) that can be attached to any JS object +/// using setNativeState. +class JSI_EXPORT NativeState { + public: + virtual ~NativeState(); +}; + /// Represents a JS runtime. Movable, but not copyable. Note that /// this object may not be thread-aware, but cannot be used safely from /// multiple threads at once. The application is responsible for @@ -296,6 +303,12 @@ class JSI_EXPORT Runtime { virtual std::shared_ptr getHostObject(const jsi::Object&) = 0; virtual HostFunctionType& getHostFunction(const jsi::Function&) = 0; + virtual bool hasNativeState(const jsi::Object&) = 0; + virtual std::shared_ptr getNativeState(const jsi::Object&) = 0; + virtual void setNativeState( + const jsi::Object&, + std::shared_ptr state) = 0; + virtual Value getProperty(const Object&, const PropNameID& name) = 0; virtual Value getProperty(const Object&, const String& name) = 0; virtual bool hasProperty(const Object&, const PropNameID& name) = 0; @@ -711,6 +724,25 @@ class JSI_EXPORT Object : public Pointer { template std::shared_ptr asHostObject(Runtime& runtime) const; + /// \return whether this object has native state of type T previously set by + /// \c setNativeState. + template + bool hasNativeState(Runtime& runtime) const; + + /// \return a shared_ptr to the state previously set by \c setNativeState. + /// If \c hasNativeState is false, this will assert. Note that this does a + /// type check and will assert if the native state isn't of type \c T + template + std::shared_ptr getNativeState(Runtime& runtime) const; + + /// Set the internal native state property of this object, overwriting any old + /// value. Creates a new shared_ptr to the object managed by \p state, which + /// will live until the value at this property becomes unreachable. + /// + /// Throws a type error if this object is a proxy or host object. + void setNativeState(Runtime& runtime, std::shared_ptr state) + const; + /// \return same as \c getProperty(name).asObject(), except with /// a better exception message. Object getPropertyAsObject(Runtime& runtime, const char* name) const; From b708ee9b4e9df14ce227db00767b4b8c53fb6211 Mon Sep 17 00:00:00 2001 From: Ramanpreet Nara Date: Mon, 18 Jul 2022 17:54:37 -0700 Subject: [PATCH 0010/1165] Log if bridgeless mode is enabled, when JS Module call fails Summary: Log whether bridgeless mode is enabled or not when calling into a JavaScript module method fails. We are seeing a surge of these crashes in MessageQueue.js bridgeless mode. This temporary log will help us drill down into the issue. Changelog: [Internal] Created from CodeHub with https://fburl.com/edit-in-codehub This should not mess with the sitevar overrides. These are the two diffs where we mapped the venice and bridge errors to the same mid: D36649249, D36649249. Reviewed By: fkgozali Differential Revision: D37898744 fbshipit-source-id: 0ab337c8c0d73bd70c4756a16b8ece8ba8730c47 --- Libraries/BatchedBridge/MessageQueue.js | 5 ++++- Libraries/BatchedBridge/__tests__/MessageQueue-test.js | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Libraries/BatchedBridge/MessageQueue.js b/Libraries/BatchedBridge/MessageQueue.js index 2ae720810ac9..bfe3e0c08215 100644 --- a/Libraries/BatchedBridge/MessageQueue.js +++ b/Libraries/BatchedBridge/MessageQueue.js @@ -408,9 +408,12 @@ class MessageQueue { const callableModuleNames = Object.keys(this._lazyCallableModules); const n = callableModuleNames.length; const callableModuleNameList = callableModuleNames.join(', '); + + // TODO(T122225939): Remove after investigation: Why are we getting to this line in bridgeless mode? + const isBridgelessMode = global.RN$Bridgeless === true ? 'true' : 'false'; invariant( false, - `Failed to call into JavaScript module method ${module}.${method}(). Module has not been registered as callable. Registered callable JavaScript modules (n = ${n}): ${callableModuleNameList}. + `Failed to call into JavaScript module method ${module}.${method}(). Module has not been registered as callable. Bridgeless Mode: ${isBridgelessMode}. Registered callable JavaScript modules (n = ${n}): ${callableModuleNameList}. A frequent cause of the error is that the application entry file path is incorrect. This can also happen when the JS bundle is corrupt or there is an early initialization error when loading React Native.`, ); } diff --git a/Libraries/BatchedBridge/__tests__/MessageQueue-test.js b/Libraries/BatchedBridge/__tests__/MessageQueue-test.js index c94f580a1cbf..e80e024b6fed 100644 --- a/Libraries/BatchedBridge/__tests__/MessageQueue-test.js +++ b/Libraries/BatchedBridge/__tests__/MessageQueue-test.js @@ -108,7 +108,7 @@ describe('MessageQueue', function () { const unknownModule = 'UnknownModule', unknownMethod = 'UnknownMethod'; expect(() => queue.__callFunction(unknownModule, unknownMethod)).toThrow( - `Failed to call into JavaScript module method ${unknownModule}.${unknownMethod}(). Module has not been registered as callable. Registered callable JavaScript modules (n = 1): MessageQueueTestModule. + `Failed to call into JavaScript module method ${unknownModule}.${unknownMethod}(). Module has not been registered as callable. Bridgeless Mode: false. Registered callable JavaScript modules (n = 1): MessageQueueTestModule. A frequent cause of the error is that the application entry file path is incorrect. This can also happen when the JS bundle is corrupt or there is an early initialization error when loading React Native.`, ); }); From 089c9a5c9c9a60b6bbff6dda0c9eefa9d501a092 Mon Sep 17 00:00:00 2001 From: Nick Gerleman Date: Mon, 18 Jul 2022 18:20:22 -0700 Subject: [PATCH 0011/1165] Fix `AttributedString` comparison logic for TextInput state updates Summary: D37801394 (https://github.com/facebook/react-native/commit/51f49ca9982f24de08f5a5654a5210e547bb5b86) attempted to fix an issue of TextInput values being dropped when an uncontrolled component is restyled, and a defaultValue is present. I had missed quite a bit of functionality, where TextInput may have child Text elements, which the native side flattens into a single AttributedString. `lastNativeValue` includes a lossy version of the flattened string produced from the child fragments, so sending it along with the children led to duplicating of the current input on each edit, and things blow up. With some experimentation, I found that the text-loss behavior only happens on Fabric, and is triggered by a state update rather than my original assumption of the view manager command in the `useLayoutEffect` hook. `AndroidTextInputShadowNode` will compare the current and previous flattened strings, to intentionally allow the native value to drift from the React tree if the React tree hasn't changed. This `AttributedString` comparison includes layout metrics as of D20151505 (https://github.com/facebook/react-native/commit/061f54e89086af1c80e5b0460ec715533f99bdb7) meaning a restyle may cause a state update, and clear the text. I do not have full understanding of the flow of state updates to layout, or the underlying issue that led to the equality check including layout information (since TextMeasurementCache seems to explicitly compare LayoutMetrics). D18894538 (https://github.com/facebook/react-native/commit/254ebab1d2b6fac859ab1ae0c9503328fc99a6d0) used a solution of sending a no-op state update to avoid updating text for placeholders, when the Attributed strings are equal (though as of now this code is never reached, since we return earlier on AttributedString equality). I co-opted this mechanism, to avoid sending text updates if the text content and attributes of the AttributedString has not changed, disregarding any layout information. This is how the comparison worked at the time of the diff. I also updated the fragment hashing function to include layout metrics, since it was added to be part of the equality check, and is itself hashable. Changelog: [Android][Fixed] - Fix `AttributedString` comparison logic for TextInput state updates Reviewed By: sammy-SC Differential Revision: D37902643 fbshipit-source-id: c0f8e3112feb19bd0ee62b37bdadeb237a9f725e --- .../attributedstring/AttributedString.cpp | 19 ++++++++++++ .../attributedstring/AttributedString.h | 14 ++++++++- .../AndroidTextInputShadowNode.cpp | 12 ++++---- .../TextInput/TextInputSharedExamples.js | 29 +++++++++++++++++++ 4 files changed, 67 insertions(+), 7 deletions(-) diff --git a/ReactCommon/react/renderer/attributedstring/AttributedString.cpp b/ReactCommon/react/renderer/attributedstring/AttributedString.cpp index d2139c3a5270..124d44c6be36 100644 --- a/ReactCommon/react/renderer/attributedstring/AttributedString.cpp +++ b/ReactCommon/react/renderer/attributedstring/AttributedString.cpp @@ -38,6 +38,11 @@ bool Fragment::operator==(const Fragment &rhs) const { rhs.parentShadowView.layoutMetrics); } +bool Fragment::isContentEqual(const Fragment &rhs) const { + return std::tie(string, textAttributes) == + std::tie(rhs.string, rhs.textAttributes); +} + bool Fragment::operator!=(const Fragment &rhs) const { return !(*this == rhs); } @@ -126,6 +131,20 @@ bool AttributedString::operator!=(const AttributedString &rhs) const { return !(*this == rhs); } +bool AttributedString::isContentEqual(const AttributedString &rhs) const { + if (fragments_.size() != rhs.fragments_.size()) { + return false; + } + + for (auto i = 0; i < fragments_.size(); i++) { + if (!fragments_[i].isContentEqual(rhs.fragments_[i])) { + return false; + } + } + + return true; +} + #pragma mark - DebugStringConvertible #if RN_DEBUG_STRING_CONVERTIBLE diff --git a/ReactCommon/react/renderer/attributedstring/AttributedString.h b/ReactCommon/react/renderer/attributedstring/AttributedString.h index 22e205d002e6..2f1858c6f11c 100644 --- a/ReactCommon/react/renderer/attributedstring/AttributedString.h +++ b/ReactCommon/react/renderer/attributedstring/AttributedString.h @@ -46,6 +46,12 @@ class AttributedString : public Sealable, public DebugStringConvertible { */ bool isAttachment() const; + /* + * Returns whether the underlying text and attributes are equal, + * disregarding layout or other information. + */ + bool isContentEqual(const Fragment &rhs) const; + bool operator==(const Fragment &rhs) const; bool operator!=(const Fragment &rhs) const; }; @@ -96,6 +102,8 @@ class AttributedString : public Sealable, public DebugStringConvertible { */ bool compareTextAttributesWithoutFrame(const AttributedString &rhs) const; + bool isContentEqual(const AttributedString &rhs) const; + bool operator==(const AttributedString &rhs) const; bool operator!=(const AttributedString &rhs) const; @@ -118,7 +126,11 @@ struct hash { size_t operator()( const facebook::react::AttributedString::Fragment &fragment) const { return folly::hash::hash_combine( - 0, fragment.string, fragment.textAttributes, fragment.parentShadowView); + 0, + fragment.string, + fragment.textAttributes, + fragment.parentShadowView, + fragment.parentShadowView.layoutMetrics); } }; diff --git a/ReactCommon/react/renderer/components/textinput/androidtextinput/react/renderer/components/androidtextinput/AndroidTextInputShadowNode.cpp b/ReactCommon/react/renderer/components/textinput/androidtextinput/react/renderer/components/androidtextinput/AndroidTextInputShadowNode.cpp index fa497f2e13a6..5edf5badde22 100644 --- a/ReactCommon/react/renderer/components/textinput/androidtextinput/react/renderer/components/androidtextinput/AndroidTextInputShadowNode.cpp +++ b/ReactCommon/react/renderer/components/textinput/androidtextinput/react/renderer/components/androidtextinput/AndroidTextInputShadowNode.cpp @@ -141,17 +141,17 @@ void AndroidTextInputShadowNode::updateStateIfNeeded() { auto defaultTextAttributes = TextAttributes::defaultTextAttributes(); defaultTextAttributes.apply(getConcreteProps().textAttributes); - auto newEventCount = - (state.reactTreeAttributedString == reactTreeAttributedString - ? 0 - : getConcreteProps().mostRecentEventCount); - auto newAttributedString = getMostRecentAttributedString(); - // Even if we're here and updating state, it may be only to update the layout // manager If that is the case, make sure we don't update text: pass in the // current attributedString unchanged, and pass in zero for the "event count" // so no changes are applied There's no way to prevent a state update from // flowing to Java, so we just ensure it's a noop in those cases. + auto newEventCount = + state.reactTreeAttributedString.isContentEqual(reactTreeAttributedString) + ? 0 + : getConcreteProps().mostRecentEventCount; + auto newAttributedString = getMostRecentAttributedString(); + setStateData(AndroidTextInputState{ newEventCount, newAttributedString, diff --git a/packages/rn-tester/js/examples/TextInput/TextInputSharedExamples.js b/packages/rn-tester/js/examples/TextInput/TextInputSharedExamples.js index 44304d8d7765..2e9a4d754dcb 100644 --- a/packages/rn-tester/js/examples/TextInput/TextInputSharedExamples.js +++ b/packages/rn-tester/js/examples/TextInput/TextInputSharedExamples.js @@ -72,6 +72,14 @@ const styles = StyleSheet.create({ margin: 3, fontSize: 12, }, + focusedUncontrolled: { + margin: -2, + borderWidth: 2, + borderColor: '#0a0a0a', + flex: 1, + fontSize: 13, + padding: 4, + }, }); class WithLabel extends React.Component<$FlowFixMeProps> { @@ -477,6 +485,20 @@ class SelectionExample extends React.Component< } } +function UncontrolledExample() { + const [isFocused, setIsFocused] = React.useState(false); + + return ( + setIsFocused(true)} + onBlur={() => setIsFocused(false)} + /> + ); +} + module.exports = ([ { title: 'Auto-focus', @@ -696,4 +718,11 @@ module.exports = ([ ); }, }, + { + title: 'Uncontrolled component with layout changes', + name: 'uncontrolledComponent', + render: function (): React.Node { + return ; + }, + }, ]: Array); From 7d069b25835ad20654a46ebb1e09631d826598e0 Mon Sep 17 00:00:00 2001 From: Riccardo Cipolleschi Date: Tue, 19 Jul 2022 00:03:23 -0700 Subject: [PATCH 0012/1165] Extract Codegen code from the react_native_pods to its own file (#34176) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/34176 It extracts the code related to the codegen from the main `react_native_pods` script to a dedicated file, adding also tests. ## Changelog [iOS][Changed] - Move codegen in separate files Reviewed By: cortinico Differential Revision: D37755818 fbshipit-source-id: 99760d1def26ddbf065fdd234e0d183c2795513c --- scripts/cocoapods/__tests__/codegen-test.rb | 59 +++ .../cocoapods/__tests__/codegen_utils-test.rb | 435 ++++++++++++++++++ .../CodegenScriptPhaseExtractorMock.rb | 21 + .../__tests__/test_utils/CodegenUtilsMock.rb | 107 +++++ .../__tests__/test_utils/FinderMock.rb | 28 ++ .../__tests__/test_utils/PathnameMock.rb | 14 + scripts/cocoapods/__tests__/utils-test.rb | 2 +- scripts/cocoapods/codegen.rb | 35 ++ .../codegen_script_phase_extractor.rb | 13 + scripts/cocoapods/codegen_utils.rb | 286 ++++++++++++ scripts/cocoapods/helpers.rb | 8 + scripts/react_native_pods.rb | 253 +--------- 12 files changed, 1025 insertions(+), 236 deletions(-) create mode 100644 scripts/cocoapods/__tests__/codegen_utils-test.rb create mode 100644 scripts/cocoapods/__tests__/test_utils/CodegenScriptPhaseExtractorMock.rb create mode 100644 scripts/cocoapods/__tests__/test_utils/CodegenUtilsMock.rb create mode 100644 scripts/cocoapods/__tests__/test_utils/FinderMock.rb create mode 100644 scripts/cocoapods/codegen_script_phase_extractor.rb create mode 100644 scripts/cocoapods/codegen_utils.rb diff --git a/scripts/cocoapods/__tests__/codegen-test.rb b/scripts/cocoapods/__tests__/codegen-test.rb index 62526d9b4b50..ef574251c366 100644 --- a/scripts/cocoapods/__tests__/codegen-test.rb +++ b/scripts/cocoapods/__tests__/codegen-test.rb @@ -10,6 +10,7 @@ require_relative "./test_utils/FileMock.rb" require_relative "./test_utils/DirMock.rb" require_relative "./test_utils/systemUtils.rb" +require_relative "./test_utils/CodegenUtilsMock.rb" class CodegenTests < Test::Unit::TestCase :third_party_provider_header @@ -182,4 +183,62 @@ def testCheckAndGenerateEmptyThirdPartyProvider_whenBothMissing_buildCodegen() ] }) end + + # ================= # + # Test - RunCodegen # + # ================= # + def testRunCodegen_whenNewArchEnabled_runsCodegen + # Arrange + app_path = "~/app" + config_file = "" + codegen_utils_mock = CodegenUtilsMock.new() + + # Act + run_codegen!(app_path, config_file, :new_arch_enabled => true, :codegen_utils => codegen_utils_mock) + + # Assert + assert_equal(codegen_utils_mock.use_react_native_codegen_discovery_params, [{ + :app_path=>"~/app", + :codegen_disabled=>false, + :codegen_output_dir=>"build/generated/ios", + :config_file_dir=>"", + :fabric_enabled=>false, + :folly_version=>"2021.07.22.00", + :react_native_path=>"../node_modules/react-native" + }]) + assert_equal(codegen_utils_mock.get_react_codegen_spec_params, []) + assert_equal(codegen_utils_mock.generate_react_codegen_spec_params, []) + end + + def testRunCodegen_whenNewArchDisabled_runsCodegen + # Arrange + app_path = "~/app" + config_file = "" + package_json_file = "~/app/package.json" + codegen_specs = { "name" => "React-Codegen" } + codegen_utils_mock = CodegenUtilsMock.new(:react_codegen_spec => codegen_specs) + + # Act + run_codegen!( + app_path, + config_file, + :new_arch_enabled => false, + :fabric_enabled => true, + :package_json_file => package_json_file, + :codegen_utils => codegen_utils_mock) + + # Assert + assert_equal(codegen_utils_mock.use_react_native_codegen_discovery_params, []) + assert_equal(codegen_utils_mock.get_react_codegen_spec_params, [{ + :fabric_enabled => true, + :folly_version=>"2021.07.22.00", + :package_json_file => "~/app/package.json", + :script_phases => nil + }]) + assert_equal(codegen_utils_mock.generate_react_codegen_spec_params, [{ + :codegen_output_dir=>"build/generated/ios", + :react_codegen_spec=>{"name"=>"React-Codegen"} + }]) + + end end diff --git a/scripts/cocoapods/__tests__/codegen_utils-test.rb b/scripts/cocoapods/__tests__/codegen_utils-test.rb new file mode 100644 index 000000000000..e933b647b751 --- /dev/null +++ b/scripts/cocoapods/__tests__/codegen_utils-test.rb @@ -0,0 +1,435 @@ +# 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. + +require "test/unit" +require "json" +require_relative "../codegen_utils.rb" +require_relative "./test_utils/FileMock.rb" +require_relative "./test_utils/DirMock.rb" +require_relative "./test_utils/PodMock.rb" +require_relative "./test_utils/PathnameMock.rb" +require_relative "./test_utils/FinderMock.rb" +require_relative "./test_utils/CodegenUtilsMock.rb" +require_relative "./test_utils/CodegenScriptPhaseExtractorMock.rb" + +class CodegenUtilsTests < Test::Unit::TestCase + :base_path + + def setup + CodegenUtils.set_react_codegen_discovery_done(false) + CodegenUtils.set_react_codegen_podspec_generated(false) + Pod::Config.reset() + File.enable_testing_mode! + Dir.enable_testing_mode! + @base_path = "~/app/ios" + Pathname.pwd!(@base_path) + Pod::Config.instance.installation_root.relative_path_from = @base_path + end + + def teardown + Finder.reset() + Pathname.reset() + Pod::UI.reset() + Pod::Executable.reset() + File.reset() + Dir.reset() + end + + # ================================== # + # Test - GenerateReactCodegenPodspec # + # ================================== # + + def testGenerateReactCodegenPodspec_whenItHasBeenAlreadyGenerated_doesNothing + # Arrange + spec = { :name => "Test Podspec" } + codegen_output_dir = "build" + CodegenUtils.set_react_codegen_podspec_generated(true) + + # Act + CodegenUtils.new().generate_react_codegen_podspec!(spec, codegen_output_dir) + + # Assert + assert_equal(Pod::UI.collected_messages, ["[Codegen] Skipping React-Codegen podspec generation."]) + assert_equal(Pathname.pwd_invocation_count, 0) + assert_equal(Pod::Executable.executed_commands, []) + assert_equal(Pod::Config.instance.installation_root.relative_path_from_invocation_count, 0) + assert_true(CodegenUtils.react_codegen_podspec_generated) + end + + def testGenerateReactCodegenPodspec_whenItHasNotBeenAlreadyGenerated_generatesIt + # Arrange + spec = { :name => "Test Podspec" } + codegen_output_dir = "build" + + # Act + CodegenUtils.new().generate_react_codegen_podspec!(spec, codegen_output_dir) + + # Assert + assert_equal(Pathname.pwd_invocation_count, 1) + assert_equal(Pod::Config.instance.installation_root.relative_path_from_invocation_count, 1) + assert_equal(Pod::Executable.executed_commands, [{ "command" => 'mkdir', "arguments" => ["-p", "~/app/ios/build"]}]) + assert_equal(Pod::UI.collected_messages, ["[Codegen] Generating ~/app/ios/build/React-Codegen.podspec.json"]) + assert_equal(File.open_files_with_mode["~/app/ios/build/React-Codegen.podspec.json"], 'w') + assert_equal(File.open_files[0].collected_write, ['{"name":"Test Podspec"}']) + assert_equal(File.open_files[0].fsync_invocation_count, 1) + + assert_true(CodegenUtils.react_codegen_podspec_generated) + end + + # ========================== # + # Test - GetReactCodegenSpec # + # ========================== # + + def testGetReactCodegenSpec_whenFabricDisabledAndNoScriptPhases_generatesAPodspec + # Arrange + File.files_to_read('package.json' => '{ "version": "99.98.97"}') + + # Act + podspec = CodegenUtils.new().get_react_codegen_spec( + 'package.json', + :fabric_enabled => false, + :script_phases => nil + ) + + # Assert + assert_equal(podspec, get_podspec_no_fabric_no_script()) + assert_equal(Pod::UI.collected_messages, []) + end + + def testGetReactCodegenSpec_whenFabricEnabledAndScriptPhases_generatesAPodspec + # Arrange + File.files_to_read('package.json' => '{ "version": "99.98.97"}') + + # Act + podspec = CodegenUtils.new().get_react_codegen_spec( + 'package.json', + :fabric_enabled => true, + :script_phases => "echo Test Script Phase" + ) + + # Assert + assert_equal(podspec, get_podspec_fabric_and_script_phases("echo Test Script Phase")) + assert_equal(Pod::UI.collected_messages, ["[Codegen] Adding script_phases to React-Codegen."]) + end + + # =============================== # + # Test - GetCodegenConfigFromFile # + # =============================== # + + def testGetCodegenConfigFromFile_whenFileDoesNotExists_returnEmpty + # Arrange + + # Act + codegen = CodegenUtils.new().get_codegen_config_from_file('package.json', 'codegenConfig') + + # Assert + assert_equal(codegen, {'libraries' => []}) + end + + def testGetCodegenConfigFromFile_whenFileExistsButHasNoKey_returnEmpty + # Arrange + File.mocked_existing_files(['package.json']) + File.files_to_read('package.json' => '{ "codegenConfig": {}}') + + # Act + codegen = CodegenUtils.new().get_codegen_config_from_file('package.json', 'codegen') + + # Assert + assert_equal(codegen, {'libraries' => []}) + end + + def testGetCodegenConfigFromFile_whenFileExistsAndHasKey_returnObject + # Arrange + File.mocked_existing_files(['package.json']) + File.files_to_read('package.json' => '{ "codegenConfig": {"name": "MySpec"}}') + + # Act + codegen = CodegenUtils.new().get_codegen_config_from_file('package.json', 'codegenConfig') + + # Assert + assert_equal(codegen, { "name" => "MySpec"}) + end + + # ======================= # + # Test - GetListOfJSSpecs # + # ======================= # + def testGetListOfJSSpecs_whenUsesLibraries_returnAListOfFiles + # Arrange + app_codegen_config = { + 'libraries' => [ + { + 'name' => 'First Lib', + 'jsSrcsDir' => './firstlib/js' + }, + { + 'name' => 'Second Lib', + 'jsSrcsDir' => './secondlib/js' + }, + ] + } + app_path = "~/MyApp/" + Finder.set_files_for_paths({ + '~/MyApp/./firstlib/js' => ["MyFabricComponent1NativeComponent.js", "MyFabricComponent2NativeComponent.js"], + '~/MyApp/./secondlib/js' => ["NativeModule1.js", "NativeModule2.js"], + }) + + # Act + files = CodegenUtils.new().get_list_of_js_specs(app_codegen_config, app_path) + + # Assert + assert_equal(Pod::UI.collected_warns , ["[Deprecated] You are using the old `libraries` array to list all your codegen.\\nThis method will be removed in the future.\\nUpdate your `package.json` with a single object."]) + assert_equal(Finder.captured_paths, ['~/MyApp/./firstlib/js', '~/MyApp/./secondlib/js']) + assert_equal(files, [ + "${PODS_ROOT}/../MyFabricComponent1NativeComponent.js", + "${PODS_ROOT}/../MyFabricComponent2NativeComponent.js", + "${PODS_ROOT}/../NativeModule1.js", + "${PODS_ROOT}/../NativeModule2.js", + ]) + end + + def testGetListOfJSSpecs_whenDoesNotUsesLibraries_returnAListOfFiles + # Arrange + app_codegen_config = { + 'name' => 'First Lib', + 'jsSrcsDir' => './js' + } + + app_path = "~/MyApp/" + Finder.set_files_for_paths({ + '~/MyApp/./js' => ["MyFabricComponent1NativeComponent.js", "NativeModule1.js"], + }) + + # Act + files = CodegenUtils.new().get_list_of_js_specs(app_codegen_config, app_path) + + # Assert + assert_equal(Pod::UI.collected_warns , []) + assert_equal(Finder.captured_paths, ['~/MyApp/./js']) + assert_equal(files, [ + "${PODS_ROOT}/../MyFabricComponent1NativeComponent.js", + "${PODS_ROOT}/../NativeModule1.js", + ]) + end + + def testGetListOfJSSpecs_whenMisconfigured_aborts + # Arrange + app_codegen_config = {} + app_path = "~/MyApp/" + # Act + assert_raises() { + files = CodegenUtils.new().get_list_of_js_specs(app_codegen_config, app_path) + } + # Assert + assert_equal(Pod::UI.collected_warns , ["[Error] Codegen not properly configured. Please add the `codegenConfig` entry to your `package.json`"]) + + end + + # ================================== # + # Test - GetReactCodegenScriptPhases # + # ================================== # + + def testGetReactCodegenScriptPhases_whenAppPathNotDefined_abort + # Arrange + + # Act + assert_raises() { + CodegenUtils.new().get_react_codegen_script_phases(nil) + } + # Assert + assert_equal(Pod::UI.collected_warns, ["[Codegen] error: app_path is requried to use codegen discovery."]) + end + + def testGetReactCodegenScriptPhases_returnTheScriptObject + # Arrange + app_path = "~/MyApp" + input_files = ["${PODS_ROOT}/../MyFabricComponent1NativeComponent.js", "${PODS_ROOT}/../NativeModule1.js"] + computed_script = "echo ScriptPhases" + codegen_config = { "name" => "MyCodegenModule", "jsSrcsDir" => "./js"} + codegen_utils_mock = CodegenUtilsMock.new(:js_spec_list => input_files, :codegen_config => codegen_config) + script_phase_extractor_mock = CodegenScriptPhaseExtractorMock.new(computed_script) + + # Act + + scripts = CodegenUtils.new().get_react_codegen_script_phases( + app_path, + :codegen_utils => codegen_utils_mock, + :script_phase_extractor => script_phase_extractor_mock + ) + + # Assert + assert_equal(codegen_utils_mock.get_codegen_config_from_file_params, [{ + "config_key" => "codegenConfig", + "config_path" => "~/MyApp/package.json" + }]) + assert_equal(codegen_utils_mock.get_list_of_js_specs_params, [{ + "app_codegen_config" => {"jsSrcsDir"=>"./js", "name"=>"MyCodegenModule"}, + "app_path" => "~/MyApp" + }]) + assert_equal(script_phase_extractor_mock.extract_script_phase_params, [{ + fabric_enabled: false, + react_native_path: "../node_modules/react-native", + relative_app_root: "~/MyApp", + relative_config_file_dir: "" + }]) + assert_equal(scripts, { + 'name': 'Generate Specs', + 'execution_position': :before_compile, + 'input_files' => input_files, + 'show_env_vars_in_log': true, + 'output_files': ["${DERIVED_FILE_DIR}/react-codegen.log"], + 'script': computed_script + }) + end + + # ================================ # + # Test - UseReactCodegenDiscovery! # + # ================================ # + + def testUseReactCodegenDiscovery_whenCodegenDisabled_doNothing + # Arrange + + # Act + CodegenUtils.new().use_react_native_codegen_discovery!(true, nil) + + # Assert + assert_false(CodegenUtils.react_codegen_discovery_done()) + assert_equal(Pod::UI.collected_messages, []) + assert_equal(Pod::UI.collected_warns, []) + end + + def testUseReactCodegenDiscovery_whenDiscoveryDone_doNothing + # Arrange + CodegenUtils.set_react_codegen_discovery_done(true) + + # Act + CodegenUtils.new().use_react_native_codegen_discovery!(false, nil) + + # Assert + assert_true(CodegenUtils.react_codegen_discovery_done()) + assert_equal(Pod::UI.collected_messages, ["[Codegen] Skipping use_react_native_codegen_discovery."]) + assert_equal(Pod::UI.collected_warns, []) + end + + def testUseReactCodegenDiscovery_whenAppPathUndefined_abort + # Arrange + + # Act + assert_raises(){ + CodegenUtils.new().use_react_native_codegen_discovery!(false, nil) + } + + # Assert + assert_false(CodegenUtils.react_codegen_discovery_done()) + assert_equal(Pod::UI.collected_messages, []) + assert_equal(Pod::UI.collected_warns, [ + '[Codegen] Error: app_path is required for use_react_native_codegen_discovery.', + '[Codegen] If you are calling use_react_native_codegen_discovery! in your Podfile, please remove the call and pass `app_path` and/or `config_file_dir` to `use_react_native!`.' + ]) + end + + def testUseReactCodegenDiscovery_whenParametersAreGood_executeCodegen + # Arrange + app_path = "~/app" + computed_script = "echo TestScript" + codegen_spec = {"name" => "React-Codegen"} + + codegen_utils_mock = CodegenUtilsMock.new( + :react_codegen_script_phases => computed_script, + :react_codegen_spec => codegen_spec + ) + + # Act + CodegenUtils.new().use_react_native_codegen_discovery!( + false, + app_path, + :codegen_utils => codegen_utils_mock + ) + + # Assert + assert_true(CodegenUtils.react_codegen_discovery_done()) + assert_equal(Pod::UI.collected_warns, [ + '[Codegen] warn: using experimental new codegen integration' + ]) + assert_equal(codegen_utils_mock.get_react_codegen_script_phases_params, [{ + :app_path => "~/app", + :config_file_dir => "", + :config_key => "codegenConfig", + :fabric_enabled => false, + :react_native_path => "../node_modules/react-native"} + ]) + assert_equal(codegen_utils_mock.get_react_codegen_spec_params, [{ + :fabric_enabled => false, + :folly_version=>"2021.07.22.00", + :package_json_file => "../node_modules/react-native/package.json", + :script_phases => "echo TestScript" + }]) + assert_equal(codegen_utils_mock.generate_react_codegen_spec_params, [{ + :codegen_output_dir=>"build/generated/ios", + :react_codegen_spec=>{"name"=>"React-Codegen"} + }]) + assert_equal(Pod::Executable.executed_commands, [ + { + "command" => "node", + "arguments"=> ["~/app/ios/../node_modules/react-native/scripts/generate-artifacts.js", + "-p", "~/app", + "-o", Pod::Config.instance.installation_root, + "-e", "false", + "-c", ""] + } + ]) + end + + private + + def get_podspec_no_fabric_no_script + spec = { + 'name' => "React-Codegen", + 'version' => "99.98.97", + 'summary' => 'Temp pod for generated files for React Native', + 'homepage' => 'https://facebook.com/', + 'license' => 'Unlicense', + 'authors' => 'Facebook', + 'compiler_flags' => "-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -Wno-comma -Wno-shorten-64-to-32 -Wno-documentation -Wno-nullability-completeness -std=c++17", + 'source' => { :git => '' }, + 'header_mappings_dir' => './', + 'platforms' => { + 'ios' => '11.0', + }, + 'source_files' => "**/*.{h,mm,cpp}", + 'pod_target_xcconfig' => { "HEADER_SEARCH_PATHS" => + [ + "\"$(PODS_ROOT)/boost\"", + "\"$(PODS_ROOT)/RCT-Folly\"", + "\"${PODS_ROOT}/Headers/Public/React-Codegen/react/renderer/components\"", + "\"$(PODS_ROOT)/Headers/Private/React-Fabric\"", + "\"$(PODS_ROOT)/Headers/Private/React-RCTFabric\"", + ].join(' ') + }, + 'dependencies': { + "FBReactNativeSpec": ["99.98.97"], + "React-jsiexecutor": ["99.98.97"], + "RCT-Folly": ["2021.07.22.00"], + "RCTRequired": ["99.98.97"], + "RCTTypeSafety": ["99.98.97"], + "React-Core": ["99.98.97"], + "React-jsi": ["99.98.97"], + "ReactCommon/turbomodule/core": ["99.98.97"] + } + } + end + + def get_podspec_fabric_and_script_phases(script_phases) + specs = get_podspec_no_fabric_no_script() + + specs[:dependencies].merge!({ + 'React-graphics': ["99.98.97"], + 'React-rncore': ["99.98.97"], + }) + + specs[:'script_phases'] = script_phases + + return specs + end +end diff --git a/scripts/cocoapods/__tests__/test_utils/CodegenScriptPhaseExtractorMock.rb b/scripts/cocoapods/__tests__/test_utils/CodegenScriptPhaseExtractorMock.rb new file mode 100644 index 000000000000..621419d52a69 --- /dev/null +++ b/scripts/cocoapods/__tests__/test_utils/CodegenScriptPhaseExtractorMock.rb @@ -0,0 +1,21 @@ +# 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. + +class CodegenScriptPhaseExtractorMock + + attr_reader :extract_script_phase_params + @script_phase + + def initialize(script_phase) + @script_phase = script_phase + @extract_script_phase_params = [] + end + + def extract_script_phase(options) + @extract_script_phase_params.push(options) + return @script_phase + end + +end diff --git a/scripts/cocoapods/__tests__/test_utils/CodegenUtilsMock.rb b/scripts/cocoapods/__tests__/test_utils/CodegenUtilsMock.rb new file mode 100644 index 000000000000..8d9750157e2e --- /dev/null +++ b/scripts/cocoapods/__tests__/test_utils/CodegenUtilsMock.rb @@ -0,0 +1,107 @@ +# 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. + +class CodegenUtilsMock + @js_spec_list + @codegen_config + + @react_codegen_script_phases + @react_codegen_spec + + attr_reader :get_codegen_config_from_file_params + attr_reader :get_list_of_js_specs_params + attr_reader :get_react_codegen_script_phases_params + attr_reader :get_react_codegen_spec_params + attr_reader :generate_react_codegen_spec_params + attr_reader :use_react_native_codegen_discovery_params + + def initialize(js_spec_list: [], codegen_config: {}, react_codegen_script_phases: "", react_codegen_spec: {}) + @js_spec_list = js_spec_list + @codegen_config = codegen_config + @get_codegen_config_from_file_params = [] + @get_list_of_js_specs_params = [] + + @react_codegen_script_phases = react_codegen_script_phases + @react_codegen_spec = react_codegen_spec + @get_react_codegen_script_phases_params = [] + @get_react_codegen_spec_params = [] + @generate_react_codegen_spec_params = [] + @use_react_native_codegen_discovery_params = [] + end + + def get_codegen_config_from_file(config_path, config_key) + @get_codegen_config_from_file_params.push({ + "config_path" => config_path, + "config_key" => config_key + }) + return @codegen_config + end + + def get_list_of_js_specs(app_codegen_config, app_path) + @get_list_of_js_specs_params.push({ + "app_codegen_config" => app_codegen_config, + "app_path" => app_path + }) + return @js_spec_list + end + + def get_react_codegen_script_phases( + app_path, + fabric_enabled: false, + config_file_dir: '', + react_native_path: "../node_modules/react-native", + config_key: 'codegenConfig', + codegen_utils: CodegenUtils.new(), + script_phase_extractor: CodegenScriptPhaseExtractor.new() + ) + @get_react_codegen_script_phases_params.push({ + app_path: app_path, + fabric_enabled: fabric_enabled, + config_file_dir: config_file_dir, + react_native_path: react_native_path, + config_key: config_key + }) + return @react_codegen_script_phases + end + + def get_react_codegen_spec(package_json_file, folly_version: '2021.07.22.00', fabric_enabled: false, script_phases: nil) + @get_react_codegen_spec_params.push({ + package_json_file: package_json_file, + folly_version: folly_version, + fabric_enabled: fabric_enabled, + script_phases: script_phases + }) + return @react_codegen_spec + end + + def generate_react_codegen_podspec!(react_codegen_spec, codegen_output_dir) + @generate_react_codegen_spec_params.push({ + react_codegen_spec: react_codegen_spec, + codegen_output_dir: codegen_output_dir + }) + end + + def use_react_native_codegen_discovery!( + codegen_disabled, + app_path, + react_native_path: "../node_modules/react-native", + fabric_enabled: false, + config_file_dir: '', + codegen_output_dir: 'build/generated/ios', + config_key: 'codegenConfig', + folly_version: "2021.07.22.00", + codegen_utils: CodegenUtils.new() + ) + @use_react_native_codegen_discovery_params.push({ + codegen_disabled: codegen_disabled, + app_path: app_path, + react_native_path: react_native_path, + fabric_enabled: fabric_enabled, + config_file_dir: config_file_dir, + codegen_output_dir: codegen_output_dir, + folly_version: folly_version + }) + end +end diff --git a/scripts/cocoapods/__tests__/test_utils/FinderMock.rb b/scripts/cocoapods/__tests__/test_utils/FinderMock.rb new file mode 100644 index 000000000000..2d91d160104c --- /dev/null +++ b/scripts/cocoapods/__tests__/test_utils/FinderMock.rb @@ -0,0 +1,28 @@ +# 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. + +class Finder + @@captured_paths = [] + @@files_for_paths = {} + + + def self.find_codegen_file(path) + @@captured_paths.push(path) + return @@files_for_paths[path] + end + + def self.set_files_for_paths(files_for_paths) + @@files_for_paths = files_for_paths + end + + def self.captured_paths + return @@captured_paths + end + + def self.reset() + @@captured_paths = [] + @@files_for_paths = {} + end +end diff --git a/scripts/cocoapods/__tests__/test_utils/PathnameMock.rb b/scripts/cocoapods/__tests__/test_utils/PathnameMock.rb index 7aa763bc2e5c..0e4078fa0345 100644 --- a/scripts/cocoapods/__tests__/test_utils/PathnameMock.rb +++ b/scripts/cocoapods/__tests__/test_utils/PathnameMock.rb @@ -7,6 +7,20 @@ class Pathname @@pwd = "" @@pwd_invocation_count = 0 + attr_reader :path + + def initialize(path) + @path = path + end + + def realpath + return self + end + + def relative_path_from(path) + return @path + end + def self.pwd!(pwd) @@pwd = pwd end diff --git a/scripts/cocoapods/__tests__/utils-test.rb b/scripts/cocoapods/__tests__/utils-test.rb index b4cbaddca9d4..cb636838b92d 100644 --- a/scripts/cocoapods/__tests__/utils-test.rb +++ b/scripts/cocoapods/__tests__/utils-test.rb @@ -352,7 +352,7 @@ def test_applyMacCatalystPatches_correctlyAppliesNecessaryPatches third_target.build_configurations.each do |config| assert_equal(config.build_settings["CODE_SIGN_IDENTITY[sdk=macosx*]"], "-") end - + user_project_mock.native_targets.each do |target| target.build_configurations.each do |config| assert_equal(config.build_settings["DEAD_CODE_STRIPPING"], "YES") diff --git a/scripts/cocoapods/codegen.rb b/scripts/cocoapods/codegen.rb index fff57845ef12..9e144039db7c 100644 --- a/scripts/cocoapods/codegen.rb +++ b/scripts/cocoapods/codegen.rb @@ -65,3 +65,38 @@ def checkAndGenerateEmptyThirdPartyProvider!(react_native_path, new_arch_enabled File.delete(temp_schema_list_path) if File.exist?(temp_schema_list_path) end end + +def run_codegen!( + app_path, + config_file_dir, + new_arch_enabled: false, + disable_codegen: false, + react_native_path: "../node_modules/react-native", + fabric_enabled: false, + codegen_output_dir: 'build/generated/ios', + config_key: 'codegenConfig', + package_json_file: '~/app/package.json', + folly_version: '2021.07.22.00', + codegen_utils: CodegenUtils.new() + ) + if new_arch_enabled + codegen_utils.use_react_native_codegen_discovery!( + disable_codegen, + app_path, + :react_native_path => react_native_path, + :fabric_enabled => fabric_enabled, + :config_file_dir => config_file_dir, + :codegen_output_dir => codegen_output_dir, + :config_key => config_key, + :folly_version => folly_version + ) + else + # Generate a podspec file for generated files. + # This gets generated in use_react_native_codegen_discovery when codegen discovery is enabled. + react_codegen_spec = codegen_utils.get_react_codegen_spec( + package_json_file, + :fabric_enabled => fabric_enabled + ) + codegen_utils.generate_react_codegen_podspec!(react_codegen_spec, codegen_output_dir) + end +end diff --git a/scripts/cocoapods/codegen_script_phase_extractor.rb b/scripts/cocoapods/codegen_script_phase_extractor.rb new file mode 100644 index 000000000000..225ede7d2c47 --- /dev/null +++ b/scripts/cocoapods/codegen_script_phase_extractor.rb @@ -0,0 +1,13 @@ +# 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. + +class CodegenScriptPhaseExtractor + def initialize() + end + + def extract_script_phase(options) + get_script_phases_with_codegen_discovery(options) + end +end diff --git a/scripts/cocoapods/codegen_utils.rb b/scripts/cocoapods/codegen_utils.rb new file mode 100644 index 000000000000..1c1290b3d67b --- /dev/null +++ b/scripts/cocoapods/codegen_utils.rb @@ -0,0 +1,286 @@ +# 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. + +require 'json' +require_relative './helpers.rb' +require_relative './codegen_script_phase_extractor.rb' + +class CodegenUtils + + def initialize() + end + + @@REACT_CODEGEN_PODSPEC_GENERATED = false + + def self.set_react_codegen_podspec_generated(value) + @@REACT_CODEGEN_PODSPEC_GENERATED = value + end + + def self.react_codegen_podspec_generated + @@REACT_CODEGEN_PODSPEC_GENERATED + end + + @@REACT_CODEGEN_DISCOVERY_DONE = false + + def self.set_react_codegen_discovery_done(value) + @@REACT_CODEGEN_DISCOVERY_DONE = value + end + + def self.react_codegen_discovery_done + @@REACT_CODEGEN_DISCOVERY_DONE + end + + # It takes some cocoapods specs and writes them into a file + # + # Parameters + # - spec: the cocoapod specs + # - codegen_output_dir: the output directory for the codegen + def generate_react_codegen_podspec!(spec, codegen_output_dir) + # This podspec file should only be create once in the session/pod install. + # This happens when multiple targets are calling use_react_native!. + if @@REACT_CODEGEN_PODSPEC_GENERATED + Pod::UI.puts "[Codegen] Skipping React-Codegen podspec generation." + return + end + + relative_installation_root = Pod::Config.instance.installation_root.relative_path_from(Pathname.pwd) + output_dir = "#{relative_installation_root}/#{codegen_output_dir}" + Pod::Executable.execute_command("mkdir", ["-p", output_dir]); + + podspec_path = File.join(output_dir, 'React-Codegen.podspec.json') + Pod::UI.puts "[Codegen] Generating #{podspec_path}" + + File.open(podspec_path, 'w') do |f| + f.write(spec.to_json) + f.fsync + end + + @@REACT_CODEGEN_PODSPEC_GENERATED = true + end + + # It generates the podspec object that represents the `React-Codegen.podspec` file + # + # Parameters + # - package_json_file: the path to the `package.json`, required to extract the proper React Native version + # - fabric_enabled: whether fabric is enabled or not. + # - script_phases: whether we want to add some build script phases or not. + def get_react_codegen_spec(package_json_file, folly_version: '2021.07.22.00', fabric_enabled: false, script_phases: nil) + package = JSON.parse(File.read(package_json_file)) + version = package['version'] + + folly_compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -Wno-comma -Wno-shorten-64-to-32' + boost_compiler_flags = '-Wno-documentation' + + spec = { + 'name' => "React-Codegen", + 'version' => version, + 'summary' => 'Temp pod for generated files for React Native', + 'homepage' => 'https://facebook.com/', + 'license' => 'Unlicense', + 'authors' => 'Facebook', + 'compiler_flags' => "#{folly_compiler_flags} #{boost_compiler_flags} -Wno-nullability-completeness -std=c++17", + 'source' => { :git => '' }, + 'header_mappings_dir' => './', + 'platforms' => { + 'ios' => '11.0', + }, + 'source_files' => "**/*.{h,mm,cpp}", + 'pod_target_xcconfig' => { "HEADER_SEARCH_PATHS" => + [ + "\"$(PODS_ROOT)/boost\"", + "\"$(PODS_ROOT)/RCT-Folly\"", + "\"${PODS_ROOT}/Headers/Public/React-Codegen/react/renderer/components\"", + "\"$(PODS_ROOT)/Headers/Private/React-Fabric\"", + "\"$(PODS_ROOT)/Headers/Private/React-RCTFabric\"", + ].join(' ') + }, + 'dependencies': { + "FBReactNativeSpec": [version], + "React-jsiexecutor": [version], + "RCT-Folly": [folly_version], + "RCTRequired": [version], + "RCTTypeSafety": [version], + "React-Core": [version], + "React-jsi": [version], + "ReactCommon/turbomodule/core": [version] + } + } + + if fabric_enabled + spec[:'dependencies'].merge!({ + 'React-graphics': [version], + 'React-rncore': [version], + }); + end + + if script_phases + Pod::UI.puts "[Codegen] Adding script_phases to React-Codegen." + spec[:'script_phases'] = script_phases + end + + return spec + end + + # It extracts the codegen config from the configuration file + # + # Parameters + # - config_path: a path to the configuration file + # - config_ket: the codegen configuration key + # + # Returns: the list of dependencies as extracted from the package.json + def get_codegen_config_from_file(config_path, config_key) + empty = {'libraries' => []} + if !File.exist?(config_path) + return empty + end + + config = JSON.parse(File.read(config_path)) + return config[config_key] ? config[config_key] : empty + end + + # It creates a list of JS files that contains the JS specifications that Codegen needs to use to generate the code + # + # Parameters + # - app_codegen_config: an object that contains the configurations + # - app_path: path to the app + # + # Returns: the list of files that needs to be used by Codegen + def get_list_of_js_specs(app_codegen_config, app_path) + file_list = [] + + if app_codegen_config['libraries'] then + Pod::UI.warn '[Deprecated] You are using the old `libraries` array to list all your codegen.\nThis method will be removed in the future.\nUpdate your `package.json` with a single object.' + app_codegen_config['libraries'].each do |library| + library_dir = File.join(app_path, library['jsSrcsDir']) + file_list.concat(Finder.find_codegen_file(library_dir)) + end + elsif app_codegen_config['jsSrcsDir'] then + codegen_dir = File.join(app_path, app_codegen_config['jsSrcsDir']) + file_list.concat (Finder.find_codegen_file(codegen_dir)) + else + Pod::UI.warn '[Error] Codegen not properly configured. Please add the `codegenConfig` entry to your `package.json`' + abort + end + + input_files = file_list.map { |filename| "${PODS_ROOT}/../#{Pathname.new(filename).realpath().relative_path_from(Pod::Config.instance.installation_root)}" } + + return input_files + end + + # It generates the build script phase for the codegen + # + # Parameters + # - app_path: the path to the app + # - fabric_enabled: whether fabric is enabled or not + # - config_file_dir: the directory of the config file + # - react_native_path: the path to React Native + # - config_key: the configuration key to use in the package.json for the Codegen + # - codegen_utils: an object which exposes utilities functions for the codegen + # - script_phase_extractor: an object that is able to extract the Xcode Script Phases for React Native + # + # Return: an object containing the script phase + def get_react_codegen_script_phases( + app_path, + fabric_enabled: false, + config_file_dir: '', + react_native_path: "../node_modules/react-native", + config_key: 'codegenConfig', + codegen_utils: CodegenUtils.new(), + script_phase_extractor: CodegenScriptPhaseExtractor.new() + ) + if !app_path + Pod::UI.warn '[Codegen] error: app_path is requried to use codegen discovery.' + abort + end + + # We need to convert paths to relative path from installation_root for the script phase for CI. + relative_app_root = Pathname.new(app_path).realpath().relative_path_from(Pod::Config.instance.installation_root) + + relative_config_file_dir = '' + if config_file_dir != '' + relative_config_file_dir = Pathname.new(config_file_dir).relative_path_from(Pod::Config.instance.installation_root) + end + + # Generate input files for in-app libaraies which will be used to check if the script needs to be run. + # TODO: Ideally, we generate the input_files list from generate-artifacts.js and read the result here. + # Or, generate this podspec in generate-artifacts.js as well. + app_package_path = File.join(app_path, 'package.json') + app_codegen_config = codegen_utils.get_codegen_config_from_file(app_package_path, config_key) + input_files = codegen_utils.get_list_of_js_specs(app_codegen_config, app_path) + + # Add a script phase to trigger generate artifact. + # Some code is duplicated so that it's easier to delete the old way and switch over to this once it's stabilized. + return { + 'name': 'Generate Specs', + 'execution_position': :before_compile, + 'input_files' => input_files, + 'show_env_vars_in_log': true, + 'output_files': ["${DERIVED_FILE_DIR}/react-codegen.log"], + 'script': script_phase_extractor.extract_script_phase( + react_native_path: react_native_path, + relative_app_root: relative_app_root, + relative_config_file_dir: relative_config_file_dir, + fabric_enabled: fabric_enabled + ), + } + end + + def use_react_native_codegen_discovery!( + codegen_disabled, + app_path, + react_native_path: "../node_modules/react-native", + fabric_enabled: false, + config_file_dir: '', + codegen_output_dir: 'build/generated/ios', + config_key: 'codegenConfig', + folly_version: '2021.07.22.00', + codegen_utils: CodegenUtils.new() + ) + return if codegen_disabled + + if CodegenUtils.react_codegen_discovery_done() + Pod::UI.puts "[Codegen] Skipping use_react_native_codegen_discovery." + return + end + + if !app_path + Pod::UI.warn '[Codegen] Error: app_path is required for use_react_native_codegen_discovery.' + Pod::UI.warn '[Codegen] If you are calling use_react_native_codegen_discovery! in your Podfile, please remove the call and pass `app_path` and/or `config_file_dir` to `use_react_native!`.' + abort + end + + Pod::UI.warn '[Codegen] warn: using experimental new codegen integration' + relative_installation_root = Pod::Config.instance.installation_root.relative_path_from(Pathname.pwd) + + # Generate React-Codegen podspec here to add the script phases. + script_phases = codegen_utils.get_react_codegen_script_phases( + app_path, + :fabric_enabled => fabric_enabled, + :config_file_dir => config_file_dir, + :react_native_path => react_native_path, + :config_key => config_key + ) + react_codegen_spec = codegen_utils.get_react_codegen_spec( + File.join(react_native_path, "package.json"), + :folly_version => folly_version, + :fabric_enabled => fabric_enabled, + :script_phases => script_phases + ) + codegen_utils.generate_react_codegen_podspec!(react_codegen_spec, codegen_output_dir) + + out = Pod::Executable.execute_command( + 'node', + [ + "#{relative_installation_root}/#{react_native_path}/scripts/generate-artifacts.js", + "-p", "#{app_path}", + "-o", Pod::Config.instance.installation_root, + "-e", "#{fabric_enabled}", + "-c", "#{config_file_dir}", + ]) + Pod::UI.puts out; + + CodegenUtils.set_react_codegen_discovery_done(true) + end +end diff --git a/scripts/cocoapods/helpers.rb b/scripts/cocoapods/helpers.rb index 9008968393bb..03e3a5cbeac6 100644 --- a/scripts/cocoapods/helpers.rb +++ b/scripts/cocoapods/helpers.rb @@ -18,3 +18,11 @@ def ruby_platform return RUBY_PLATFORM end end + +class Finder + def self.find_codegen_file(path) + js_files = '-name "Native*.js" -or -name "*NativeComponent.js"' + ts_files = '-name "Native*.ts" -or -name "*NativeComponent.ts"' + return `find #{path} -type f \\( #{js_files} -or #{ts_files} \\)`.split("\n").sort() + end +end diff --git a/scripts/react_native_pods.rb b/scripts/react_native_pods.rb index 3d86c4f3de4e..27a57e36fbd4 100644 --- a/scripts/react_native_pods.rb +++ b/scripts/react_native_pods.rb @@ -11,6 +11,7 @@ require_relative './cocoapods/flipper.rb' require_relative './cocoapods/fabric.rb' require_relative './cocoapods/codegen.rb' +require_relative './cocoapods/codegen_utils.rb' require_relative './cocoapods/utils.rb' require_relative './cocoapods/new_architecture.rb' require_relative './cocoapods/local_podspec_patch.rb' @@ -18,12 +19,13 @@ $CODEGEN_OUTPUT_DIR = 'build/generated/ios' $CODEGEN_COMPONENT_DIR = 'react/renderer/components' $CODEGEN_MODULE_DIR = '.' -$REACT_CODEGEN_PODSPEC_GENERATED = false -$REACT_CODEGEN_DISCOVERY_DONE = false $START_TIME = Time.now.to_i def use_react_native! (options={}) + # The version of folly that must be used + folly_version = '2021.07.22.00' + # The prefix to react-native prefix = options[:path] ||= "../node_modules/react-native" @@ -79,21 +81,17 @@ def use_react_native! (options={}) pod 'boost', :podspec => "#{prefix}/third-party-podspecs/boost.podspec" pod 'RCT-Folly', :podspec => "#{prefix}/third-party-podspecs/RCT-Folly.podspec", :modular_headers => true - if new_arch_enabled - app_path = options[:app_path] - config_file_dir = options[:config_file_dir] - use_react_native_codegen_discovery!({ - react_native_path: prefix, - app_path: app_path, - fabric_enabled: fabric_enabled, - config_file_dir: config_file_dir, - }) - else - # Generate a podspec file for generated files. - # This gets generated in use_react_native_codegen_discovery when codegen discovery is enabled. - react_codegen_spec = get_react_codegen_spec(fabric_enabled: fabric_enabled) - generate_react_codegen_podspec!(react_codegen_spec) - end + run_codegen!( + options[:app_path], + options[:config_file_dir], + :new_arch_enabled => new_arch_enabled, + :disable_codegen => ENV['DISABLE_CODEGEN'] == '1', + :react_native_path => prefix, + :fabric_enabled => fabric_enabled, + :codegen_output_dir => $CODEGEN_OUTPUT_DIR, + :package_json_file => File.join(__dir__, "..", "package.json"), + :folly_version => folly_version + ) pod 'React-Codegen', :path => $CODEGEN_OUTPUT_DIR, :modular_headers => true @@ -150,224 +148,9 @@ def react_native_post_install(installer, react_native_path = "../node_modules/re Pod::UI.puts "Pod install took #{Time.now.to_i - $START_TIME} [s] to run".green end -def get_react_codegen_spec(options={}) - fabric_enabled = options[:fabric_enabled] ||= false - script_phases = options[:script_phases] ||= nil - - package = JSON.parse(File.read(File.join(__dir__, "..", "package.json"))) - version = package['version'] - - source = { :git => 'https://github.com/facebook/react-native.git' } - if version == '1000.0.0' - # This is an unpublished version, use the latest commit hash of the react-native repo, which we’re presumably in. - source[:commit] = `git rev-parse HEAD`.strip if system("git rev-parse --git-dir > /dev/null 2>&1") - else - source[:tag] = "v#{version}" - end - - folly_compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -Wno-comma -Wno-shorten-64-to-32' - folly_version = '2021.07.22.00' - boost_version = '1.76.0' - boost_compiler_flags = '-Wno-documentation' - - spec = { - 'name' => "React-Codegen", - 'version' => version, - 'summary' => 'Temp pod for generated files for React Native', - 'homepage' => 'https://facebook.com/', - 'license' => 'Unlicense', - 'authors' => 'Facebook', - 'compiler_flags' => "#{folly_compiler_flags} #{boost_compiler_flags} -Wno-nullability-completeness -std=c++17", - 'source' => { :git => '' }, - 'header_mappings_dir' => './', - 'platforms' => { - 'ios' => '11.0', - }, - 'source_files' => "**/*.{h,mm,cpp}", - 'pod_target_xcconfig' => { "HEADER_SEARCH_PATHS" => - [ - "\"$(PODS_ROOT)/boost\"", - "\"$(PODS_ROOT)/RCT-Folly\"", - "\"${PODS_ROOT}/Headers/Public/React-Codegen/react/renderer/components\"", - "\"$(PODS_ROOT)/Headers/Private/React-Fabric\"", - "\"$(PODS_ROOT)/Headers/Private/React-RCTFabric\"", - ].join(' ') - }, - 'dependencies': { - "FBReactNativeSpec": [version], - "React-jsiexecutor": [version], - "RCT-Folly": [folly_version], - "RCTRequired": [version], - "RCTTypeSafety": [version], - "React-Core": [version], - "React-jsi": [version], - "ReactCommon/turbomodule/core": [version] - } - } - - if fabric_enabled - spec[:'dependencies'].merge!({ - 'React-graphics': [version], - 'React-rncore': [version], - }); - end - - if script_phases - Pod::UI.puts "[Codegen] Adding script_phases to React-Codegen." - spec[:'script_phases'] = script_phases - end - - return spec -end - -def get_codegen_config_from_file(config_path, config_key) - empty = {'libraries' => []} - if !File.exist?(config_path) - return empty - end - - config = JSON.parse(File.read(config_path)) - return config[config_key] ? config[config_key] : empty -end - -def get_react_codegen_script_phases(options={}) - app_path = options[:app_path] ||= '' - if !app_path - Pod::UI.warn '[Codegen] error: app_path is requried to use codegen discovery.' - exit 1 - end - - # We need to convert paths to relative path from installation_root for the script phase for CI. - relative_app_root = Pathname.new(app_path).realpath().relative_path_from(Pod::Config.instance.installation_root) - - config_file_dir = options[:config_file_dir] ||= '' - relative_config_file_dir = '' - if config_file_dir != '' - relative_config_file_dir = Pathname.new(config_file_dir).relative_path_from(Pod::Config.instance.installation_root) - end - - fabric_enabled = options[:fabric_enabled] ||= false - - # react_native_path should be relative already. - react_native_path = options[:react_native_path] ||= "../node_modules/react-native" - - # Generate input files for in-app libaraies which will be used to check if the script needs to be run. - # TODO: Ideally, we generate the input_files list from generate-artifacts.js and read the result here. - # Or, generate this podspec in generate-artifacts.js as well. - config_key = options[:config_key] ||= 'codegenConfig' - app_package_path = File.join(app_path, 'package.json') - app_codegen_config = get_codegen_config_from_file(app_package_path, config_key) - file_list = [] - if app_codegen_config['libraries'] then - Pod::UI.warn '[Deprecated] You are using the old `libraries` array to list all your codegen.\nThis method will be removed in the future.\nUpdate your `package.json` with a single object.' - app_codegen_config['libraries'].each do |library| - library_dir = File.join(app_path, library['jsSrcsDir']) - file_list.concat (`find #{library_dir} -type f \\( -name "Native*.js" -or -name "*NativeComponent.js" \\)`.split("\n").sort) - end - elsif app_codegen_config['jsSrcsDir'] then - codegen_dir = File.join(app_path, app_codegen_config['jsSrcsDir']) - file_list.concat (`find #{codegen_dir} -type f \\( -name "Native*.js" -or -name "*NativeComponent.js" \\)`.split("\n").sort) - else - Pod::UI.warn '[Error] Codegen not properly configured. Please add the `codegenConf` entry to your `package.json`' - exit 1 - end - - input_files = file_list.map { |filename| "${PODS_ROOT}/../#{Pathname.new(filename).realpath().relative_path_from(Pod::Config.instance.installation_root)}" } - - # Add a script phase to trigger generate artifact. - # Some code is duplicated so that it's easier to delete the old way and switch over to this once it's stabilized. - return { - 'name': 'Generate Specs', - 'execution_position': :before_compile, - 'input_files' => input_files, - 'show_env_vars_in_log': true, - 'output_files': ["${DERIVED_FILE_DIR}/react-codegen.log"], - 'script': get_script_phases_with_codegen_discovery( - react_native_path: react_native_path, - relative_app_root: relative_app_root, - relative_config_file_dir: relative_config_file_dir, - fabric_enabled: fabric_enabled - ), - } - -end - -def set_react_codegen_podspec_generated(value) - $REACT_CODEGEN_PODSPEC_GENERATED = value -end - -def has_react_codegen_podspec_generated() - return $REACT_CODEGEN_PODSPEC_GENERATED -end - -def generate_react_codegen_podspec!(spec) - # This podspec file should only be create once in the session/pod install. - # This happens when multiple targets are calling use_react_native!. - if has_react_codegen_podspec_generated() - Pod::UI.puts "[Codegen] Skipping React-Codegen podspec generation." - return - end - relative_installation_root = Pod::Config.instance.installation_root.relative_path_from(Pathname.pwd) - output_dir = "#{relative_installation_root}/#{$CODEGEN_OUTPUT_DIR}" - Pod::Executable.execute_command("mkdir", ["-p", output_dir]); - - podspec_path = File.join(output_dir, 'React-Codegen.podspec.json') - Pod::UI.puts "[Codegen] Generating #{podspec_path}" - - File.open(podspec_path, 'w') do |f| - f.write(spec.to_json) - f.fsync - end - - set_react_codegen_podspec_generated(true) - - return { - "spec" => spec, - "path" => $CODEGEN_OUTPUT_DIR, # Path needs to be relative to `Podfile` - } -end - - -def use_react_native_codegen_discovery!(options={}) - return if ENV['DISABLE_CODEGEN'] == '1' - - if $REACT_CODEGEN_DISCOVERY_DONE - Pod::UI.puts "[Codegen] Skipping use_react_native_codegen_discovery." - return - end - - Pod::UI.warn '[Codegen] warn: using experimental new codegen integration' - react_native_path = options[:react_native_path] ||= "../node_modules/react-native" - app_path = options[:app_path] - fabric_enabled = options[:fabric_enabled] ||= false - config_file_dir = options[:config_file_dir] ||= '' - relative_installation_root = Pod::Config.instance.installation_root.relative_path_from(Pathname.pwd) - - if !app_path - Pod::UI.warn '[Codegen] Error: app_path is required for use_react_native_codegen_discovery.' - Pod::UI.warn '[Codegen] If you are calling use_react_native_codegen_discovery! in your Podfile, please remove the call and pass `app_path` and/or `config_file_dir` to `use_react_native!`.' - exit 1 - end - - # Generate React-Codegen podspec here to add the script phases. - script_phases = get_react_codegen_script_phases(options) - react_codegen_spec = get_react_codegen_spec(fabric_enabled: fabric_enabled, script_phases: script_phases) - generate_react_codegen_podspec!(react_codegen_spec) - - out = Pod::Executable.execute_command( - 'node', - [ - "#{relative_installation_root}/#{react_native_path}/scripts/generate-artifacts.js", - "-p", "#{app_path}", - "-o", Pod::Config.instance.installation_root, - "-e", "#{fabric_enabled}", - "-c", "#{config_file_dir}", - ]) - Pod::UI.puts out; - - $REACT_CODEGEN_DISCOVERY_DONE = true -end - +# === LEGACY METHOD === +# We need to keep this while we continue to support the old architecture. +# ===================== def use_react_native_codegen!(spec, options={}) return if ENV['RCT_NEW_ARCH_ENABLED'] == '1' # TODO: Once the new codegen approach is ready for use, we should output a warning here to let folks know to migrate. From 79a37e5a88e179090ade7145a453a46719c87b3f Mon Sep 17 00:00:00 2001 From: Riccardo Cipolleschi Date: Tue, 19 Jul 2022 00:03:23 -0700 Subject: [PATCH 0013/1165] Destructure use_react_native! parameters and doc (#34177) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/34177 This Diff destructures the parameters of the use_react_native! function. It does that in a backward compatible way, so we there should be no disruptions. It also adds documentation to the various public method we want to export to our users. ## Changelog [iOS][Changed] - Destruct use_reactnative parameters and ad ddocumentation Reviewed By: cortinico Differential Revision: D37787365 fbshipit-source-id: 27f9030db2e8c6c66b9548b4c1287eb8165ae5fc --- scripts/react_native_pods.rb | 57 +++++++++++++++++++++++------------- 1 file changed, 37 insertions(+), 20 deletions(-) diff --git a/scripts/react_native_pods.rb b/scripts/react_native_pods.rb index 27a57e36fbd4..80f98c0a90c3 100644 --- a/scripts/react_native_pods.rb +++ b/scripts/react_native_pods.rb @@ -22,27 +22,32 @@ $START_TIME = Time.now.to_i -def use_react_native! (options={}) +# Function that setup all the react native dependencies +#  +# Parameters +# - path: path to react_native installation. +# - fabric_enabled: whether fabric should be enabled or not. +# - new_arch_enabled: whether the new architecture should be enabled or not. +# - production: whether the dependencies must be installed to target a Debug or a Release build. +# - hermes_enabled: whether Hermes should be enabled or not. +# - flipper_configuration: The configuration to use for flipper. +# - app_path: path to the React Native app. Required by the New Architecture. +# - config_file_dir: directory of the `package.json` file, required by the New Architecture. +def use_react_native! ( + path: "../node_modules/react-native", + fabric_enabled: false, + new_arch_enabled: ENV['RCT_NEW_ARCH_ENABLED'] == '1', + production: false, + hermes_enabled: true, + flipper_configuration: FlipperConfiguration.disabled, + app_path: '..', + config_file_dir: '') + + prefix = path + # The version of folly that must be used folly_version = '2021.07.22.00' - # The prefix to react-native - prefix = options[:path] ||= "../node_modules/react-native" - - # Include Fabric dependencies - fabric_enabled = options[:fabric_enabled] ||= false - - # New arch enabled - new_arch_enabled = ENV['RCT_NEW_ARCH_ENABLED'] == '1' - - # Include DevSupport dependency - production = options[:production] ||= false - - # Include Hermes dependencies - hermes_enabled = options[:hermes_enabled] != nil ? options[:hermes_enabled] : true - - flipper_configuration = options[:flipper_configuration] ||= FlipperConfiguration.disabled - ReactNativePodsUtils.warn_if_not_on_arm64() # The Pods which should be included in all projects @@ -82,8 +87,8 @@ def use_react_native! (options={}) pod 'RCT-Folly', :podspec => "#{prefix}/third-party-podspecs/RCT-Folly.podspec", :modular_headers => true run_codegen!( - options[:app_path], - options[:config_file_dir], + app_path, + config_file_dir, :new_arch_enabled => new_arch_enabled, :disable_codegen => ENV['DISABLE_CODEGEN'] == '1', :react_native_path => prefix, @@ -121,15 +126,27 @@ def use_react_native! (options={}) end end +# It returns the default flags. def get_default_flags() return ReactNativePodsUtils.get_default_flags() end +# It installs the flipper dependencies into the project. +# +# Parameters +# - versions: a dictionary of Flipper Library -> Versions that can be used to customize which version of Flipper to install. +# - configurations: an array of configuration where to install the dependencies. def use_flipper!(versions = {}, configurations: ['Debug']) Pod::UI.warn "use_flipper is deprecated, use the flipper_configuration option in the use_react_native function" use_flipper_pods(versions, :configurations => configurations) end +# Function that executes after React Native has been installed to configure some flags and build settings. +# +# Parameters +# - installer: the Cocoapod object that allows to customize the project. +# - react_native_path: path to React Native. +# - mac_catalyst_enabled: whether we are running the Pod on a Mac Catalyst project or not. def react_native_post_install(installer, react_native_path = "../node_modules/react-native", mac_catalyst_enabled: false) ReactNativePodsUtils.apply_mac_catalyst_patches(installer) if mac_catalyst_enabled From 1d997ce6d67242b9f667b01365c5e719c3d3f8d7 Mon Sep 17 00:00:00 2001 From: Antoine Doubovetzky Date: Tue, 19 Jul 2022 05:47:17 -0700 Subject: [PATCH 0014/1165] (PULL_REQUEST_TEMPLATE) update link to changelog documentation (#34206) Summary: I just opened another PR and noticed the changelog page in the wiki redirected to the react native documentation. ## Changelog [Internal] [Changed] - Update link to changelog documentation in PULL_REQUEST_TEMPLATE Pull Request resolved: https://github.com/facebook/react-native/pull/34206 Reviewed By: NickGerleman Differential Revision: D37920424 Pulled By: cortinico fbshipit-source-id: f4e47172a13fe5b42c29e320d34816b490a14b6c --- .github/PULL_REQUEST_TEMPLATE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 073b9af6d242..4b81ca2408c3 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -7,7 +7,7 @@ ## Changelog [CATEGORY] [TYPE] - Message From 46a9edc8544ae070149a97ea3d919b88dd6e2942 Mon Sep 17 00:00:00 2001 From: Lorenzo Sciandra Date: Tue, 19 Jul 2022 07:34:18 -0700 Subject: [PATCH 0015/1165] Hermes pod: change logic to use the hermes tag to set the pod source correctly (#34221) Summary: This fix is necessarly to ensure that when working on the codebase in the `0.XX-stable` branches (ex. when you are working on a release) the Hermes podfile is correctly set against the right commit for that branch, and not latest commit from main branch of Hermes repo. I didn't add a check to verify that the file `.hermesversion` exists because I think it's safe to assume that the file and the tag correctly exists when this step (doing a pod install on the `0.XX-stable` branch). Once this is merged, we need to cherry pick it on both the 0.69 and 0.70 branches ## Changelog [iOS] [Fixed] - Hermes pod: change logic to use the hermes tag to set the pod source correctly Pull Request resolved: https://github.com/facebook/react-native/pull/34221 Test Plan: * git clone the repo * checkout 0.69-stable branch * follow https://reactnative.dev/contributing/release-testing * without this commit, when testing RNTester + iOS + Hermes the app will insta-crash on opening * with it, the app gets build successfully Reviewed By: cortinico Differential Revision: D37957660 Pulled By: cipolleschi fbshipit-source-id: 4e50099ed712b1ad8e6439822e3f530142982c1b --- sdks/hermes-engine/hermes-engine.podspec | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sdks/hermes-engine/hermes-engine.podspec b/sdks/hermes-engine/hermes-engine.podspec index 672b7a048d03..8d331e096ad2 100644 --- a/sdks/hermes-engine/hermes-engine.podspec +++ b/sdks/hermes-engine/hermes-engine.podspec @@ -31,8 +31,10 @@ elsif version == '1000.0.0' source[:commit] = `git ls-remote https://github.com/facebook/hermes main | cut -f 1`.strip elsif currentremote.strip.end_with?("facebook/react-native.git") and currentbranch.strip.end_with?("-stable") Pod::UI.puts '[Hermes] Detected that you are on a React Native release branch, building Hermes from source...'.yellow if Object.const_defined?("Pod::UI") + hermestag_file = File.join(__dir__, "..", ".hermesversion") + hermestag = File.read(hermestag_file).strip source[:git] = git - source[:commit] = `git ls-remote https://github.com/facebook/hermes main | cut -f 1`.strip + source[:tag] = hermestag else source[:http] = "https://github.com/facebook/react-native/releases/download/v#{version}/hermes-runtime-darwin-v#{version}.tar.gz" end From af3dfbaa47f4d58f3f3f892a5debd8d54113c2c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danilo=20B=C3=BCrger?= Date: Tue, 19 Jul 2022 09:11:08 -0700 Subject: [PATCH 0016/1165] Move cocoapods cli native_modules require from template to rn scripts (#34215) Summary: This resolves issues where the node_modules structure is not hoisted (like with pnpm). Since the template does not directly depend on the cli, it doesn't exist in the pnpm node_modules root. Moving it to the rn scripts makes sure that the relative require starts in the correct directory for both hoisted and pnpm structures. ## Changelog [iOS] [Fixed] - Fix cocoapods cli native_modules require for pnpm node_modules Pull Request resolved: https://github.com/facebook/react-native/pull/34215 Test Plan: 1. react-native init 2. rm -rf node_modules 3. pnpm i 4. bundle install 5. bundle exec pod install --project-directory=ios This should succeed. Without the patch, it will fail with ``` [!] Invalid `Podfile` file: cannot load such file -- /.../node_modules/react-native-community/cli-platform-ios/native_modules. # from /.../ios/Podfile:2 # ------------------------------------------- # require_relative '../node_modules/react-native/scripts/react_native_pods' > require_relative '../node_modules/react-native-community/cli-platform-ios/native_modules' # # ------------------------------------------- ``` Reviewed By: cortinico Differential Revision: D37959152 Pulled By: cipolleschi fbshipit-source-id: 7fa9af4a8c153cfd38360f57eca415a8c252dbd5 --- package.json | 1 + scripts/native_modules.rb | 6 ++++++ template/ios/Podfile | 2 +- 3 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 scripts/native_modules.rb diff --git a/package.json b/package.json index eaba0ca0d854..47d6ffdbe277 100644 --- a/package.json +++ b/package.json @@ -49,6 +49,7 @@ "scripts/xcode/with-environment.sh", "scripts/launchPackager.bat", "scripts/launchPackager.command", + "scripts/native_modules.rb", "scripts/node-binary.sh", "scripts/packager.sh", "scripts/packager-reporter.js", diff --git a/scripts/native_modules.rb b/scripts/native_modules.rb new file mode 100644 index 000000000000..729035ddd91d --- /dev/null +++ b/scripts/native_modules.rb @@ -0,0 +1,6 @@ +# 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. + +require_relative '../../@react-native-community/cli-platform-ios/native_modules' diff --git a/template/ios/Podfile b/template/ios/Podfile index 92e7ee1919e6..594b74dc56f5 100644 --- a/template/ios/Podfile +++ b/template/ios/Podfile @@ -1,5 +1,5 @@ require_relative '../node_modules/react-native/scripts/react_native_pods' -require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules' +require_relative '../node_modules/react-native/scripts/native_modules' platform :ios, '12.4' install! 'cocoapods', :deterministic_uuids => false From b9adf2db20bf9e1436fa58182d886fd9461df9af Mon Sep 17 00:00:00 2001 From: Mike Hardy Date: Tue, 19 Jul 2022 11:28:25 -0700 Subject: [PATCH 0017/1165] deps(android): bump soloader to 0.10.4 (#34213) Summary: soloader 0.10.3 will apparently cause crashes in instrumented tests, 0.10.4 appears to fix these crashes Related: https://github.com/facebook/SoLoader/issues/94 Related: https://github.com/reactwg/react-native-releases/discussions/26#discussioncomment-3166381 ## Changelog [Android] [Changed] - Bump Soloader to 0.10.4 Pull Request resolved: https://github.com/facebook/react-native/pull/34213 Test Plan: This is hard to test since it's in the AAR etc., I'm hoping CI is sufficient as the previous soloader bump PR went through similarly Reviewed By: cipolleschi Differential Revision: D37960320 Pulled By: cortinico fbshipit-source-id: ce1611d7b30df737c8525a70839b5491a6585c75 --- ReactAndroid/gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ReactAndroid/gradle.properties b/ReactAndroid/gradle.properties index 1a612aec2ccc..3027dd26292e 100644 --- a/ReactAndroid/gradle.properties +++ b/ReactAndroid/gradle.properties @@ -22,7 +22,7 @@ OKHTTP_VERSION=4.9.2 POWERMOCK_VERSION=2.0.2 PROGUARD_ANNOTATIONS_VERSION=1.19.0 ROBOLECTRIC_VERSION=4.4 -SO_LOADER_VERSION=0.10.3 +SO_LOADER_VERSION=0.10.4 SWIPEREFRESH_LAYOUT_VERSION=1.0.0 # Native Dependency Versions From b66db7a84093b0da9b619b1e187c2c812b16893e Mon Sep 17 00:00:00 2001 From: Ruslan Latypov Date: Tue, 19 Jul 2022 12:53:11 -0700 Subject: [PATCH 0018/1165] fix more imports Summary: There are many files across fbobjc relying on -include_pch and therefore they miss Foundation.h and UIKit.h includes. This diff was generated by a codemod and fixes these missing includes. More details on the missing imports https://fb.workplace.com/groups/929548250966094/permalink/981237982463787/ Changelog: [Internal] Reviewed By: yannickl Differential Revision: D37282740 fbshipit-source-id: 0f419025b3cf2f811e96ff464cb19e8e5a25aa09 --- React/Views/RCTViewUtils.h | 1 + 1 file changed, 1 insertion(+) diff --git a/React/Views/RCTViewUtils.h b/React/Views/RCTViewUtils.h index a6204c5faa9f..ef2a335c0166 100644 --- a/React/Views/RCTViewUtils.h +++ b/React/Views/RCTViewUtils.h @@ -6,6 +6,7 @@ */ #import +#import NS_ASSUME_NONNULL_BEGIN From 8a33b75f55ba429e9e7a897179557aa8bb49ab35 Mon Sep 17 00:00:00 2001 From: Xin Chen Date: Tue, 19 Jul 2022 22:30:29 -0700 Subject: [PATCH 0019/1165] getModule API may return null module Summary: The native module might be null, and that should not be an exception thrown by the subclassed method. Changelog: [Android][Internal] - Mark getModule API to be nullable Reviewed By: mdvacca, makovkastar Differential Revision: D37900294 fbshipit-source-id: a4ecc9804b95bf0512554e96985f272b435e33b2 --- .../src/main/java/com/facebook/react/TurboReactPackage.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/TurboReactPackage.java b/ReactAndroid/src/main/java/com/facebook/react/TurboReactPackage.java index 0efffb9cff54..8dc8ba5471b8 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/TurboReactPackage.java +++ b/ReactAndroid/src/main/java/com/facebook/react/TurboReactPackage.java @@ -8,6 +8,7 @@ package com.facebook.react; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.facebook.react.bridge.ModuleHolder; import com.facebook.react.bridge.ModuleSpec; import com.facebook.react.bridge.NativeModule; @@ -42,7 +43,8 @@ public List createNativeModules(ReactApplicationContext reactConte * @param reactContext * @return */ - public abstract NativeModule getModule(String name, final ReactApplicationContext reactContext); + public abstract @Nullable NativeModule getModule( + String name, final ReactApplicationContext reactContext); /** * This is a temporary method till we implement TurboModules. Once we implement TurboModules, we From 2b57b749fbdeee8340dee385288d194155f693c8 Mon Sep 17 00:00:00 2001 From: Samuel Susla Date: Wed, 20 Jul 2022 04:01:36 -0700 Subject: [PATCH 0020/1165] Remove redundant Android runtime scheduler mobile config flags Summary: changelog: [internal] Remove features flags for enabling RuntimeScheduler and RuntimeScheduler+TM to simplify setup. Reviewed By: mdvacca Differential Revision: D37912783 fbshipit-source-id: 1a24720dec3cf06067bf523d72f0919731a91b72 --- .../react/bridge/CatalystInstanceImpl.java | 13 ++----- .../react/config/ReactFeatureFlags.java | 4 --- .../jni/react/jni/CatalystInstanceImpl.cpp | 36 ++++++------------- .../main/jni/react/jni/CatalystInstanceImpl.h | 12 ++----- 4 files changed, 15 insertions(+), 50 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java index 50aedd434212..ad5fb6985f9d 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java +++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java @@ -108,8 +108,7 @@ public String toString() { // C++ parts private final HybridData mHybridData; - private static native HybridData initHybrid( - boolean enableRuntimeScheduler, boolean enableRuntimeSchedulerInTurboModule); + private static native HybridData initHybrid(); public native CallInvokerHolderImpl getJSCallInvokerHolder(); @@ -124,15 +123,7 @@ private CatalystInstanceImpl( FLog.d(ReactConstants.TAG, "Initializing React Xplat Bridge."); Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "createCatalystInstanceImpl"); - if (ReactFeatureFlags.enableRuntimeSchedulerInTurboModule - && !ReactFeatureFlags.enableRuntimeScheduler) { - Assertions.assertUnreachable(); - } - - mHybridData = - initHybrid( - ReactFeatureFlags.enableRuntimeScheduler, - ReactFeatureFlags.enableRuntimeSchedulerInTurboModule); + mHybridData = initHybrid(); mReactQueueConfiguration = ReactQueueConfigurationImpl.create( diff --git a/ReactAndroid/src/main/java/com/facebook/react/config/ReactFeatureFlags.java b/ReactAndroid/src/main/java/com/facebook/react/config/ReactFeatureFlags.java index a8a5264042ba..68728b18fed4 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/config/ReactFeatureFlags.java +++ b/ReactAndroid/src/main/java/com/facebook/react/config/ReactFeatureFlags.java @@ -70,10 +70,6 @@ public class ReactFeatureFlags { /** This feature flag enables logs for Fabric */ public static boolean enableFabricLogs = false; - public static boolean enableRuntimeScheduler = false; - - public static boolean enableRuntimeSchedulerInTurboModule = false; - /** Feature flag to configure eager attachment of the root view/initialisation of the JS code */ public static boolean enableEagerRootViewAttachment = false; diff --git a/ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.cpp b/ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.cpp index 6a936c66f66f..e44913e4fd08 100644 --- a/ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.cpp +++ b/ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.cpp @@ -93,21 +93,12 @@ class JInstanceCallback : public InstanceCallback { } // namespace jni::local_ref -CatalystInstanceImpl::initHybrid( - jni::alias_ref, - bool enableRuntimeScheduler, - bool enableRuntimeSchedulerInTurboModule) { - return makeCxxInstance( - enableRuntimeScheduler, enableRuntimeSchedulerInTurboModule); +CatalystInstanceImpl::initHybrid(jni::alias_ref) { + return makeCxxInstance(); } -CatalystInstanceImpl::CatalystInstanceImpl( - bool enableRuntimeScheduler, - bool enableRuntimeSchedulerInTurboModule) - : instance_(std::make_unique()), - enableRuntimeScheduler_(enableRuntimeScheduler), - enableRuntimeSchedulerInTurboModule_( - enableRuntimeScheduler && enableRuntimeSchedulerInTurboModule) {} +CatalystInstanceImpl::CatalystInstanceImpl() + : instance_(std::make_unique()) {} void CatalystInstanceImpl::warnOnLegacyNativeModuleSystemUse() { CxxNativeModule::setShouldWarnOnUse(true); @@ -382,17 +373,12 @@ void CatalystInstanceImpl::handleMemoryPressure(int pressureLevel) { jni::alias_ref CatalystInstanceImpl::getJSCallInvokerHolder() { if (!jsCallInvokerHolder_) { - if (enableRuntimeSchedulerInTurboModule_) { - auto runtimeScheduler = getRuntimeScheduler(); - auto runtimeSchedulerCallInvoker = - std::make_shared( - runtimeScheduler->cthis()->get()); - jsCallInvokerHolder_ = jni::make_global( - CallInvokerHolder::newObjectCxxArgs(runtimeSchedulerCallInvoker)); - } else { - jsCallInvokerHolder_ = jni::make_global( - CallInvokerHolder::newObjectCxxArgs(instance_->getJSCallInvoker())); - } + auto runtimeScheduler = getRuntimeScheduler(); + auto runtimeSchedulerCallInvoker = + std::make_shared( + runtimeScheduler->cthis()->get()); + jsCallInvokerHolder_ = jni::make_global( + CallInvokerHolder::newObjectCxxArgs(runtimeSchedulerCallInvoker)); } return jsCallInvokerHolder_; } @@ -440,7 +426,7 @@ CatalystInstanceImpl::getRuntimeExecutor() { jni::alias_ref CatalystInstanceImpl::getRuntimeScheduler() { - if (enableRuntimeScheduler_ && !runtimeScheduler_) { + if (!runtimeScheduler_) { auto runtimeExecutor = instance_->getRuntimeExecutor(); auto runtimeScheduler = std::make_shared(runtimeExecutor); diff --git a/ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.h b/ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.h index fe635bf48250..cd242903faba 100644 --- a/ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.h +++ b/ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.h @@ -37,10 +37,7 @@ class CatalystInstanceImpl : public jni::HybridClass { static constexpr auto kJavaDescriptor = "Lcom/facebook/react/bridge/CatalystInstanceImpl;"; - static jni::local_ref initHybrid( - jni::alias_ref, - bool enableRuntimeScheduler, - bool enableRuntimeSchedulerInTurboModule); + static jni::local_ref initHybrid(jni::alias_ref); static void registerNatives(); @@ -51,9 +48,7 @@ class CatalystInstanceImpl : public jni::HybridClass { private: friend HybridBase; - CatalystInstanceImpl( - bool enableRuntimeScheduler, - bool enableRuntimeSchedulerInTurboModule); + CatalystInstanceImpl(); void initializeBridge( jni::alias_ref callback, @@ -120,9 +115,6 @@ class CatalystInstanceImpl : public jni::HybridClass { jni::global_ref nativeCallInvokerHolder_; jni::global_ref runtimeExecutor_; jni::global_ref runtimeScheduler_; - - bool const enableRuntimeScheduler_; - bool const enableRuntimeSchedulerInTurboModule_; }; } // namespace react From d0b1d49e9a61774ebbadcf56ae97682fdf954079 Mon Sep 17 00:00:00 2001 From: Samuel Susla Date: Wed, 20 Jul 2022 04:01:36 -0700 Subject: [PATCH 0021/1165] Delete mobile config react_native_new_architecture:enable_call_immediates_ios Summary: changelog: [internal] Remove shipped mobile config Reviewed By: cortinico Differential Revision: D37913209 fbshipit-source-id: 1a5877360e12e329342d4c8efc0a10bff24abcaa --- ReactCommon/react/renderer/scheduler/Scheduler.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ReactCommon/react/renderer/scheduler/Scheduler.cpp b/ReactCommon/react/renderer/scheduler/Scheduler.cpp index 53a7fe6bf340..4132c83af547 100644 --- a/ReactCommon/react/renderer/scheduler/Scheduler.cpp +++ b/ReactCommon/react/renderer/scheduler/Scheduler.cpp @@ -53,8 +53,7 @@ Scheduler::Scheduler( auto enableCallImmediates = reactNativeConfig_->getBool( "react_native_new_architecture:enable_call_immediates_android"); #else - auto enableCallImmediates = reactNativeConfig_->getBool( - "react_native_new_architecture:enable_call_immediates_ios"); + auto enableCallImmediates = true; #endif auto weakRuntimeScheduler = From e1d17c813800016d044ad9258346b37b9bad6cf8 Mon Sep 17 00:00:00 2001 From: Samuel Susla Date: Wed, 20 Jul 2022 05:47:26 -0700 Subject: [PATCH 0022/1165] delete mobile config react_native_new_architecture:suspend_before_app_termination Summary: changelog: [internal] Remove shipped mobile config Reviewed By: mdvacca Differential Revision: D37913252 fbshipit-source-id: f1557e2b93b7f0410385e4dec41ec354e46d04f1 --- React/Fabric/RCTSurfacePresenter.mm | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/React/Fabric/RCTSurfacePresenter.mm b/React/Fabric/RCTSurfacePresenter.mm index df612c2bbada..6c26e253a03a 100644 --- a/React/Fabric/RCTSurfacePresenter.mm +++ b/React/Fabric/RCTSurfacePresenter.mm @@ -98,13 +98,10 @@ - (instancetype)initWithContextContainer:(ContextContainer::Shared)contextContai _scheduler = [self _createScheduler]; - auto reactNativeConfig = _contextContainer->at>("ReactNativeConfig"); - if (reactNativeConfig->getBool("react_native_new_architecture:suspend_before_app_termination")) { - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(_applicationWillTerminate) - name:UIApplicationWillTerminateNotification - object:nil]; - } + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(_applicationWillTerminate) + name:UIApplicationWillTerminateNotification + object:nil]; } return self; From 698b14789cb0777961fe5f1d4363387f9f185b1b Mon Sep 17 00:00:00 2001 From: Dmitry Minkovsky Date: Wed, 20 Jul 2022 07:06:18 -0700 Subject: [PATCH 0023/1165] Use readlink instead of realpath in packager.sh (#34145) Summary: `realpath` is not available on macOS 12.2 and 12.4. Because of this, the following error is shown when launching an RN app with XCode (which calls `packager.sh` via `launchPackage.command`): Screen Shot 2022-07-06 at 1 26 08 PM I am running Bash 5 but realpath is also not available with zsh. This issue was introduced in https://github.com/facebook/react-native/commit/bb8ddd6c1247fde230a60c662a318422df52516e#diff-6ca7c99209bdf630550bb9e2946ce8611948c5a23b32ffb25028792ef5d48b8d, which interestingly did not change `launchPackage.command`. There's a recent comment on that commit that confirms this issue: https://github.com/facebook/react-native/commit/bb8ddd6c1247fde230a60c662a318422df52516e#commitcomment-77818917 ## Changelog [iOS] [Fixed] - Use readlink instead of realpath in packager.sh Pull Request resolved: https://github.com/facebook/react-native/pull/34145 Reviewed By: cipolleschi Differential Revision: D37669417 Pulled By: cortinico fbshipit-source-id: bcc4cb6e886df059e6598ee811226e3cd1a6ae14 --- scripts/packager.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/packager.sh b/scripts/packager.sh index b9f90160f1ae..acb158125786 100755 --- a/scripts/packager.sh +++ b/scripts/packager.sh @@ -5,7 +5,7 @@ # LICENSE file in the root directory of this source tree. # scripts directory -THIS_DIR=$(cd -P "$(dirname "$(realpath "${BASH_SOURCE[0]}" || echo "${BASH_SOURCE[0]}")")" && pwd) +THIS_DIR=$(cd -P "$(dirname "$(readlink "${BASH_SOURCE[0]}" || echo "${BASH_SOURCE[0]}")")" && pwd) REACT_NATIVE_ROOT="$THIS_DIR/.." # Application root directory - General use case: react-native is a dependency PROJECT_ROOT="$THIS_DIR/../../.." From a22f30d2ce866cb1488b26bb18eee0620a0ac259 Mon Sep 17 00:00:00 2001 From: Nicola Corti Date: Wed, 20 Jul 2022 07:08:33 -0700 Subject: [PATCH 0024/1165] Fix missing import on New Architecture build script in template (#34230) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/34230 The OS static class is accessed inside app/build.gradle but the import is on the top level Gradle file. This is causing an app created from template to fail building. This is needed to be cherry-picked on the 0.70-stable branch. Changelog: [Android] [Fixed] - Fix missing import on New Architecture build script in template Reviewed By: cipolleschi Differential Revision: D37995897 fbshipit-source-id: aad22100cee004944c4fa0841f5ef0dfc6ea1e94 --- template/android/app/build.gradle | 1 + template/android/build.gradle | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/template/android/app/build.gradle b/template/android/app/build.gradle index bb4470cd7336..5816fe08d543 100644 --- a/template/android/app/build.gradle +++ b/template/android/app/build.gradle @@ -1,6 +1,7 @@ apply plugin: "com.android.application" import com.android.build.OutputFile +import org.apache.tools.ant.taskdefs.condition.Os /** * The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets diff --git a/template/android/build.gradle b/template/android/build.gradle index 338dc272f39d..8569fee3a7f5 100644 --- a/template/android/build.gradle +++ b/template/android/build.gradle @@ -1,5 +1,3 @@ -import org.apache.tools.ant.taskdefs.condition.Os - // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { From 31887277931cf2a3c84f6965df72e3bd85c16f8f Mon Sep 17 00:00:00 2001 From: Lorenzo Sciandra Date: Wed, 20 Jul 2022 07:08:57 -0700 Subject: [PATCH 0025/1165] add 0.69.2 changelog (#34227) Summary: Adds changelog for new patch. ## Changelog [Internal] [Changed] - add changelog entry for 0.69.2 Pull Request resolved: https://github.com/facebook/react-native/pull/34227 Test Plan: N/A Reviewed By: cipolleschi Differential Revision: D37993752 Pulled By: cortinico fbshipit-source-id: 339f2b6bf42547360d0bca9984e2a3fd45299cc0 --- CHANGELOG.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 255539250f8b..296ea125c320 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## v0.69.2 + +### Changed + +- Set react-shallow-renderer v16.15.0 for react v18 compat ([a39a7c453d](https://github.com/facebook/react-native/commit/a39a7c453d87086935ff07d549ba8220cbcf30bd) by [@mikehardy](https://github.com/mikehardy)) +- Upgrade RN CLI to v8.0.3 ([28cbd21d21](https://github.com/facebook/react-native/commit/28cbd21d21f2ffb3f38b2449a4983f013947ce0a) by [@thymikee](https://github.com/thymikee)) + +#### iOS specific + +- Hermes pod: change logic to use the hermes tag to set the pod source correctly ([46a9edc854](https://github.com/facebook/react-native/commit/46a9edc8544ae070149a97ea3d919b88dd6e2942) by [@kelset](https://github.com/kelset)) +- Fix the race condition when calling readAsDataURL after new Blob(blobs) ([bd12e41188](https://github.com/facebook/react-native/commit/bd12e41188c8d85c0acbd713f10f0bd34ea0edca) by [@wood1986](https://github.com/wood1986)) +- Make sure that Flipper pods are not installed when creating a release build ([23accbf58d](https://github.com/facebook/react-native/commit/23accbf58d2fa03ad020e07f00012a32609c7218) by [@cipolleschi](https://github.com/cipolleschi)) + ## v0.69.1 ### Changed From 361d939afd0b43b2e9e6ea0d4c619482e91e82e3 Mon Sep 17 00:00:00 2001 From: Riccardo Cipolleschi Date: Wed, 20 Jul 2022 08:53:38 -0700 Subject: [PATCH 0026/1165] Build Hermes in CI also when it is against stable branch (#34224) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/34224 This Diff is a copy of this [PR](https://github.com/facebook/react-native/pull/34228) that we have against 0.69-stable. This Diff makes sure we can build Hermes also in PR that are created against a stable branch ## Changelog [General] [Changed] - Make sure we can build Hermes from source when PR are opened agains -stable Reviewed By: cortinico Differential Revision: D37961092 fbshipit-source-id: 65577fcc69f0e2a68377cbd46e3bd3a6af24e7c3 --- .circleci/config.yml | 2 +- scripts/hermes/hermes-utils.js | 17 ++++++++++++++++- scripts/hermes/prepare-hermes-for-build.js | 8 +++++--- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index fee64be10324..7d3f39b95653 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -898,7 +898,7 @@ jobs: - run: name: Download Hermes tarball command: | - node scripts/hermes/prepare-hermes-for-build + node scripts/hermes/prepare-hermes-for-build $CIRCLE_PULL_REQUEST cp sdks/download/* $HERMES_WS_DIR/download/. cp -r sdks/hermes/* $HERMES_WS_DIR/hermes/. - save_cache: diff --git a/scripts/hermes/hermes-utils.js b/scripts/hermes/hermes-utils.js index 588c11c52e97..1dc2bba067d6 100644 --- a/scripts/hermes/hermes-utils.js +++ b/scripts/hermes/hermes-utils.js @@ -199,11 +199,26 @@ function isRequestingLatestCommitFromHermesMainBranch() { return hermesTag === DEFAULT_HERMES_TAG; } -function shouldBuildHermesFromSource() { +function isPRAgainstStable(pullRequest) { + if (pullRequest == null) { + return false; + } + + const prComponents = pullRequest.split('/'); + const prNumber = prComponents[prComponents.length - 1]; + const apiURL = `https://api.github.com/repos/facebook/react-native/pulls/${prNumber}`; + const prJson = JSON.parse(execSync(`curl ${apiURL}`).toString()); + const baseBranch = prJson.base.label; + + return baseBranch.endsWith('-stable'); +} + +function shouldBuildHermesFromSource(pullRequest) { return ( !isTestingAgainstLocalHermesTarball() && (isOnAReactNativeReleaseBranch() || isOnAReactNativeReleaseTag() || + isPRAgainstStable(pullRequest) || isRequestingLatestCommitFromHermesMainBranch()) ); } diff --git a/scripts/hermes/prepare-hermes-for-build.js b/scripts/hermes/prepare-hermes-for-build.js index 29a5d9ae27ad..42b33bad58a0 100644 --- a/scripts/hermes/prepare-hermes-for-build.js +++ b/scripts/hermes/prepare-hermes-for-build.js @@ -23,8 +23,8 @@ const { shouldBuildHermesFromSource, } = require('./hermes-utils'); -async function main() { - if (!shouldBuildHermesFromSource()) { +async function main(pullRequest) { + if (!shouldBuildHermesFromSource(pullRequest)) { copyPodSpec(); return; } @@ -40,6 +40,8 @@ async function main() { } } -main().then(() => { +const pullRequest = process.argv.length > 2 ? process.argv[2] : null; +console.log(`Pull request detected: ${pullRequest}`); +main(pullRequest).then(() => { process.exit(0); }); From 9923ac1b524ae959abdf50a28a3094198015f77e Mon Sep 17 00:00:00 2001 From: Riccardo Cipolleschi Date: Wed, 20 Jul 2022 09:12:47 -0700 Subject: [PATCH 0027/1165] Properly cache sdk/hermes to improve build times (#34209) Summary: Currently, iOS jobs takes up to 2 hours to run. This is firstly due to Hermes being rebuilt at least 3 times during the CI process. One issue I discovered is that the `Hermes-SDK-Cache-Key` was depending on the `{{ .Environment.CIRCLE_JOB }}` which is different from all the jobs (`test_ios_rntester`, `test_ios` and `build_hermes_macos`) which forced hermes to be build 3 times. Another issue I found was that we were not caching hermes at all the first time we build it, during the `build_hermes_macos` step. To ensure that `test_rn_tester` and `test_ios` has a valid version of Hermes from the cache, they now depend on the `build_hermes_macos` job ## Changelog [iOS] [Changed] - Add caching for Hermes when we build it, updated the hermes_sdk_cache_key, update job dependencies Pull Request resolved: https://github.com/facebook/react-native/pull/34209 Test Plan: CircleCI must be green and take less than 2 hrs **Before** {F753846143} **After** {F753846214} Reviewed By: cortinico Differential Revision: D37959500 Pulled By: cipolleschi fbshipit-source-id: c3435717bfa71e7488326894cd1ad7638044004e --- .circleci/config.yml | 154 ++++++++++++++++++++++++++++--------------- 1 file changed, 101 insertions(+), 53 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 7d3f39b95653..107fba519651 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -52,8 +52,9 @@ references: gems_cache_key: &gems_cache_key v1-gems-{{ checksum "Gemfile.lock" }} gradle_cache_key: &gradle_cache_key v1-gradle-{{ checksum "gradle/wrapper/gradle-wrapper.properties" }}-{{ checksum "ReactAndroid/gradle.properties" }} hermes_cache_key: &hermes_cache_key v1-hermes-{{ .Environment.CIRCLE_JOB }}-{{ checksum "/tmp/hermes/hermesversion" }} - hermes_sdk_cache_key: &hermes_sdk_cache_key v1-hermes-{{ .Environment.CIRCLE_JOB }}-{{ checksum "sdks/.hermes-cache-key-file" }} + hermes_sdk_cache_key: &hermes_sdk_cache_key v1-hermes-{{ checksum "sdks/.hermes-cache-key-file" }} hermes_windows_cache_key: &hermes_windows_cache_key v1-hermes-{{ .Environment.CIRCLE_JOB }}-{{ checksum "tmp/hermes/hermesversion" }} + hermes_tarball_cache_key: &hermes_tarball_cache_key v1-hermes-tarball-{{ checksum "sdks/.hermes-cache-key-file" }} pods_cache_key: &pods_cache_key v6-pods-{{ .Environment.CIRCLE_JOB }}-{{ checksum "packages/rn-tester/Podfile.lock.bak" }}-{{ checksum "packages/rn-tester/Podfile" }} windows_yarn_cache_key: &windows_yarn_cache_key v1-win-yarn-cache-{{ arch }}-{{ checksum "yarn.lock" }} yarn_cache_key: &yarn_cache_key v5-yarn-cache-{{ .Environment.CIRCLE_JOB }} @@ -281,10 +282,13 @@ commands: name: Report size of RNTester.app (analysis-bot) command: GITHUB_TOKEN="$PUBLIC_ANALYSISBOT_GITHUB_TOKEN_A""$PUBLIC_ANALYSISBOT_GITHUB_TOKEN_B" scripts/circleci/report-bundle-size.sh << parameters.platform >> || true - with_hermes_sdk_cache_span: + with_hermes_tarball_cache_span: parameters: steps: type: steps + set_tarball_path: + type: boolean + default: False steps: - run: name: Setup Hermes cache @@ -295,13 +299,31 @@ commands: fi - restore_cache: keys: - - *hermes_sdk_cache_key + - *hermes_tarball_cache_key + - when: + condition: << parameters.set_tarball_path >> + steps: + - run: + name: Set HERMES_TARBALL_PATH if present + command: | + BASE_PATH=/tmp/hermes/hermes-runtime-darwin/ + if [ ! -d $BASE_PATH ]; then + echo "Hermes tarball base path not present ($BASE_PATH). Build it from source." + return + fi + TARBALL=$(ls /tmp/hermes/hermes-runtime-darwin/) + TARBALL_PATH=$BASE_PATH$TARBALL + if [ ! -f $TARBALL_PATH ]; then + echo "Hermes tarball not present ($TARBALL_PATH). Build it from source." + return + fi + + echo "export HERMES_ENGINE_TARBALL_PATH=$TARBALL_PATH" >> $BASH_ENV - steps: << parameters.steps >> - save_cache: - key: *hermes_sdk_cache_key + key: *hermes_tarball_cache_key paths: - - sdks/hermesc - - sdks/hermes + - /tmp/hermes/hermes-runtime-darwin/ # ------------------------- # JOBS @@ -492,7 +514,8 @@ jobs: name: Setup the CocoaPods environment command: bundle exec pod setup - - with_hermes_sdk_cache_span: + - with_hermes_tarball_cache_span: + set_tarball_path: True steps: - with_rntester_pods_cache_span: steps: @@ -738,7 +761,8 @@ jobs: - brew_install: package: cmake - - with_hermes_sdk_cache_span: + - with_hermes_tarball_cache_span: + set_tarball_path: True steps: - run: name: Install CocoaPods dependencies @@ -976,50 +1000,70 @@ jobs: name: Install dependencies command: | brew install cmake - - run: - name: Build the Hermes iOS frameworks - command: | - cd ~/react-native/sdks/hermes - ./utils/build-ios-framework.sh - - run: - name: Build the Hermes Mac frameworks - command: | - cd ~/react-native/sdks/hermes - ./utils/build-mac-framework.sh - cp build_macosx/bin/hermesc /tmp/hermes/osx-bin/. - - run: - name: Package the Hermes Apple frameworks - command: | - cd ~/react-native/sdks/hermes - . ./utils/build-apple-framework.sh - - mkdir -p /tmp/cocoapods-package-root/destroot - mkdir -p /tmp/hermes/output - cp -R ./destroot /tmp/cocoapods-package-root - cp LICENSE /tmp/cocoapods-package-root - - tar -C /tmp/cocoapods-package-root/ -czvf /tmp/hermes/output/hermes-runtime-darwin-v$(get_release_version).tar.gz . - - mkdir -p /tmp/hermes/hermes-runtime-darwin - cp /tmp/hermes/output/hermes-runtime-darwin-v$(get_release_version).tar.gz /tmp/hermes/hermes-runtime-darwin/. - - save_cache: - key: *hermes_cache_key - paths: - - ~/react-native/hermes/build_host_hermesc - - ~/react-native/hermes/build_iphoneos - - ~/react-native/hermes/build_catalyst - - ~/react-native/hermes/build_iphonesimulator - - ~/react-native/hermes/build_macosx - - ~/react-native/hermes/destroot - - store_artifacts: - path: /tmp/hermes/hermes-runtime-darwin/ - - store_artifacts: - path: /tmp/hermes/osx-bin/ - - persist_to_workspace: - root: /tmp/hermes/ - paths: - - hermes-runtime-darwin - - osx-bin + - with_hermes_tarball_cache_span: + steps: + - run: + name: Build the Hermes iOS frameworks + command: | + if [[ -d "~/react-native/sdks/hermes/destroot" && -d "/tmp/hermes/hermes-runtime-darwin/" ]]; then + echo "destroot and tarball exists. Skip building" + return + fi + echo "either destroot or the tarball does not exists. Build from source" + + cd ~/react-native/sdks/hermes + ./utils/build-ios-framework.sh + - run: + name: Build the Hermes Mac frameworks + command: | + if [[ -d "~/react-native/sdks/hermes/destroot" && -d "/tmp/hermes/hermes-runtime-darwin/" ]]; then + echo "destroot and tarball exists. Skip building" + return + fi + echo "either destroot or the tarball does not exists. Build from source" + + cd ~/react-native/sdks/hermes + ./utils/build-mac-framework.sh + cp build_macosx/bin/hermesc /tmp/hermes/osx-bin/. + - run: + name: Package the Hermes Apple frameworks + command: | + if [[ -d "~/react-native/sdks/hermes/destroot" && -d "/tmp/hermes/hermes-runtime-darwin/" ]]; then + echo "destroot and tarball exists. Skip building" + return + fi + echo "either destroot or the tarball does not exists. Build from source" + + cd ~/react-native/sdks/hermes + . ./utils/build-apple-framework.sh + + mkdir -p /tmp/cocoapods-package-root/destroot + mkdir -p /tmp/hermes/output + cp -R ./destroot /tmp/cocoapods-package-root + cp LICENSE /tmp/cocoapods-package-root + + tar -C /tmp/cocoapods-package-root/ -czvf /tmp/hermes/output/hermes-runtime-darwin-v$(get_release_version).tar.gz . + + mkdir -p /tmp/hermes/hermes-runtime-darwin + cp /tmp/hermes/output/hermes-runtime-darwin-v$(get_release_version).tar.gz /tmp/hermes/hermes-runtime-darwin/. + - save_cache: + key: *hermes_cache_key + paths: + - ~/react-native/sdks/hermes/build_host_hermesc + - ~/react-native/sdks/hermes/build_iphoneos + - ~/react-native/sdks/hermes/build_catalyst + - ~/react-native/sdks/hermes/build_iphonesimulator + - ~/react-native/sdks/hermes/build_macosx + - ~/react-native/sdks/hermes/destroot + - store_artifacts: + path: /tmp/hermes/hermes-runtime-darwin/ + - store_artifacts: + path: /tmp/hermes/osx-bin/ + - persist_to_workspace: + root: /tmp/hermes/ + paths: + - hermes-runtime-darwin + - osx-bin build_hermesc_windows: executor: @@ -1296,9 +1340,13 @@ workflows: - test_ios_template: requires: - build_npm_package - - test_ios_rntester + - test_ios_rntester: + requires: + - build_hermes_macos - test_ios: run_unit_tests: true + requires: + - build_hermes_macos # DISABLED: USE_FRAMEWORKS=1 not supported by Flipper # - test_ios: # name: test_ios_frameworks From 27fe6f10796ecd47314279b1ae7cdfe29c16d1f0 Mon Sep 17 00:00:00 2001 From: Graham Mendick Date: Wed, 20 Jul 2022 13:51:28 -0700 Subject: [PATCH 0028/1165] Fix contentInsetAdjustmentBehavior set to automatic on ScrollView in the new architecture (#34217) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: Fixes https://github.com/facebook/react-native/issues/34165 and [Large title fails](https://github.com/reactwg/react-native-new-architecture/discussions/43) on the new React Native architecture. There are problems with setting `contentInsetAdjustmentBehavior` to `automatic` on the `ScrollView` component in the new React Native architecture. The `automatic` setting matters to navigation libraries (like [my Navigation router](https://github.com/grahammendick/navigation)) because it stops the `ScrollView` from overlapping the `UINavigationBar`. The setting also powers important native features like large titles and search bars on iOS. The `automatic` setting works fine on the old architecture. It doesn’t work on the new architecture because React Native is recycling views. In https://github.com/facebook/react-native/issues/34165 and [Large title fails](https://github.com/reactwg/react-native-new-architecture/discussions/43) there are videos comparing the setting in the old and the new architecture. ## Changelog [iOS] [Fixed] - Fix `contentInsetAdjustmentBehavior` set to `automatic` on `ScrollView` in the new architecture Pull Request resolved: https://github.com/facebook/react-native/pull/34217 Test Plan: I checked the fix in both the repros in https://github.com/facebook/react-native/issues/34165 and [Large title fails](https://github.com/reactwg/react-native-new-architecture/discussions/43). Here is a video of the fix running with large titles in the new architecture. https://user-images.githubusercontent.com/1761227/179612188-162b896b-82c5-45de-bb5a-ba80f452fbee.mov Reviewed By: sammy-SC Differential Revision: D37952506 Pulled By: cipolleschi fbshipit-source-id: 6cff6c85aa33b579405fe34a9e36c8630f4c24bd --- .../ComponentViews/ScrollView/RCTScrollViewComponentView.mm | 3 +++ 1 file changed, 3 insertions(+) diff --git a/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm b/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm index e699640940d8..1a5aa5b1f8b8 100644 --- a/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm +++ b/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm @@ -401,6 +401,9 @@ - (void)prepareForRecycle _shouldUpdateContentInsetAdjustmentBehavior = YES; _state.reset(); _isUserTriggeredScrolling = NO; + CGRect oldFrame = self.frame; + self.frame = CGRectZero; + self.frame = oldFrame; [super prepareForRecycle]; } From 143a0f74b86bf2593dd29ce3c85d73d703d7a9f5 Mon Sep 17 00:00:00 2001 From: Luna Wei Date: Wed, 20 Jul 2022 17:58:01 -0700 Subject: [PATCH 0029/1165] Fix (Pointer|Touch)Events not firing after drag and scroll for ScrollView and HorizontalScrollView Summary: Changelog: [Android][Fixed] - Fix such that when the scrollviews call `onChildStartedNativeGesture`, they appropriately call `onChildEndedNativeGesture` to unlock the native gesture such that `JSTouchDispatcher` or `JSPointerDispatcher` will continue to emit events. ### How did we find this issue? As React Native is adding pointer event support for different input types, we noticed after pressing and dragging on a ScrollView, hover events would not fire. ### Why was this not an issue before? This was always an issue -- it was just that `JSTouchDispatcher` worked its way around it by explicitly setting `mChildIsHandlingNativeGesture = false` on a `ACTION_DOWN` event, [code pointer](https://github.com/facebook/react-native/blob/main/ReactAndroid/src/main/java/com/facebook/react/uimanager/JSTouchDispatcher.java#L76). Similarly, `JSPointerDispatcher` [copied this logic](https://github.com/facebook/react-native/blob/main/ReactAndroid/src/main/java/com/facebook/react/uimanager/JSPointerDispatcher.java#L106). With new hover support in `JSPointerDispatcher` no similar workaround was put in (or even a good place to insert). ### What's next? * As a follow-up, we should look at removing this workaround (at least for `JSPointerDispatcher`) * By searching for usages of where we `notifyNativeGestureStarted`, it looks like `ReactDrawerLayout` and `ReactSwipeRefreshLayout` both do and don't call the symmetric `notifyNativeGestureEnded`. This will likely be an issue in the future (or maybe if we remove the workaround) Reviewed By: mdvacca Differential Revision: D37977982 fbshipit-source-id: 0d18767f4debbf24cfb24b54df1310f6f96a0d03 --- .../facebook/react/views/scroll/ReactHorizontalScrollView.java | 1 + .../java/com/facebook/react/views/scroll/ReactScrollView.java | 1 + 2 files changed, 2 insertions(+) diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.java b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.java index 964c8d721ba8..3c962f03565a 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.java @@ -532,6 +532,7 @@ public boolean onTouchEvent(MotionEvent ev) { float velocityX = mVelocityHelper.getXVelocity(); float velocityY = mVelocityHelper.getYVelocity(); ReactScrollViewHelper.emitScrollEndDragEvent(this, velocityX, velocityY); + NativeGestureUtil.notifyNativeGestureEnded(this, ev); mDragging = false; // After the touch finishes, we may need to do some scrolling afterwards either as a result // of a fling or because we need to page align the content diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollView.java b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollView.java index 7f44e14e432f..69da5b3af197 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollView.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollView.java @@ -404,6 +404,7 @@ public boolean onTouchEvent(MotionEvent ev) { float velocityX = mVelocityHelper.getXVelocity(); float velocityY = mVelocityHelper.getYVelocity(); ReactScrollViewHelper.emitScrollEndDragEvent(this, velocityX, velocityY); + NativeGestureUtil.notifyNativeGestureEnded(this, ev); mDragging = false; // After the touch finishes, we may need to do some scrolling afterwards either as a result // of a fling or because we need to page align the content From 64528e5faa445907b8287b412c344f30c20fca61 Mon Sep 17 00:00:00 2001 From: Samuel Susla Date: Thu, 21 Jul 2022 03:34:56 -0700 Subject: [PATCH 0030/1165] Fix measure when view is inverted Summary: changelog: [internal] Vertical and horizontal inversion was not taken into account in `computeRelativeLayoutMetrics`. To fix it, we precompute frames to include inversions. Reviewed By: mdvacca Differential Revision: D37994809 fbshipit-source-id: 043e6f19b6fa577f61fa3c739ce2d751ef973cc3 --- .../renderer/core/LayoutableShadowNode.cpp | 73 +++- .../core/tests/LayoutableShadowNodeTest.cpp | 344 ++++++++++++++++++ .../react/renderer/graphics/Transform.cpp | 20 +- .../react/renderer/graphics/Transform.h | 15 + .../renderer/graphics/tests/TransformTest.cpp | 7 + 5 files changed, 451 insertions(+), 8 deletions(-) diff --git a/ReactCommon/react/renderer/core/LayoutableShadowNode.cpp b/ReactCommon/react/renderer/core/LayoutableShadowNode.cpp index c56846922579..7f1802906df7 100644 --- a/ReactCommon/react/renderer/core/LayoutableShadowNode.cpp +++ b/ReactCommon/react/renderer/core/LayoutableShadowNode.cpp @@ -17,6 +17,60 @@ namespace facebook { namespace react { +template +using LayoutableSmallVector = butter::small_vector; + +static LayoutableSmallVector calculateTransformedFrames( + LayoutableSmallVector const &shadowNodeList, + LayoutableShadowNode::LayoutInspectingPolicy policy) { + auto size = shadowNodeList.size(); + auto transformedFrames = LayoutableSmallVector{size}; + auto transformation = Transform::Identity(); + + for (int i = size - 1; i >= 0; --i) { + auto currentShadowNode = + traitCast(shadowNodeList.at(i)); + auto currentFrame = currentShadowNode->getLayoutMetrics().frame; + + if (policy.includeTransform) { + if (Transform::isVerticalInversion(transformation)) { + auto parentShadowNode = + traitCast(shadowNodeList.at(i + 1)); + currentFrame.origin.y = + parentShadowNode->getLayoutMetrics().frame.size.height - + currentFrame.size.height - currentFrame.origin.y; + } + + if (Transform::isHorizontalInversion(transformation)) { + auto parentShadowNode = + traitCast(shadowNodeList.at(i + 1)); + currentFrame.origin.x = + parentShadowNode->getLayoutMetrics().frame.size.width - + currentFrame.size.width - currentFrame.origin.x; + } + + if (i != size - 1) { + auto parentShadowNode = + traitCast(shadowNodeList.at(i + 1)); + auto contentOritinOffset = parentShadowNode->getContentOriginOffset(); + if (Transform::isVerticalInversion(transformation)) { + contentOritinOffset.y = -contentOritinOffset.y; + } + if (Transform::isHorizontalInversion(transformation)) { + contentOritinOffset.x = -contentOritinOffset.x; + } + currentFrame.origin += contentOritinOffset; + } + + transformation = transformation * currentShadowNode->getTransform(); + } + + transformedFrames[i] = currentFrame; + } + + return transformedFrames; +} + LayoutableShadowNode::LayoutableShadowNode( ShadowNodeFragment const &fragment, ShadowNodeFamily::Shared const &family, @@ -34,6 +88,8 @@ LayoutMetrics LayoutableShadowNode::computeRelativeLayoutMetrics( ShadowNodeFamily const &descendantNodeFamily, LayoutableShadowNode const &ancestorNode, LayoutInspectingPolicy policy) { + // Prelude. + if (&descendantNodeFamily == &ancestorNode.getFamily()) { // Layout metrics of a node computed relatively to the same node are equal // to `transform`-ed layout metrics of the node with zero `origin`. @@ -53,10 +109,12 @@ LayoutMetrics LayoutableShadowNode::computeRelativeLayoutMetrics( return EmptyLayoutMetrics; } + // ------------------------------ + // Step 1. // Creating a list of nodes that form a chain from the descender node to // ancestor node inclusively. - auto shadowNodeList = butter::small_vector{}; + auto shadowNodeList = LayoutableSmallVector{}; // Finding the measured node. // The last element in the `AncestorList` is a pair of a parent of the node @@ -81,6 +139,8 @@ LayoutMetrics LayoutableShadowNode::computeRelativeLayoutMetrics( } } + // ------------------------------ + // Step 2. // Computing the initial size of the measured node. auto descendantLayoutableNode = @@ -90,6 +150,9 @@ LayoutMetrics LayoutableShadowNode::computeRelativeLayoutMetrics( return EmptyLayoutMetrics; } + // ------------------------------ + + auto transformedFrames = calculateTransformedFrames(shadowNodeList, policy); auto layoutMetrics = descendantLayoutableNode->getLayoutMetrics(); auto &resultFrame = layoutMetrics.frame; resultFrame.origin = {0, 0}; @@ -105,7 +168,7 @@ LayoutMetrics LayoutableShadowNode::computeRelativeLayoutMetrics( return EmptyLayoutMetrics; } - auto currentFrame = currentShadowNode->getLayoutMetrics().frame; + auto currentFrame = transformedFrames[i]; if (i == size - 1) { // If it's the last element, its origin is irrelevant. currentFrame.origin = {0, 0}; @@ -122,12 +185,10 @@ LayoutMetrics LayoutableShadowNode::computeRelativeLayoutMetrics( } resultFrame.origin += currentFrame.origin; - - if (i != 0 && policy.includeTransform) { - resultFrame.origin += currentShadowNode->getContentOriginOffset(); - } } + // ------------------------------ + return layoutMetrics; } diff --git a/ReactCommon/react/renderer/core/tests/LayoutableShadowNodeTest.cpp b/ReactCommon/react/renderer/core/tests/LayoutableShadowNodeTest.cpp index 55c761c95424..8fde7fd71227 100644 --- a/ReactCommon/react/renderer/core/tests/LayoutableShadowNodeTest.cpp +++ b/ReactCommon/react/renderer/core/tests/LayoutableShadowNodeTest.cpp @@ -431,3 +431,347 @@ TEST(LayoutableShadowNodeTest, includeViewportOffset) { EXPECT_EQ(layoutMetrics.frame.origin.x, 10); EXPECT_EQ(layoutMetrics.frame.origin.y, 20); } + +/* + * ┌───────────────────────────────┐ + * │ │ + * │ │ + * │┌─────────────────────────────┐│ + * ││ ││ + * ││ ││ + * │└─────────────────────────────┘│ + * │┌─────────────────────────────┐│ + * ││ ││ + * ││ ││ + * │└─────────────────────────────┘│ + * └───────────────────────────────┘ + */ +TEST(LayoutableShadowNodeTest, invertedVerticalView) { + auto builder = simpleComponentBuilder(); + auto childShadowNode1 = std::shared_ptr{}; + auto childShadowNode2 = std::shared_ptr{}; + // clang-format off + auto element = + Element() + .props([] { + auto sharedProps = std::make_shared(); + sharedProps->transform = Transform::VerticalInversion(); // Inverted + return sharedProps; + }) + .finalize([](ViewShadowNode &shadowNode){ + auto layoutMetrics = EmptyLayoutMetrics; + layoutMetrics.frame.size = {200, 200}; + shadowNode.setLayoutMetrics(layoutMetrics); + }).children({ + Element() + .reference(childShadowNode1) + .finalize([](ViewShadowNode &shadowNode){ + auto layoutMetrics = EmptyLayoutMetrics; + layoutMetrics.frame.origin = {0, 0}; + layoutMetrics.frame.size = {100, 100}; + shadowNode.setLayoutMetrics(layoutMetrics); + }), + Element() + .reference(childShadowNode2) + .finalize([](ViewShadowNode &shadowNode){ + auto layoutMetrics = EmptyLayoutMetrics; + layoutMetrics.frame.origin = {0, 100}; + layoutMetrics.frame.size = {100, 100}; + shadowNode.setLayoutMetrics(layoutMetrics); + }) + }); + // clang-format on + + auto scrollShadowNode = builder.build(element); + + auto firstItemRelativeLayoutMetrics = + LayoutableShadowNode::computeRelativeLayoutMetrics( + childShadowNode1->getFamily(), *scrollShadowNode, {}); + + EXPECT_EQ(firstItemRelativeLayoutMetrics.frame.origin.x, 0); + EXPECT_EQ(firstItemRelativeLayoutMetrics.frame.origin.y, 100); + EXPECT_EQ(firstItemRelativeLayoutMetrics.frame.size.width, 100); + EXPECT_EQ(firstItemRelativeLayoutMetrics.frame.size.height, 100); + + auto secondItemRelativeLayoutMetrics = + LayoutableShadowNode::computeRelativeLayoutMetrics( + childShadowNode2->getFamily(), *scrollShadowNode, {}); + + EXPECT_EQ(secondItemRelativeLayoutMetrics.frame.origin.x, 0); + EXPECT_EQ(secondItemRelativeLayoutMetrics.frame.origin.y, 0); + EXPECT_EQ(secondItemRelativeLayoutMetrics.frame.size.width, 100); + EXPECT_EQ(secondItemRelativeLayoutMetrics.frame.size.height, 100); +} + +/* + * ┌────────────────────────────────────┐ + * │ │ + * │ │ + * │ ┌───────────────────────────────┐ │ + * │ │ │ │ + * │ │ │ │ + * │ │┌─────────────────────────────┐│ │ + * │ ││ ││ │ + * │ ││ ││ │ + * │ │└─────────────────────────────┘│ │ + * │ │┌─────────────────────────────┐│ │ + * │ ││ ││ │ + * │ ││ ││ │ + * │ │└─────────────────────────────┘│ │ + * │ └───────────────────────────────┘ │ + * └────────────────────────────────────┘ + */ +TEST(LayoutableShadowNodeTest, nestedInvertedVerticalView) { + auto builder = simpleComponentBuilder(); + auto childShadowNode1 = std::shared_ptr{}; + auto childShadowNode2 = std::shared_ptr{}; + // clang-format off + auto element = + Element() + .props([] { + auto sharedProps = std::make_shared(); + sharedProps->transform = Transform::VerticalInversion(); // Inverted + return sharedProps; + }) + .finalize([](ViewShadowNode &shadowNode){ + auto layoutMetrics = EmptyLayoutMetrics; + layoutMetrics.frame.size = {400, 400}; + shadowNode.setLayoutMetrics(layoutMetrics); + }) + .children({ + Element() + .finalize([](ViewShadowNode &shadowNode){ + auto layoutMetrics = EmptyLayoutMetrics; + layoutMetrics.frame.origin = {100, 50}; + layoutMetrics.frame.size = {200, 200}; + shadowNode.setLayoutMetrics(layoutMetrics); + }).children({ + Element() + .reference(childShadowNode1) + .finalize([](ViewShadowNode &shadowNode){ + auto layoutMetrics = EmptyLayoutMetrics; + layoutMetrics.frame.origin = {0, 0}; + layoutMetrics.frame.size = {100, 100}; + shadowNode.setLayoutMetrics(layoutMetrics); + }), + Element() + .reference(childShadowNode2) + .finalize([](ViewShadowNode &shadowNode){ + auto layoutMetrics = EmptyLayoutMetrics; + layoutMetrics.frame.origin = {0, 100}; + layoutMetrics.frame.size = {100, 100}; + shadowNode.setLayoutMetrics(layoutMetrics); + }) + }) + }); + // clang-format on + + auto scrollShadowNode = builder.build(element); + + auto firstItemRelativeLayoutMetrics = + LayoutableShadowNode::computeRelativeLayoutMetrics( + childShadowNode1->getFamily(), *scrollShadowNode, {}); + + EXPECT_EQ(firstItemRelativeLayoutMetrics.frame.origin.x, 100); + EXPECT_EQ(firstItemRelativeLayoutMetrics.frame.origin.y, 250); + EXPECT_EQ(firstItemRelativeLayoutMetrics.frame.size.width, 100); + EXPECT_EQ(firstItemRelativeLayoutMetrics.frame.size.height, 100); + + auto secondItemRelativeLayoutMetrics = + LayoutableShadowNode::computeRelativeLayoutMetrics( + childShadowNode2->getFamily(), *scrollShadowNode, {}); + + EXPECT_EQ(secondItemRelativeLayoutMetrics.frame.origin.x, 100); + EXPECT_EQ(secondItemRelativeLayoutMetrics.frame.origin.y, 150); + EXPECT_EQ(secondItemRelativeLayoutMetrics.frame.size.width, 100); + EXPECT_EQ(secondItemRelativeLayoutMetrics.frame.size.height, 100); +} + +/* + * ┌──────────────────────────────────────┐ + * │ │ + * │ │ + * │┌─────────────────┐┌─────────────────┐│ + * ││ ││ ││ + * ││ ││ ││ + * │└─────────────────┘└─────────────────┘│ + * └──────────────────────────────────────┘ + */ +TEST(LayoutableShadowNodeTest, invertedHorizontalView) { + auto builder = simpleComponentBuilder(); + auto childShadowNode1 = std::shared_ptr{}; + auto childShadowNode2 = std::shared_ptr{}; + // clang-format off + auto element = + Element() + .props([] { + auto sharedProps = std::make_shared(); + sharedProps->transform = Transform::HorizontalInversion(); // Inverted + return sharedProps; + }) + .finalize([](ViewShadowNode &shadowNode){ + auto layoutMetrics = EmptyLayoutMetrics; + layoutMetrics.frame.size = {200, 200}; + shadowNode.setLayoutMetrics(layoutMetrics); + }).children({ + Element() + .reference(childShadowNode1) + .finalize([](ViewShadowNode &shadowNode){ + auto layoutMetrics = EmptyLayoutMetrics; + layoutMetrics.frame.origin = {0, 0}; + layoutMetrics.frame.size = {100, 100}; + shadowNode.setLayoutMetrics(layoutMetrics); + }), + Element() + .reference(childShadowNode2) + .finalize([](ViewShadowNode &shadowNode){ + auto layoutMetrics = EmptyLayoutMetrics; + layoutMetrics.frame.origin = {100, 0}; + layoutMetrics.frame.size = {100, 100}; + shadowNode.setLayoutMetrics(layoutMetrics); + }) + }); + // clang-format on + + auto scrollShadowNode = builder.build(element); + + auto firstItemRelativeLayoutMetrics = + LayoutableShadowNode::computeRelativeLayoutMetrics( + childShadowNode1->getFamily(), *scrollShadowNode, {}); + + EXPECT_EQ(firstItemRelativeLayoutMetrics.frame.origin.x, 100); + EXPECT_EQ(firstItemRelativeLayoutMetrics.frame.origin.y, 0); + EXPECT_EQ(firstItemRelativeLayoutMetrics.frame.size.width, 100); + EXPECT_EQ(firstItemRelativeLayoutMetrics.frame.size.height, 100); + + auto secondItemRelativeLayoutMetrics = + LayoutableShadowNode::computeRelativeLayoutMetrics( + childShadowNode2->getFamily(), *scrollShadowNode, {}); + + EXPECT_EQ(secondItemRelativeLayoutMetrics.frame.origin.x, 0); + EXPECT_EQ(secondItemRelativeLayoutMetrics.frame.origin.y, 0); + EXPECT_EQ(secondItemRelativeLayoutMetrics.frame.size.width, 100); + EXPECT_EQ(secondItemRelativeLayoutMetrics.frame.size.height, 100); +} + +/* + * ┌──────────────────────────────────────────┐ + * │ │ + * │ │ + * │ ┌──────────────────────────────────────┐ │ + * │ │ │ │ + * │ │ │ │ + * │ │┌─────────────────┐┌─────────────────┐│ │ + * │ ││ ││ ││ │ + * │ ││ ││ ││ │ + * │ │└─────────────────┘└─────────────────┘│ │ + * │ └──────────────────────────────────────┘ │ + * └──────────────────────────────────────────┘ + */ +TEST(LayoutableShadowNodeTest, nestedInvertedHorizontalView) { + auto builder = simpleComponentBuilder(); + auto childShadowNode1 = std::shared_ptr{}; + auto childShadowNode2 = std::shared_ptr{}; + // clang-format off + auto element = + Element() + .props([] { + auto sharedProps = std::make_shared(); + sharedProps->transform = Transform::HorizontalInversion(); // Inverted + return sharedProps; + }) + .finalize([](ViewShadowNode &shadowNode){ + auto layoutMetrics = EmptyLayoutMetrics; + layoutMetrics.frame.size = {400, 400}; + shadowNode.setLayoutMetrics(layoutMetrics); + }) + .children({ + Element() + .finalize([](ViewShadowNode &shadowNode){ + auto layoutMetrics = EmptyLayoutMetrics; + layoutMetrics.frame.origin = {50, 100}; + layoutMetrics.frame.size = {200, 200}; + shadowNode.setLayoutMetrics(layoutMetrics); + }).children({ + Element() + .reference(childShadowNode1) + .finalize([](ViewShadowNode &shadowNode){ + auto layoutMetrics = EmptyLayoutMetrics; + layoutMetrics.frame.origin = {0, 0}; + layoutMetrics.frame.size = {100, 100}; + shadowNode.setLayoutMetrics(layoutMetrics); + }), + Element() + .reference(childShadowNode2) + .finalize([](ViewShadowNode &shadowNode){ + auto layoutMetrics = EmptyLayoutMetrics; + layoutMetrics.frame.origin = {100, 0}; + layoutMetrics.frame.size = {100, 100}; + shadowNode.setLayoutMetrics(layoutMetrics); + }) + }) + }); + // clang-format on + + auto scrollShadowNode = builder.build(element); + + auto firstItemRelativeLayoutMetrics = + LayoutableShadowNode::computeRelativeLayoutMetrics( + childShadowNode1->getFamily(), *scrollShadowNode, {}); + + EXPECT_EQ(firstItemRelativeLayoutMetrics.frame.origin.x, 250); + EXPECT_EQ(firstItemRelativeLayoutMetrics.frame.origin.y, 100); + EXPECT_EQ(firstItemRelativeLayoutMetrics.frame.size.width, 100); + EXPECT_EQ(firstItemRelativeLayoutMetrics.frame.size.height, 100); + + auto secondItemRelativeLayoutMetrics = + LayoutableShadowNode::computeRelativeLayoutMetrics( + childShadowNode2->getFamily(), *scrollShadowNode, {}); + + EXPECT_EQ(secondItemRelativeLayoutMetrics.frame.origin.x, 150); + EXPECT_EQ(secondItemRelativeLayoutMetrics.frame.origin.y, 100); + EXPECT_EQ(secondItemRelativeLayoutMetrics.frame.size.width, 100); + EXPECT_EQ(secondItemRelativeLayoutMetrics.frame.size.height, 100); +} + +TEST(LayoutableShadowNodeTest, inversedContentOriginOffset) { + auto builder = simpleComponentBuilder(); + + auto childShadowNode = std::shared_ptr{}; + // clang-format off + auto element = + Element() + .props([] { + auto sharedProps = std::make_shared(); + sharedProps->transform = Transform::HorizontalInversion() * Transform::VerticalInversion(); + return sharedProps; + }) + .finalize([](ScrollViewShadowNode &shadowNode){ + auto layoutMetrics = EmptyLayoutMetrics; + layoutMetrics.frame.size = {300, 350}; + shadowNode.setLayoutMetrics(layoutMetrics); + }) + .stateData([](ScrollViewState &data) { + data.contentOffset = {10, 20}; + }) + .children({ + Element() + .finalize([](ViewShadowNode &shadowNode){ + auto layoutMetrics = EmptyLayoutMetrics; + layoutMetrics.frame.origin = {30, 40}; + layoutMetrics.frame.size = {100, 200}; + shadowNode.setLayoutMetrics(layoutMetrics); + }) + .reference(childShadowNode) + }); + // clang-format on + + auto parentShadowNode = builder.build(element); + + auto relativeLayoutMetrics = + LayoutableShadowNode::computeRelativeLayoutMetrics( + childShadowNode->getFamily(), *parentShadowNode, {}); + + EXPECT_EQ(relativeLayoutMetrics.frame.origin.x, 180); + EXPECT_EQ(relativeLayoutMetrics.frame.origin.y, 130); +} diff --git a/ReactCommon/react/renderer/graphics/Transform.cpp b/ReactCommon/react/renderer/graphics/Transform.cpp index d34246fa17eb..a8a7f1033b80 100644 --- a/ReactCommon/react/renderer/graphics/Transform.cpp +++ b/ReactCommon/react/renderer/graphics/Transform.cpp @@ -32,6 +32,14 @@ Transform Transform::Identity() { return {}; } +Transform Transform::VerticalInversion() { + return Transform::Scale(1, -1, 1); +} + +Transform Transform::HorizontalInversion() { + return Transform::Scale(-1, 1, 1); +} + Transform Transform::Perspective(Float perspective) { auto transform = Transform{}; transform.operations.push_back(TransformOperation{ @@ -241,6 +249,14 @@ Transform Transform::Interpolate( return result; } +bool Transform::isVerticalInversion(Transform const &transform) { + return transform.at(1, 1) == -1; +} + +bool Transform::isHorizontalInversion(Transform const &transform) { + return transform.at(0, 0) == -1; +} + bool Transform::operator==(Transform const &rhs) const { for (auto i = 0; i < 16; i++) { if (matrix[i] != rhs.matrix[i]) { @@ -387,8 +403,8 @@ Size operator*(Size const &size, Transform const &transform) { } auto result = Size{}; - result.width = transform.at(0, 0) * size.width; - result.height = transform.at(1, 1) * size.height; + result.width = std::abs(transform.at(0, 0) * size.width); + result.height = std::abs(transform.at(1, 1) * size.height); return result; } diff --git a/ReactCommon/react/renderer/graphics/Transform.h b/ReactCommon/react/renderer/graphics/Transform.h index a275afb19441..e24f4af028b2 100644 --- a/ReactCommon/react/renderer/graphics/Transform.h +++ b/ReactCommon/react/renderer/graphics/Transform.h @@ -77,6 +77,18 @@ struct Transform { */ static Transform Identity(); + /* + * Returns the vertival inversion transform (`[1 0 0 0; 0 -1 0 0; 0 0 1 0; 0 0 + * 0 1]`). + */ + static Transform VerticalInversion(); + + /* + * Returns the horizontal inversion transform (`[-1 0 0 0; 0 1 0 0; 0 0 1 0; 0 + * 0 0 1]`). + */ + static Transform HorizontalInversion(); + /* * Returns a Perspective transform. */ @@ -121,6 +133,9 @@ struct Transform { Transform const &lhs, Transform const &rhs); + static bool isVerticalInversion(Transform const &transform); + static bool isHorizontalInversion(Transform const &transform); + /* * Equality operators. */ diff --git a/ReactCommon/react/renderer/graphics/tests/TransformTest.cpp b/ReactCommon/react/renderer/graphics/tests/TransformTest.cpp index bcd0641d62f9..70c232ecd019 100644 --- a/ReactCommon/react/renderer/graphics/tests/TransformTest.cpp +++ b/ReactCommon/react/renderer/graphics/tests/TransformTest.cpp @@ -41,6 +41,13 @@ TEST(TransformTest, scalingRect) { EXPECT_EQ(transformedRect.size.height, 200); } +TEST(TransformTest, invertingSize) { + auto size = facebook::react::Size{300, 400}; + auto transformedSize = size * Transform::VerticalInversion(); + EXPECT_EQ(transformedSize.width, 300); + EXPECT_EQ(transformedSize.height, 400); +} + TEST(TransformTest, rotatingRect) { auto point = facebook::react::Point{10, 10}; auto size = facebook::react::Size{10, 10}; From 8993ffc82e8d4010d82dcb1d69c33a609bb2771a Mon Sep 17 00:00:00 2001 From: Eric Edouard Date: Thu, 21 Jul 2022 04:11:30 -0700 Subject: [PATCH 0031/1165] Added border curve style prop ("Squircle" effect - iOS only) (#33783) Summary: NOTE: PR is based on https://github.com/facebook/react-native/pull/32017 which went stale for quite a long time but can now safely be closed ![](https://preview.redd.it/nuvl4746ys471.png?width=960&crop=smart&auto=webp&s=084a517a645364ac246b70b7fa8e0f2470cc7af3) Since iOS 13+, it is possible to change the corner curve property on iOS in order to smoothen border radius and make it more "rounded" (also called "squircle") Here's an [article](https://medium.com/arthurofbabylon/a-smooth-corner-radius-in-ios-54b80aa2d372) explaining in details what it is. This property is also built in figma, but currently there is no way to implement this directly with react-native despite it being available natively on iOS. Many open source react-native libraries were created in order to simulate this behaviour: [react-native-super-ellipse-mask](https://github.com/everdrone/react-native-super-ellipse-mask) [react-native-squircle-view](https://github.com/everdrone/react-native-squircle-view) [react-native-figma-squircle](https://github.com/tienphaw/react-native-figma-squircle) But they rely on creating an SVG shape with the smoothed corners and masking the view behind. This makes it not very performant (flickering on mounting was a common side-effect) This PR aims at implementing the property natively. PR for the docs update: https://github.com/facebook/react-native-website/pull/2785 ## Changelog [iOS] [Added] - Added `borderCurve` style prop for smooth border radius (squircle effect) Pull Request resolved: https://github.com/facebook/react-native/pull/33783 Test Plan: We used the RNTester app and added an example with `cornerCurve ` set to `'continuous'` (only on iOS). As the difference is quite subtle, we also made some more tests to better illustrate the difference (these are not in the RN-tester app): ![IMG_0810](https://user-images.githubusercontent.com/19872411/133893536-26207c53-aade-4583-9eef-7a1739b6907b.PNG) We overlapped two views with `position: absolute`, the one in the background has a red background and has `cornerRadius` set to `false`, and the one in the foreground is set to `true`. We can clearly see where the borders differs on the corners. Reviewed By: sammy-SC Differential Revision: D37883631 Pulled By: cipolleschi fbshipit-source-id: 09f06de9628fa326323eba63875de30102c4a59e --- BUCK | 1 + .../View/ReactNativeStyleAttributes.js | 1 + .../NativeComponent/BaseViewConfig.ios.js | 1 + Libraries/StyleSheet/StyleSheetTypes.js | 1 + React/Base/RCTConvert.h | 2 ++ React/Base/RCTConvert.m | 9 ++++++ .../View/RCTViewComponentView.mm | 15 ++++++++++ React/Views/RCTBorderCurve.h | 13 ++++++++ React/Views/RCTView.h | 6 ++++ React/Views/RCTView.m | 20 +++++++++++-- React/Views/RCTViewManager.m | 14 +++++++++ .../renderer/components/view/ViewProps.cpp | 10 +++++++ .../renderer/components/view/ViewProps.h | 1 + .../renderer/components/view/conversions.h | 18 +++++++++++ .../renderer/components/view/primitives.h | 7 +++++ packages/rn-tester/Podfile.lock | 12 ++++---- .../rn-tester/js/examples/View/ViewExample.js | 30 +++++++++++++++---- 17 files changed, 147 insertions(+), 14 deletions(-) create mode 100644 React/Views/RCTBorderCurve.h diff --git a/BUCK b/BUCK index 69a9a077041b..7780ff8e1f66 100644 --- a/BUCK +++ b/BUCK @@ -248,6 +248,7 @@ REACT_PUBLIC_HEADERS = { "React/RCTAnimationType.h": RCTVIEWS_PATH + "RCTAnimationType.h", "React/RCTAssert.h": RCTBASE_PATH + "RCTAssert.h", "React/RCTAutoInsetsProtocol.h": RCTVIEWS_PATH + "RCTAutoInsetsProtocol.h", + "React/RCTBorderCurve.h": RCTVIEWS_PATH + "RCTBorderCurve.h", "React/RCTBorderDrawing.h": RCTVIEWS_PATH + "RCTBorderDrawing.h", "React/RCTBorderStyle.h": RCTVIEWS_PATH + "RCTBorderStyle.h", "React/RCTBridge+Private.h": RCTBASE_PATH + "RCTBridge+Private.h", diff --git a/Libraries/Components/View/ReactNativeStyleAttributes.js b/Libraries/Components/View/ReactNativeStyleAttributes.js index 7736e5026db9..542bfd3a88ee 100644 --- a/Libraries/Components/View/ReactNativeStyleAttributes.js +++ b/Libraries/Components/View/ReactNativeStyleAttributes.js @@ -98,6 +98,7 @@ const ReactNativeStyleAttributes: {[string]: AnyAttributeType, ...} = { borderBottomRightRadius: true, borderBottomStartRadius: true, borderColor: colorAttributes, + borderCurve: true, borderEndColor: colorAttributes, borderLeftColor: colorAttributes, borderRadius: true, diff --git a/Libraries/NativeComponent/BaseViewConfig.ios.js b/Libraries/NativeComponent/BaseViewConfig.ios.js index d19693deb929..95cf5dee34f1 100644 --- a/Libraries/NativeComponent/BaseViewConfig.ios.js +++ b/Libraries/NativeComponent/BaseViewConfig.ios.js @@ -193,6 +193,7 @@ const validAttributesForNonEventProps = { removeClippedSubviews: true, borderRadius: true, borderColor: {process: require('../StyleSheet/processColor')}, + borderCurve: true, borderWidth: true, borderStyle: true, hitSlop: {diff: require('../Utilities/differ/insetsDiffer')}, diff --git a/Libraries/StyleSheet/StyleSheetTypes.js b/Libraries/StyleSheet/StyleSheetTypes.js index a12ed0cafc1a..4b7aa36cda6c 100644 --- a/Libraries/StyleSheet/StyleSheetTypes.js +++ b/Libraries/StyleSheet/StyleSheetTypes.js @@ -532,6 +532,7 @@ export type ____ViewStyle_InternalCore = $ReadOnly<{ backfaceVisibility?: 'visible' | 'hidden', backgroundColor?: ____ColorValue_Internal, borderColor?: ____ColorValue_Internal, + borderCurve?: 'circular' | 'continuous', borderBottomColor?: ____ColorValue_Internal, borderEndColor?: ____ColorValue_Internal, borderLeftColor?: ____ColorValue_Internal, diff --git a/React/Base/RCTConvert.h b/React/Base/RCTConvert.h index c4913f60c7ab..ad92515fd584 100644 --- a/React/Base/RCTConvert.h +++ b/React/Base/RCTConvert.h @@ -9,6 +9,7 @@ #import #import +#import #import #import #import @@ -130,6 +131,7 @@ typedef BOOL css_backface_visibility_t; + (RCTPointerEvents)RCTPointerEvents:(id)json; + (RCTAnimationType)RCTAnimationType:(id)json; + (RCTBorderStyle)RCTBorderStyle:(id)json; ++ (RCTBorderCurve)RCTBorderCurve:(id)json; + (RCTTextDecorationLineType)RCTTextDecorationLineType:(id)json; @end diff --git a/React/Base/RCTConvert.m b/React/Base/RCTConvert.m index c21ef072acd4..b44a5430db1a 100644 --- a/React/Base/RCTConvert.m +++ b/React/Base/RCTConvert.m @@ -345,6 +345,15 @@ + (NSLocale *)NSLocale:(id)json RCTBorderStyleSolid, integerValue) +RCT_ENUM_CONVERTER( + RCTBorderCurve, + (@{ + @"circular" : @(RCTBorderCurveCircular), + @"continuous" : @(RCTBorderCurveContinuous), + }), + RCTBorderCurveCircular, + integerValue) + RCT_ENUM_CONVERTER( RCTTextDecorationLineType, (@{ diff --git a/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm b/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm index 06e7b5bd39ca..bf691dba2e15 100644 --- a/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm +++ b/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm @@ -516,6 +516,18 @@ static void RCTReleaseRCTBorderColors(RCTBorderColors borderColors) CGColorRelease(borderColors.right); } +static CALayerCornerCurve CornerCurveFromBorderCurve(BorderCurve borderCurve) +{ + // The constants are available only starting from iOS 13 + // CALayerCornerCurve is a typealias on NSString * + switch (borderCurve) { + case BorderCurve::Continuous: + return @"continuous"; // kCACornerCurveContinuous; + case BorderCurve::Circular: + return @"circular"; // kCACornerCurveCircular; + } +} + static RCTBorderStyle RCTBorderStyleFromBorderStyle(BorderStyle borderStyle) { switch (borderStyle) { @@ -580,6 +592,9 @@ - (void)invalidateLayer layer.borderColor = borderColor; CGColorRelease(borderColor); layer.cornerRadius = (CGFloat)borderMetrics.borderRadii.topLeft; + if (@available(iOS 13.0, *)) { + layer.cornerCurve = CornerCurveFromBorderCurve(borderMetrics.borderCurves.topLeft); + } layer.backgroundColor = _backgroundColor.CGColor; } else { if (!_borderLayer) { diff --git a/React/Views/RCTBorderCurve.h b/React/Views/RCTBorderCurve.h new file mode 100644 index 000000000000..96002659ed70 --- /dev/null +++ b/React/Views/RCTBorderCurve.h @@ -0,0 +1,13 @@ +/* + * 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. + */ + +#import + +typedef NS_ENUM(NSInteger, RCTBorderCurve) { + RCTBorderCurveContinuous = 0, + RCTBorderCurveCircular, +}; diff --git a/React/Views/RCTView.h b/React/Views/RCTView.h index fe27daae1fb0..b3df8e80a68b 100644 --- a/React/Views/RCTView.h +++ b/React/Views/RCTView.h @@ -7,6 +7,7 @@ #import +#import #import #import #import @@ -93,6 +94,11 @@ extern const UIAccessibilityTraits SwitchAccessibilityTrait; @property (nonatomic, assign) CGFloat borderEndWidth; @property (nonatomic, assign) CGFloat borderWidth; +/** + * Border curve. + */ +@property (nonatomic, assign) RCTBorderCurve borderCurve; + /** * Border styles. */ diff --git a/React/Views/RCTView.m b/React/Views/RCTView.m index 03dcc94d9310..7fb45443248a 100644 --- a/React/Views/RCTView.m +++ b/React/Views/RCTView.m @@ -10,6 +10,7 @@ #import #import "RCTAutoInsetsProtocol.h" +#import "RCTBorderCurve.h" #import "RCTBorderDrawing.h" #import "RCTI18nUtil.h" #import "RCTLog.h" @@ -126,6 +127,7 @@ - (instancetype)initWithFrame:(CGRect)frame _borderBottomRightRadius = -1; _borderBottomStartRadius = -1; _borderBottomEndRadius = -1; + _borderCurve = RCTBorderCurveCircular; _borderStyle = RCTBorderStyleSolid; _hitTestEdgeInsets = UIEdgeInsetsZero; @@ -945,6 +947,20 @@ -(void)setBorder##side##Radius : (CGFloat)radius \ setBorderRadius(TopEnd) setBorderRadius(BottomLeft) setBorderRadius(BottomRight) setBorderRadius(BottomStart) setBorderRadius(BottomEnd) +#pragma mark - Border Curve + +#define setBorderCurve(side) \ + -(void)setBorder##side##Curve : (RCTBorderCurve)curve \ + { \ + if (_border##side##Curve == curve) { \ + return; \ + } \ + _border##side##Curve = curve; \ + [self.layer setNeedsDisplay]; \ + } + + setBorderCurve() + #pragma mark - Border Style #define setBorderStyle(side) \ @@ -957,6 +973,6 @@ -(void)setBorder##side##Style : (RCTBorderStyle)style \ [self.layer setNeedsDisplay]; \ } - setBorderStyle() + setBorderStyle() - @end + @end diff --git a/React/Views/RCTViewManager.m b/React/Views/RCTViewManager.m index f10eea73bff7..f1bb13eb7cfa 100644 --- a/React/Views/RCTViewManager.m +++ b/React/Views/RCTViewManager.m @@ -8,6 +8,7 @@ #import "RCTViewManager.h" #import "RCTAssert.h" +#import "RCTBorderCurve.h" #import "RCTBorderStyle.h" #import "RCTBridge.h" #import "RCTConvert+Transform.h" @@ -264,6 +265,19 @@ - (RCTShadowView *)shadowView view.removeClippedSubviews = json ? [RCTConvert BOOL:json] : defaultView.removeClippedSubviews; } } +RCT_CUSTOM_VIEW_PROPERTY(borderCurve, RCTBorderCurve, RCTView) +{ + if (@available(iOS 13.0, *)) { + switch ([RCTConvert RCTBorderCurve:json]) { + case RCTBorderCurveContinuous: + view.layer.cornerCurve = kCACornerCurveContinuous; + break; + case RCTBorderCurveCircular: + view.layer.cornerCurve = kCACornerCurveCircular; + break; + } + } +} RCT_CUSTOM_VIEW_PROPERTY(borderRadius, CGFloat, RCTView) { if ([view respondsToSelector:@selector(setBorderRadius:)]) { diff --git a/ReactCommon/react/renderer/components/view/ViewProps.cpp b/ReactCommon/react/renderer/components/view/ViewProps.cpp index 5be4a80699e4..f04753da8935 100644 --- a/ReactCommon/react/renderer/components/view/ViewProps.cpp +++ b/ReactCommon/react/renderer/components/view/ViewProps.cpp @@ -67,6 +67,15 @@ ViewProps::ViewProps( "Color", sourceProps.borderColors, {})), + borderCurves( + Props::enablePropIteratorSetter ? sourceProps.borderCurves + : convertRawProp( + context, + rawProps, + "border", + "Curve", + sourceProps.borderCurves, + {})), borderStyles( Props::enablePropIteratorSetter ? sourceProps.borderStyles : convertRawProp( @@ -412,6 +421,7 @@ BorderMetrics ViewProps::resolveBorderMetrics( /* .borderWidths = */ borderWidths.resolve(isRTL, 0), /* .borderRadii = */ ensureNoOverlap(borderRadii.resolve(isRTL, 0), layoutMetrics.frame.size), + /* .borderCurves = */ borderCurves.resolve(isRTL, BorderCurve::Circular), /* .borderStyles = */ borderStyles.resolve(isRTL, BorderStyle::Solid), }; } diff --git a/ReactCommon/react/renderer/components/view/ViewProps.h b/ReactCommon/react/renderer/components/view/ViewProps.h index 21a425dc73fe..cc09768ad736 100644 --- a/ReactCommon/react/renderer/components/view/ViewProps.h +++ b/ReactCommon/react/renderer/components/view/ViewProps.h @@ -51,6 +51,7 @@ class ViewProps : public YogaStylableProps, public AccessibilityProps { // Borders CascadedBorderRadii borderRadii{}; CascadedBorderColors borderColors{}; + CascadedBorderCurves borderCurves{}; CascadedBorderStyles borderStyles{}; // Shadow diff --git a/ReactCommon/react/renderer/components/view/conversions.h b/ReactCommon/react/renderer/components/view/conversions.h index f70c9f9b9b00..8a8a30295e51 100644 --- a/ReactCommon/react/renderer/components/view/conversions.h +++ b/ReactCommon/react/renderer/components/view/conversions.h @@ -563,6 +563,24 @@ inline void fromRawValue( react_native_assert(false); } +inline void fromRawValue( + const PropsParserContext &context, + const RawValue &value, + BorderCurve &result) { + react_native_assert(value.hasType()); + auto stringValue = (std::string)value; + if (stringValue == "circular") { + result = BorderCurve::Circular; + return; + } + if (stringValue == "continuous") { + result = BorderCurve::Continuous; + return; + } + LOG(FATAL) << "Could not parse BorderCurve:" << stringValue; + react_native_assert(false); +} + inline void fromRawValue( const PropsParserContext &context, const RawValue &value, diff --git a/ReactCommon/react/renderer/components/view/primitives.h b/ReactCommon/react/renderer/components/view/primitives.h index 16b02c2dd8c8..10fe3bf19c52 100644 --- a/ReactCommon/react/renderer/components/view/primitives.h +++ b/ReactCommon/react/renderer/components/view/primitives.h @@ -77,6 +77,8 @@ inline static bool operator!=(ViewEvents const &lhs, ViewEvents const &rhs) { enum class BackfaceVisibility { Auto, Visible, Hidden }; +enum class BorderCurve { Circular, Continuous }; + enum class BorderStyle { Solid, Dotted, Dashed }; template @@ -202,11 +204,13 @@ struct CascadedRectangleCorners { }; using BorderWidths = RectangleEdges; +using BorderCurves = RectangleCorners; using BorderStyles = RectangleEdges; using BorderColors = RectangleEdges; using BorderRadii = RectangleCorners; using CascadedBorderWidths = CascadedRectangleEdges; +using CascadedBorderCurves = CascadedRectangleCorners; using CascadedBorderStyles = CascadedRectangleEdges; using CascadedBorderColors = CascadedRectangleEdges; using CascadedBorderRadii = CascadedRectangleCorners; @@ -215,6 +219,7 @@ struct BorderMetrics { BorderColors borderColors{}; BorderWidths borderWidths{}; BorderRadii borderRadii{}; + BorderCurves borderCurves{}; BorderStyles borderStyles{}; bool operator==(const BorderMetrics &rhs) const { @@ -222,11 +227,13 @@ struct BorderMetrics { this->borderColors, this->borderWidths, this->borderRadii, + this->borderCurves, this->borderStyles) == std::tie( rhs.borderColors, rhs.borderWidths, rhs.borderRadii, + rhs.borderCurves, rhs.borderStyles); } diff --git a/packages/rn-tester/Podfile.lock b/packages/rn-tester/Podfile.lock index 824da7bca361..96fed7c9a97f 100644 --- a/packages/rn-tester/Podfile.lock +++ b/packages/rn-tester/Podfile.lock @@ -753,7 +753,7 @@ DEPENDENCIES: - RCTRequired (from `../../Libraries/RCTRequired`) - RCTTypeSafety (from `../../Libraries/TypeSafety`) - React (from `../../`) - - React-bridging (from `../../ReactCommon/react/bridging`) + - React-bridging (from `../../ReactCommon`) - React-callinvoker (from `../../ReactCommon/callinvoker`) - React-Codegen (from `build/generated/ios`) - React-Core (from `../../`) @@ -826,7 +826,7 @@ EXTERNAL SOURCES: React: :path: "../../" React-bridging: - :path: "../../ReactCommon/react/bridging" + :path: "../../ReactCommon" React-callinvoker: :path: "../../ReactCommon/callinvoker" React-Codegen: @@ -905,11 +905,11 @@ SPEC CHECKSUMS: glog: 04b94705f318337d7ead9e6d17c019bd9b1f6b1b libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913 OpenSSL-Universal: ebc357f1e6bc71fa463ccb2fe676756aff50e88c - RCT-Folly: 9638863070ed4e7b2be5e91385745a0ad741e9c1 + RCT-Folly: 0080d0a6ebf2577475bda044aa59e2ca1f909cda RCTRequired: 1c8808cf84569265784a6c33984bbb506ada8c6e RCTTypeSafety: b6dcb5036a808864ee8cad66ca15f263c24661cc React: 8d809d414723bb5763093ddec7658066a21ccabc - React-bridging: 3ba3efbd3a2d7d99aad5658b8e48b1c134c16ecf + React-bridging: cc10a051eff1f03306a1d7659593d8aac3242bc3 React-callinvoker: 5f16202ad4e45f0607b1fae0f6955a8f7c87eef1 React-Codegen: 5adf19af97eb37a7d441c040521191e446255086 React-Core: 0cfb25c65d4dcb856b1807fe44a1ebe5e7ec9749 @@ -936,12 +936,12 @@ SPEC CHECKSUMS: React-RCTVibration: 0386f50996a153b3f39cecbe7d139763ac9a9fdf React-rncore: 6daa27c74047a9e13ce3412b99660274a5780603 React-runtimeexecutor: 97dca9247f4d3cfe0733384b189c6930fbd402b7 - ReactCommon: a34f02c7251e6725e744167b9381d5dd9d016591 + ReactCommon: 6cef8ed13ee2a9d7d4cf9660dbe6dd2ea6ba7104 ScreenshotManager: 71d047abd38a77310985b87f8136b620c5c61e88 SocketRocket: fccef3f9c5cedea1353a9ef6ada904fde10d6608 Yoga: 1b1a12ff3d86a10565ea7cbe057d42f5e5fb2a07 YogaKit: f782866e155069a2cca2517aafea43200b01fd5a -PODFILE CHECKSUM: e067e04e7697dc3cd3d3fbd7556f77c6eccf8075 +PODFILE CHECKSUM: 54d9bd86f3c8151531bd4da1d3ba2e2e1f9a6ca9 COCOAPODS: 1.11.3 diff --git a/packages/rn-tester/js/examples/View/ViewExample.js b/packages/rn-tester/js/examples/View/ViewExample.js index 2ea127b9df19..fd15cf4c1ceb 100644 --- a/packages/rn-tester/js/examples/View/ViewExample.js +++ b/packages/rn-tester/js/examples/View/ViewExample.js @@ -17,6 +17,7 @@ const { Text, TouchableWithoutFeedback, View, + Platform, } = require('react-native'); class ViewBorderStyleExample extends React.Component< @@ -360,12 +361,29 @@ exports.examples = [ title: 'Border Radius', render(): React.Node { return ( - - - Too much use of `borderRadius` (especially large radii) on anything - which is scrolling may result in dropped frames. Use sparingly. - - + <> + + + Too much use of `borderRadius` (especially large radii) on + anything which is scrolling may result in dropped frames. Use + sparingly. + + + {Platform.OS === 'ios' && ( + + + View with continuous border curve + + + )} + ); }, }, From 2013a203fc1d088c4bd1da357b8109370bce97f2 Mon Sep 17 00:00:00 2001 From: Samuel Susla Date: Thu, 21 Jul 2022 06:08:23 -0700 Subject: [PATCH 0032/1165] Delete mobile config react_fabric:finalize_updates_on_synchronous_update_view_ios Summary: changelog: [internal] This was used as a kill switch, it has been in place for over 4 months, let's get rid of it. Reviewed By: mdvacca Differential Revision: D37921377 fbshipit-source-id: 594586033694766e13d0f2ab2bcd73b28ba180a9 --- React/Fabric/Mounting/RCTMountingManager.mm | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/React/Fabric/Mounting/RCTMountingManager.mm b/React/Fabric/Mounting/RCTMountingManager.mm index bfe8680d27be..7c26c83a79eb 100644 --- a/React/Fabric/Mounting/RCTMountingManager.mm +++ b/React/Fabric/Mounting/RCTMountingManager.mm @@ -324,10 +324,7 @@ - (void)synchronouslyUpdateViewOnUIThread:(ReactTag)reactTag componentView.layer.opacity = newViewProps.opacity; } - auto reactNativeConfig = _contextContainer->at>("ReactNativeConfig"); - if (reactNativeConfig && reactNativeConfig->getBool("react_fabric:finalize_updates_on_synchronous_update_view_ios")) { - [componentView finalizeUpdates:RNComponentViewUpdateMaskProps]; - } + [componentView finalizeUpdates:RNComponentViewUpdateMaskProps]; } - (void)synchronouslyDispatchCommandOnUIThread:(ReactTag)reactTag From 33d1291e1a96497a4f994e9d622248a745ee1ea6 Mon Sep 17 00:00:00 2001 From: "Zihan Chen (MSFT)" <53799235+ZihanChen-MSFT@users.noreply.github.com> Date: Thu, 21 Jul 2022 06:38:59 -0700 Subject: [PATCH 0033/1165] Support TypeScript array types for turbo module (component only) (#34216) Summary: Turbo module codegen for component parse `readonly T[]` and `readonly Object[][]` incorrectly. In this change, it is fixed, with necessary test cases added. ## Changelog [General] [Added] - Support TypeScript array types for turbo module (component only) Pull Request resolved: https://github.com/facebook/react-native/pull/34216 Test Plan: `yarn jest` passed in `packages/react-native-codegen` Reviewed By: sammy-SC Differential Revision: D37953004 Pulled By: cipolleschi fbshipit-source-id: b71ea35eb9c4bd5dc41130f1dcf9201704ec298e --- .../components/__test_fixtures__/fixtures.js | 133 ++++ .../typescript-component-parser-test.js.snap | 684 ++++++++++++++++++ .../parsers/typescript/components/props.js | 84 ++- 3 files changed, 872 insertions(+), 29 deletions(-) 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 cb1357c40127..e27afe6a4b6e 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 @@ -459,6 +459,138 @@ export default codegenNativeComponent( ) as HostComponent; `; +const ARRAY2_PROP_TYPES_NO_EVENTS = ` +/** + * 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 { + // 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_PROP_TYPES_NO_EVENTS = ` /** * Copyright (c) Meta Platforms, Inc. and affiliates. @@ -959,6 +1091,7 @@ export default codegenNativeComponent( module.exports = { ALL_PROP_TYPES_NO_EVENTS, ARRAY_PROP_TYPES_NO_EVENTS, + ARRAY2_PROP_TYPES_NO_EVENTS, OBJECT_PROP_TYPES_NO_EVENTS, PROPS_ALIASED_LOCALLY, ONE_OF_EACH_PROP_EVENT_DEFAULT_AND_OPTIONS, 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 bfaa95fdbf98..27ea1405c86e 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 @@ -1231,6 +1231,690 @@ 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`] = ` +"{ + '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 COMMANDS_AND_EVENTS_TYPES_EXPORTED 1`] = ` "{ 'modules': { 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 74659ff0dc6e..ff2f94c00e5a 100644 --- a/packages/react-native-codegen/src/parsers/typescript/components/props.js +++ b/packages/react-native-codegen/src/parsers/typescript/components/props.js @@ -41,12 +41,54 @@ function getPropProperties( } } +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 ( @@ -56,7 +98,7 @@ function getTypeAnnotationForArray( ) ) { 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"', + 'Nested optionals such as "ReadonlyArray" are not supported, please declare optionals at the top level of value definitions as in "ReadonlyArray | null | undefined"', ); } @@ -69,44 +111,28 @@ function getTypeAnnotationForArray( ); } + // 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 { - type: 'ObjectTypeAnnotation', - properties: flattenProperties( - objectType.typeParameters.params[0].members || - objectType.typeParameters.params, - types, - ) - .map(prop => buildPropSchema(prop, types)) - .filter(Boolean), - }; + return getTypeAnnotationForObjectAsArrayElement(objectType, types); } + // Covers: ReadonlyArray if (objectType.typeName.name === 'ReadonlyArray') { - // We need to go yet another level deeper to resolve - // types that may be defined in a type alias - const nestedObjectType = getValueFromTypes( + return getTypeAnnotationForArrayOfArrayOfObject( objectType.typeParameters.params[0], types, ); - - return { - type: 'ArrayTypeAnnotation', - elementType: { - type: 'ObjectTypeAnnotation', - properties: flattenProperties( - nestedObjectType.typeParameters.params[0].members || - nestedObjectType.typeParameters.params, - types, - ) - .map(prop => buildPropSchema(prop, types)) - .filter(Boolean), - }, - }; } } @@ -239,7 +265,7 @@ function getTypeAnnotation( type: 'ArrayTypeAnnotation', elementType: getTypeAnnotationForArray( name, - typeAnnotation.typeAnnotation, + typeAnnotation.typeAnnotation.elementType, defaultValue, types, ), From b9cf207db9c18bddf9b9c719dd905e802ae6a504 Mon Sep 17 00:00:00 2001 From: Dark Knight <> Date: Thu, 21 Jul 2022 12:21:48 -0700 Subject: [PATCH 0034/1165] Revert D37912783: Multisect successfully blamed D37912783 for test or build failures Summary: changelog: [internal] This diff is reverting D37912783 (https://github.com/facebook/react-native/commit/2b57b749fbdeee8340dee385288d194155f693c8) Depends on D38035753 D37912783 (https://github.com/facebook/react-native/commit/2b57b749fbdeee8340dee385288d194155f693c8) has been identified to be causing the following test or build failures: Tests affected: - https://www.internalfb.com/intern/test/281475006604971/ Here's the Multisect link: https://www.internalfb.com/intern/testinfra/multisect/1077515 Here are the tasks that are relevant to this breakage: T93091116: 1 test started failing for oncall messenger_kids_www_rn in the last 2 weeks We're generating a revert to back out the changes in this diff, please note the backout may land if someone accepts it. Reviewed By: sammy-SC Differential Revision: D38035761 fbshipit-source-id: 70034af3275b7b69c0b50f12a377182d4f23e669 --- .../react/bridge/CatalystInstanceImpl.java | 13 +++++-- .../react/config/ReactFeatureFlags.java | 4 +++ .../jni/react/jni/CatalystInstanceImpl.cpp | 36 +++++++++++++------ .../main/jni/react/jni/CatalystInstanceImpl.h | 12 +++++-- 4 files changed, 50 insertions(+), 15 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java index ad5fb6985f9d..50aedd434212 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java +++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java @@ -108,7 +108,8 @@ public String toString() { // C++ parts private final HybridData mHybridData; - private static native HybridData initHybrid(); + private static native HybridData initHybrid( + boolean enableRuntimeScheduler, boolean enableRuntimeSchedulerInTurboModule); public native CallInvokerHolderImpl getJSCallInvokerHolder(); @@ -123,7 +124,15 @@ private CatalystInstanceImpl( FLog.d(ReactConstants.TAG, "Initializing React Xplat Bridge."); Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "createCatalystInstanceImpl"); - mHybridData = initHybrid(); + if (ReactFeatureFlags.enableRuntimeSchedulerInTurboModule + && !ReactFeatureFlags.enableRuntimeScheduler) { + Assertions.assertUnreachable(); + } + + mHybridData = + initHybrid( + ReactFeatureFlags.enableRuntimeScheduler, + ReactFeatureFlags.enableRuntimeSchedulerInTurboModule); mReactQueueConfiguration = ReactQueueConfigurationImpl.create( diff --git a/ReactAndroid/src/main/java/com/facebook/react/config/ReactFeatureFlags.java b/ReactAndroid/src/main/java/com/facebook/react/config/ReactFeatureFlags.java index 68728b18fed4..a8a5264042ba 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/config/ReactFeatureFlags.java +++ b/ReactAndroid/src/main/java/com/facebook/react/config/ReactFeatureFlags.java @@ -70,6 +70,10 @@ public class ReactFeatureFlags { /** This feature flag enables logs for Fabric */ public static boolean enableFabricLogs = false; + public static boolean enableRuntimeScheduler = false; + + public static boolean enableRuntimeSchedulerInTurboModule = false; + /** Feature flag to configure eager attachment of the root view/initialisation of the JS code */ public static boolean enableEagerRootViewAttachment = false; diff --git a/ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.cpp b/ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.cpp index e44913e4fd08..6a936c66f66f 100644 --- a/ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.cpp +++ b/ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.cpp @@ -93,12 +93,21 @@ class JInstanceCallback : public InstanceCallback { } // namespace jni::local_ref -CatalystInstanceImpl::initHybrid(jni::alias_ref) { - return makeCxxInstance(); +CatalystInstanceImpl::initHybrid( + jni::alias_ref, + bool enableRuntimeScheduler, + bool enableRuntimeSchedulerInTurboModule) { + return makeCxxInstance( + enableRuntimeScheduler, enableRuntimeSchedulerInTurboModule); } -CatalystInstanceImpl::CatalystInstanceImpl() - : instance_(std::make_unique()) {} +CatalystInstanceImpl::CatalystInstanceImpl( + bool enableRuntimeScheduler, + bool enableRuntimeSchedulerInTurboModule) + : instance_(std::make_unique()), + enableRuntimeScheduler_(enableRuntimeScheduler), + enableRuntimeSchedulerInTurboModule_( + enableRuntimeScheduler && enableRuntimeSchedulerInTurboModule) {} void CatalystInstanceImpl::warnOnLegacyNativeModuleSystemUse() { CxxNativeModule::setShouldWarnOnUse(true); @@ -373,12 +382,17 @@ void CatalystInstanceImpl::handleMemoryPressure(int pressureLevel) { jni::alias_ref CatalystInstanceImpl::getJSCallInvokerHolder() { if (!jsCallInvokerHolder_) { - auto runtimeScheduler = getRuntimeScheduler(); - auto runtimeSchedulerCallInvoker = - std::make_shared( - runtimeScheduler->cthis()->get()); - jsCallInvokerHolder_ = jni::make_global( - CallInvokerHolder::newObjectCxxArgs(runtimeSchedulerCallInvoker)); + if (enableRuntimeSchedulerInTurboModule_) { + auto runtimeScheduler = getRuntimeScheduler(); + auto runtimeSchedulerCallInvoker = + std::make_shared( + runtimeScheduler->cthis()->get()); + jsCallInvokerHolder_ = jni::make_global( + CallInvokerHolder::newObjectCxxArgs(runtimeSchedulerCallInvoker)); + } else { + jsCallInvokerHolder_ = jni::make_global( + CallInvokerHolder::newObjectCxxArgs(instance_->getJSCallInvoker())); + } } return jsCallInvokerHolder_; } @@ -426,7 +440,7 @@ CatalystInstanceImpl::getRuntimeExecutor() { jni::alias_ref CatalystInstanceImpl::getRuntimeScheduler() { - if (!runtimeScheduler_) { + if (enableRuntimeScheduler_ && !runtimeScheduler_) { auto runtimeExecutor = instance_->getRuntimeExecutor(); auto runtimeScheduler = std::make_shared(runtimeExecutor); diff --git a/ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.h b/ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.h index cd242903faba..fe635bf48250 100644 --- a/ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.h +++ b/ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.h @@ -37,7 +37,10 @@ class CatalystInstanceImpl : public jni::HybridClass { static constexpr auto kJavaDescriptor = "Lcom/facebook/react/bridge/CatalystInstanceImpl;"; - static jni::local_ref initHybrid(jni::alias_ref); + static jni::local_ref initHybrid( + jni::alias_ref, + bool enableRuntimeScheduler, + bool enableRuntimeSchedulerInTurboModule); static void registerNatives(); @@ -48,7 +51,9 @@ class CatalystInstanceImpl : public jni::HybridClass { private: friend HybridBase; - CatalystInstanceImpl(); + CatalystInstanceImpl( + bool enableRuntimeScheduler, + bool enableRuntimeSchedulerInTurboModule); void initializeBridge( jni::alias_ref callback, @@ -115,6 +120,9 @@ class CatalystInstanceImpl : public jni::HybridClass { jni::global_ref nativeCallInvokerHolder_; jni::global_ref runtimeExecutor_; jni::global_ref runtimeScheduler_; + + bool const enableRuntimeScheduler_; + bool const enableRuntimeSchedulerInTurboModule_; }; } // namespace react From a333eb2ac54a86d9b2dd49b4ea5508d6177a4d08 Mon Sep 17 00:00:00 2001 From: Pieter Vanderwerff Date: Thu, 21 Jul 2022 12:31:37 -0700 Subject: [PATCH 0035/1165] Deploy suppressions ahead of 0.183.0 to xplat Summary: Changelog: [Internal] Reviewed By: SamChou19815 Differential Revision: D38020751 fbshipit-source-id: d32b15429605d2c42195d98de9e5455926f0022b --- Libraries/Image/Image.ios.js | 2 ++ Libraries/StyleSheet/splitLayoutProps.js | 2 ++ 2 files changed, 4 insertions(+) diff --git a/Libraries/Image/Image.ios.js b/Libraries/Image/Image.ios.js index 7b5d0c0c4337..f4c5ca3ca421 100644 --- a/Libraries/Image/Image.ios.js +++ b/Libraries/Image/Image.ios.js @@ -126,7 +126,9 @@ const BaseImage = (props: ImagePropsType, forwardedRef) => { } } + // $FlowFixMe[prop-missing] const resizeMode = props.resizeMode || style.resizeMode || 'cover'; + // $FlowFixMe[prop-missing] const tintColor = style.tintColor; if (props.src != null) { diff --git a/Libraries/StyleSheet/splitLayoutProps.js b/Libraries/StyleSheet/splitLayoutProps.js index 8575d2638738..9fdf9e86c9e0 100644 --- a/Libraries/StyleSheet/splitLayoutProps.js +++ b/Libraries/StyleSheet/splitLayoutProps.js @@ -51,11 +51,13 @@ export default function splitLayoutProps(props: ?____ViewStyle_Internal): { case 'transform': // $FlowFixMe[cannot-write] // $FlowFixMe[incompatible-use] + // $FlowFixMe[prop-missing] outer[prop] = props[prop]; break; default: // $FlowFixMe[cannot-write] // $FlowFixMe[incompatible-use] + // $FlowFixMe[prop-missing] inner[prop] = props[prop]; break; } From 8cd63de7ea2315194305581ccd7f38c79c1e59b5 Mon Sep 17 00:00:00 2001 From: Daniel Andersson Date: Thu, 21 Jul 2022 12:43:30 -0700 Subject: [PATCH 0036/1165] Minor improvements to NativeState Summary: Minor improvements to NativeState implementation and test. Does not change the API. Changelog: [Internal][Changed] - Minor improvements to jsi::NativeState Reviewed By: neildhar Differential Revision: D37961515 fbshipit-source-id: b87dcf2458ace883c784f3127a13f5a6c296d4a2 --- ReactCommon/jsi/jsi/jsi-inl.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ReactCommon/jsi/jsi/jsi-inl.h b/ReactCommon/jsi/jsi/jsi-inl.h index 992ee9f535e8..c3cad4dd8e7f 100644 --- a/ReactCommon/jsi/jsi/jsi-inl.h +++ b/ReactCommon/jsi/jsi/jsi-inl.h @@ -208,6 +208,11 @@ inline bool Object::hasNativeState(Runtime& runtime) const { std::dynamic_pointer_cast(runtime.getNativeState(*this)); } +template <> +inline bool Object::hasNativeState(Runtime& runtime) const { + return runtime.hasNativeState(*this); +} + template inline std::shared_ptr Object::getNativeState(Runtime& runtime) const { assert(hasNativeState(runtime)); From 8fbcb0b6a3f35ccc7492057d2ff96c49b0374627 Mon Sep 17 00:00:00 2001 From: Pieter Vanderwerff Date: Thu, 21 Jul 2022 13:08:33 -0700 Subject: [PATCH 0037/1165] Deploy 0.183.0 to xplat Summary: Changelog: [Internal] Reviewed By: suvarshibhadra, SamChou19815 Differential Revision: D38020761 fbshipit-source-id: 7e55f270e9fcf6f7991946432cf63aff6ee4d5b2 --- .flowconfig | 2 +- .flowconfig.android | 2 +- package.json | 2 +- repo-config/package.json | 2 +- template/_flowconfig | 2 +- yarn.lock | 8 ++++---- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.flowconfig b/.flowconfig index c2d114b4f676..73732dda4a34 100644 --- a/.flowconfig +++ b/.flowconfig @@ -74,4 +74,4 @@ untyped-import untyped-type-import [version] -^0.182.0 +^0.183.0 diff --git a/.flowconfig.android b/.flowconfig.android index dc9d12aba7e9..c999cadd3a58 100644 --- a/.flowconfig.android +++ b/.flowconfig.android @@ -74,4 +74,4 @@ untyped-import untyped-type-import [version] -^0.182.0 +^0.183.0 diff --git a/package.json b/package.json index 47d6ffdbe277..bf0ecc57ca7f 100644 --- a/package.json +++ b/package.json @@ -136,7 +136,7 @@ "ws": "^6.1.4" }, "devDependencies": { - "flow-bin": "^0.182.0", + "flow-bin": "^0.183.0", "hermes-eslint": "0.8.0", "react": "18.1.0", "react-test-renderer": "^18.1.0" diff --git a/repo-config/package.json b/repo-config/package.json index b28f4e453a0e..886c20d56577 100644 --- a/repo-config/package.json +++ b/repo-config/package.json @@ -32,7 +32,7 @@ "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-native": "^4.0.0", "eslint-plugin-relay": "^1.8.3", - "flow-bin": "^0.182.0", + "flow-bin": "^0.183.0", "inquirer": "^7.1.0", "jest": "^26.6.3", "jest-junit": "^10.0.0", diff --git a/template/_flowconfig b/template/_flowconfig index 3782e447cdef..15c6d8153303 100644 --- a/template/_flowconfig +++ b/template/_flowconfig @@ -63,4 +63,4 @@ untyped-import untyped-type-import [version] -^0.182.0 +^0.183.0 diff --git a/yarn.lock b/yarn.lock index 78882cf943f2..4d30f85bd10c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3240,10 +3240,10 @@ flatted@^3.1.0: resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.2.tgz#64bfed5cb68fe3ca78b3eb214ad97b63bedce561" integrity sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA== -flow-bin@^0.182.0: - version "0.182.0" - resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.182.0.tgz#1dacbd72465743670412ada015d3182deda6f966" - integrity sha512-Ux90c2sMfoV/VVjOEFT2OHFJFnyfoIbTK/5AKAMnU4Skfru1G+FyS5YLu3XxQl0R6mpA9+rrFlPfYZq/5B+J3w== +flow-bin@^0.183.0: + version "0.183.0" + resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.183.0.tgz#17f37c94edd04b705a897b5890dd6cdc02e0c94e" + integrity sha512-7IJHUnMPYgNEZU8t9M4vJII/G+fJft9C/INm2+HRSXx5KDF2j+vD2iap6+Yg2FWgXTnNLUvk7kr1QdO5Fk/8/Q== flow-parser@0.*: version "0.163.0" From 1237952d070bfe28ff2c94cd9bf8ea19e6cdd395 Mon Sep 17 00:00:00 2001 From: Sim Sun Date: Thu, 21 Jul 2022 16:43:01 -0700 Subject: [PATCH 0038/1165] Bump SoLoader version to 0.10.4 Summary: ## Changelog [Android] [Changed] - Bump Soloader to 0.10.4 Reviewed By: cortinico Differential Revision: D37988583 fbshipit-source-id: 6d2a423f39c2c4077bad29406e8d9fd67141045b --- ReactAndroid/hermes-engine/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ReactAndroid/hermes-engine/build.gradle b/ReactAndroid/hermes-engine/build.gradle index ab79d88004af..79a260b1fc57 100644 --- a/ReactAndroid/hermes-engine/build.gradle +++ b/ReactAndroid/hermes-engine/build.gradle @@ -199,7 +199,7 @@ android { dependencies { implementation("com.facebook.fbjni:fbjni:0.2.2") - implementation("com.facebook.soloader:soloader:0.10.3") + implementation("com.facebook.soloader:soloader:0.10.4") implementation("com.facebook.yoga:proguard-annotations:1.19.0") implementation("androidx.annotation:annotation:1.3.0") } From 087f142cb79803cf0fdbe89e172176767b650b6e Mon Sep 17 00:00:00 2001 From: Sam Zhou Date: Thu, 21 Jul 2022 21:17:16 -0700 Subject: [PATCH 0039/1165] Release resolved-env Summary: Changelog: [internal] Reviewed By: bradzacher Differential Revision: D38054157 fbshipit-source-id: 6f859e45623168e5b17b5303adb5955b74fc3641 --- .flowconfig | 2 +- .flowconfig.android | 2 +- .../rn-tester/js/examples/TextInput/TextInputExample.ios.js | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.flowconfig b/.flowconfig index 73732dda4a34..fef98d162110 100644 --- a/.flowconfig +++ b/.flowconfig @@ -52,7 +52,7 @@ suppress_type=$FlowFixMeProps suppress_type=$FlowFixMeState suppress_type=$FlowFixMeEmpty -experimental.env_mode=ssa +experimental.env_mode=resolved [lints] sketchy-null-number=warn diff --git a/.flowconfig.android b/.flowconfig.android index c999cadd3a58..6988748dd128 100644 --- a/.flowconfig.android +++ b/.flowconfig.android @@ -52,7 +52,7 @@ suppress_type=$FlowFixMeProps suppress_type=$FlowFixMeState suppress_type=$FlowFixMeEmpty -experimental.env_mode=ssa +experimental.env_mode=resolved [lints] sketchy-null-number=warn diff --git a/packages/rn-tester/js/examples/TextInput/TextInputExample.ios.js b/packages/rn-tester/js/examples/TextInput/TextInputExample.ios.js index 5d27d97eccbc..f5901a8f1107 100644 --- a/packages/rn-tester/js/examples/TextInput/TextInputExample.ios.js +++ b/packages/rn-tester/js/examples/TextInput/TextInputExample.ios.js @@ -96,6 +96,7 @@ class TextInputAccessoryViewChangeKeyboardExample extends React.Component< return ( Set InputAccessoryView with ID & switch keyboard: + {/* $FlowFixMe[incompatible-use] */} Date: Fri, 22 Jul 2022 02:13:47 -0700 Subject: [PATCH 0040/1165] Simplify logic to choose if we need to build hermes from source or not. (#34232) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/34232 This diff simplify the logic to decide whether we want to build hermes from source or not. The requirement we have is that we don't want our users to build hermes. So, we don't want to build hermes when there is a precompiled tarball available, while we want to build hermes in CI. ## Changelog [General][Changed] - Build hermes when in CI and not when there is a tarball Reviewed By: cortinico Differential Revision: D37999748 fbshipit-source-id: 7d9cab51c37fb47db216055c057a22081e10df07 --- scripts/hermes/hermes-utils.js | 62 +--------------------- scripts/hermes/prepare-hermes-for-build.js | 11 ++-- sdks/hermes-engine/hermes-engine.podspec | 5 +- 3 files changed, 10 insertions(+), 68 deletions(-) diff --git a/scripts/hermes/hermes-utils.js b/scripts/hermes/hermes-utils.js index 1dc2bba067d6..d9db7a4aba61 100644 --- a/scripts/hermes/hermes-utils.js +++ b/scripts/hermes/hermes-utils.js @@ -15,7 +15,6 @@ const {execSync} = require('child_process'); const SDKS_DIR = path.normalize(path.join(__dirname, '..', '..', 'sdks')); const HERMES_DIR = path.join(SDKS_DIR, 'hermes'); -const DEFAULT_HERMES_TAG = 'main'; const HERMES_TAG_FILE_PATH = path.join(SDKS_DIR, '.hermesversion'); const HERMES_TARBALL_BASE_URL = 'https://github.com/facebook/hermes/tarball/'; const HERMES_TARBALL_DOWNLOAD_DIR = path.join(SDKS_DIR, 'download'); @@ -162,65 +161,8 @@ function isTestingAgainstLocalHermesTarball() { return 'HERMES_ENGINE_TARBALL_PATH' in process.env; } -function isOnAReactNativeReleaseBranch() { - try { - let currentBranch = execSync('git rev-parse --abbrev-ref HEAD') - .toString() - .trim(); - let currentRemote = execSync('git config --get remote.origin.url') - .toString() - .trim(); - return ( - currentBranch.endsWith('-stable') && - currentRemote.endsWith('facebook/react-native.git') - ); - } catch (error) { - // If not inside a git repo, we're going to fail here and return. - return false; - } -} - -function isOnAReactNativeReleaseTag() { - try { - // If on a named tag, this method will return the tag name. - // If not, it will throw as the return code is not 0. - execSync('git describe --exact-match HEAD', {stdio: 'ignore'}); - } catch (error) { - return false; - } - let currentRemote = execSync('git config --get remote.origin.url') - .toString() - .trim(); - return currentRemote.endsWith('facebook/react-native.git'); -} - -function isRequestingLatestCommitFromHermesMainBranch() { - const hermesTag = readHermesTag(); - return hermesTag === DEFAULT_HERMES_TAG; -} - -function isPRAgainstStable(pullRequest) { - if (pullRequest == null) { - return false; - } - - const prComponents = pullRequest.split('/'); - const prNumber = prComponents[prComponents.length - 1]; - const apiURL = `https://api.github.com/repos/facebook/react-native/pulls/${prNumber}`; - const prJson = JSON.parse(execSync(`curl ${apiURL}`).toString()); - const baseBranch = prJson.base.label; - - return baseBranch.endsWith('-stable'); -} - -function shouldBuildHermesFromSource(pullRequest) { - return ( - !isTestingAgainstLocalHermesTarball() && - (isOnAReactNativeReleaseBranch() || - isOnAReactNativeReleaseTag() || - isPRAgainstStable(pullRequest) || - isRequestingLatestCommitFromHermesMainBranch()) - ); +function shouldBuildHermesFromSource(isInCI) { + return !isTestingAgainstLocalHermesTarball() && isInCI; } function shouldUsePrebuiltHermesC(os) { diff --git a/scripts/hermes/prepare-hermes-for-build.js b/scripts/hermes/prepare-hermes-for-build.js index 42b33bad58a0..140d9f3a4380 100644 --- a/scripts/hermes/prepare-hermes-for-build.js +++ b/scripts/hermes/prepare-hermes-for-build.js @@ -23,12 +23,11 @@ const { shouldBuildHermesFromSource, } = require('./hermes-utils'); -async function main(pullRequest) { - if (!shouldBuildHermesFromSource(pullRequest)) { +async function main(isInCI) { + if (!shouldBuildHermesFromSource(isInCI)) { copyPodSpec(); return; } - downloadHermesTarball(); expandHermesTarball(); copyPodSpec(); @@ -40,8 +39,8 @@ async function main(pullRequest) { } } -const pullRequest = process.argv.length > 2 ? process.argv[2] : null; -console.log(`Pull request detected: ${pullRequest}`); -main(pullRequest).then(() => { +const isInCI = process.env.CI === 'true'; + +main(isInCI).then(() => { process.exit(0); }); diff --git a/sdks/hermes-engine/hermes-engine.podspec b/sdks/hermes-engine/hermes-engine.podspec index 8d331e096ad2..430ab9e7639a 100644 --- a/sdks/hermes-engine/hermes-engine.podspec +++ b/sdks/hermes-engine/hermes-engine.podspec @@ -13,6 +13,8 @@ import_hermesc_file=File.join(__dir__, "..", "hermesc", "osx-bin", "ImportHermes package_file = File.join(__dir__, "..", "..", "package.json") package = JSON.parse(File.read(package_file)) version = package['version'] +isInCI = ENV['CI'] == true +hermestag_file = File.join(__dir__, "..", ".hermesversion") # We need to check the current git branch/remote to verify if # we're on a React Native release branch to actually build Hermes. @@ -29,9 +31,8 @@ elsif version == '1000.0.0' Pod::UI.puts '[Hermes] Hermes needs to be compiled, installing hermes-engine may take a while...'.yellow if Object.const_defined?("Pod::UI") source[:git] = git source[:commit] = `git ls-remote https://github.com/facebook/hermes main | cut -f 1`.strip -elsif currentremote.strip.end_with?("facebook/react-native.git") and currentbranch.strip.end_with?("-stable") +elsif File.exists?(hermestag_file) && isInCI Pod::UI.puts '[Hermes] Detected that you are on a React Native release branch, building Hermes from source...'.yellow if Object.const_defined?("Pod::UI") - hermestag_file = File.join(__dir__, "..", ".hermesversion") hermestag = File.read(hermestag_file).strip source[:git] = git source[:tag] = hermestag From 77752fc4037e66d5b0a5851bae79c4d3285ed334 Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Fri, 22 Jul 2022 02:28:07 -0700 Subject: [PATCH 0041/1165] Update Podfile for `PRODUCTION=1 pod install` (#34234) Summary: ### Mentioned - pr[main]: https://github.com/facebook/react-native/pull/33882 - discussion: https://github.com/reactwg/react-native-releases/discussions/21#discussioncomment-2945972 - pr[0.69-stable]: https://github.com/facebook/react-native/pull/34098 Close: https://github.com/facebook/react-native/issues/33764 Saw the issue ago couple wks too: https://github.com/leotm/react-native-template-new-architecture/issues/757 Fixed similarly: https://github.com/leotm/react-native-template-new-architecture/pull/791 ## Changelog [iOS] [Changed] - Update Podfile to allow `PRODUCTION=1 pod install` [CATEGORY] [TYPE] - Message Pull Request resolved: https://github.com/facebook/react-native/pull/34234 Test Plan: Everything builds and runs as expected Reviewed By: cortinico Differential Revision: D38029117 Pulled By: cipolleschi fbshipit-source-id: bdb58200a999cb66f1043a2feb670f9037c8e463 --- scripts/react_native_pods.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/react_native_pods.rb b/scripts/react_native_pods.rb index 80f98c0a90c3..8390a3ab6d0e 100644 --- a/scripts/react_native_pods.rb +++ b/scripts/react_native_pods.rb @@ -37,7 +37,7 @@ def use_react_native! ( path: "../node_modules/react-native", fabric_enabled: false, new_arch_enabled: ENV['RCT_NEW_ARCH_ENABLED'] == '1', - production: false, + production: ENV['PRODUCTION'] == '1', hermes_enabled: true, flipper_configuration: FlipperConfiguration.disabled, app_path: '..', From ccdf9ac9853601a81ff21f8f42f5bd866dd4de75 Mon Sep 17 00:00:00 2001 From: Riccardo Cipolleschi Date: Fri, 22 Jul 2022 05:56:02 -0700 Subject: [PATCH 0042/1165] Reduce flakiness of CI (#34235) Summary: How the Hermes cache worked had a concurrency issue. It used to work by asking the Hermes repository for the latest commit and using that commit as cache key to try and retrieve a built version of Hermes to avoid to compile it more than once. The problem happened when the `build_hermes_macos` was building Hermes using a commit A. While building, another PR could be merged into `hermes:main`, creating commit B. When this happened, the tasks `test_ios` and `test_ios_rntester`would try to retrieve a cached version of Hermes using commit B. That version did not exist because Hermes was created using commit A, and the job would either fail or trying to build Hermes from source, ending up taking a lot of time. This PR attaches the `.hermes-cache-key-file` to the workspace and restores it in the other jobs, making sure that the same cache key is used in all three jobs. ## Changelog [General] [Changed] - Attach the `.hermes-cache-key-file` to the workspace to avoid race conditions for new PR landing on Hermes and changing the head commit between the time Hermes is built and the time it has to be consumed. Pull Request resolved: https://github.com/facebook/react-native/pull/34235 Test Plan: Tested manually, looking at the messages in CI. **build_hermes_macos** Screenshot 2022-07-21 at 15 40 02 **test_ios_rntester**: notice that the `echo` is not executed, meaning that the `if` does not evaluate to true and, therefore, the file has been correctly attached. Screenshot 2022-07-21 at 15 40 52 **test_ios**: notice that the `echo` is not executed, meaning that the `if` does not evaluate to true and, therefore, the file has been correctly attached. Screenshot 2022-07-21 at 15 46 33 Reviewed By: cortinico Differential Revision: D38037386 Pulled By: cipolleschi fbshipit-source-id: 4db4f7c478e1afb2e4a18ba3d3f70896ed41d235 --- .circleci/config.yml | 39 ++++++++++++++++----------------------- 1 file changed, 16 insertions(+), 23 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 107fba519651..d4da82a4e9b1 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -52,9 +52,8 @@ references: gems_cache_key: &gems_cache_key v1-gems-{{ checksum "Gemfile.lock" }} gradle_cache_key: &gradle_cache_key v1-gradle-{{ checksum "gradle/wrapper/gradle-wrapper.properties" }}-{{ checksum "ReactAndroid/gradle.properties" }} hermes_cache_key: &hermes_cache_key v1-hermes-{{ .Environment.CIRCLE_JOB }}-{{ checksum "/tmp/hermes/hermesversion" }} - hermes_sdk_cache_key: &hermes_sdk_cache_key v1-hermes-{{ checksum "sdks/.hermes-cache-key-file" }} hermes_windows_cache_key: &hermes_windows_cache_key v1-hermes-{{ .Environment.CIRCLE_JOB }}-{{ checksum "tmp/hermes/hermesversion" }} - hermes_tarball_cache_key: &hermes_tarball_cache_key v1-hermes-tarball-{{ checksum "sdks/.hermes-cache-key-file" }} + hermes_tarball_cache_key: &hermes_tarball_cache_key v1-hermes-tarball-{{ checksum "/tmp/hermes/cache/.hermes-cache-key-file" }} pods_cache_key: &pods_cache_key v6-pods-{{ .Environment.CIRCLE_JOB }}-{{ checksum "packages/rn-tester/Podfile.lock.bak" }}-{{ checksum "packages/rn-tester/Podfile" }} windows_yarn_cache_key: &windows_yarn_cache_key v1-win-yarn-cache-{{ arch }}-{{ checksum "yarn.lock" }} yarn_cache_key: &yarn_cache_key v5-yarn-cache-{{ .Environment.CIRCLE_JOB }} @@ -293,10 +292,13 @@ commands: - run: name: Setup Hermes cache command: | - HERMES_CACHE_KEY_FILE="sdks/.hermes-cache-key-file" + HERMES_CACHE_KEY_FILE="/tmp/hermes/cache/.hermes-cache-key-file" if [ ! -f "$HERMES_CACHE_KEY_FILE" ]; then + echo "File not found. Creating it using latest commit from main" + mkdir -p /tmp/hermes/cache git ls-remote https://github.com/facebook/hermes main | cut -f 1 > $HERMES_CACHE_KEY_FILE fi + cat $HERMES_CACHE_KEY_FILE - restore_cache: keys: - *hermes_tarball_cache_key @@ -309,13 +311,13 @@ commands: BASE_PATH=/tmp/hermes/hermes-runtime-darwin/ if [ ! -d $BASE_PATH ]; then echo "Hermes tarball base path not present ($BASE_PATH). Build it from source." - return + exit 0 fi TARBALL=$(ls /tmp/hermes/hermes-runtime-darwin/) TARBALL_PATH=$BASE_PATH$TARBALL if [ ! -f $TARBALL_PATH ]; then echo "Hermes tarball not present ($TARBALL_PATH). Build it from source." - return + exit 0 fi echo "export HERMES_ENGINE_TARBALL_PATH=$TARBALL_PATH" >> $BASH_ENV @@ -472,6 +474,8 @@ jobs: cd scripts sh run_ruby_tests.sh - run_yarn + - attach_workspace: + at: /tmp/hermes/ - run: | cd packages/rn-tester bundle check || bundle install @@ -761,6 +765,9 @@ jobs: - brew_install: package: cmake + - attach_workspace: + at: /tmp/hermes + - with_hermes_tarball_cache_span: set_tarball_path: True steps: @@ -1002,38 +1009,24 @@ jobs: brew install cmake - with_hermes_tarball_cache_span: steps: + - persist_to_workspace: + root: /tmp/hermes/ + paths: + - cache - run: name: Build the Hermes iOS frameworks command: | - if [[ -d "~/react-native/sdks/hermes/destroot" && -d "/tmp/hermes/hermes-runtime-darwin/" ]]; then - echo "destroot and tarball exists. Skip building" - return - fi - echo "either destroot or the tarball does not exists. Build from source" - cd ~/react-native/sdks/hermes ./utils/build-ios-framework.sh - run: name: Build the Hermes Mac frameworks command: | - if [[ -d "~/react-native/sdks/hermes/destroot" && -d "/tmp/hermes/hermes-runtime-darwin/" ]]; then - echo "destroot and tarball exists. Skip building" - return - fi - echo "either destroot or the tarball does not exists. Build from source" - cd ~/react-native/sdks/hermes ./utils/build-mac-framework.sh cp build_macosx/bin/hermesc /tmp/hermes/osx-bin/. - run: name: Package the Hermes Apple frameworks command: | - if [[ -d "~/react-native/sdks/hermes/destroot" && -d "/tmp/hermes/hermes-runtime-darwin/" ]]; then - echo "destroot and tarball exists. Skip building" - return - fi - echo "either destroot or the tarball does not exists. Build from source" - cd ~/react-native/sdks/hermes . ./utils/build-apple-framework.sh From 1e3cb9170794afa03a3b4b15f75b711dace7a774 Mon Sep 17 00:00:00 2001 From: Tony Du Date: Fri, 22 Jul 2022 13:08:45 -0700 Subject: [PATCH 0043/1165] Allow multiline TextInputs be submittable without blurring (#33653) Summary: For multiline TextInputs, it's possible to send the submit event when pressing the return key only with `blurOnSubmit`. However, there's currently no way to do so without blurring the input and dismissing the keyboard. This problem is apparent when we want to use a TextInput to span multiple lines but still have it be submittable (but not blurrable), like one might want for a TODO list. ![multiline-momentary-blur](https://user-images.githubusercontent.com/22553678/163596940-aae779f5-4d2a-4425-8ed0-e4aa77b90699.gif) ## Changelog [General] [Added] - Add `returnKeyAction` prop to `TextInput` component [General] [Deprecated] - Remove usages of `blurOnSubmit` in native code and convert `blurOnSubmit` to `returnKeyAction` in the JavaScript conversion layer Pull Request resolved: https://github.com/facebook/react-native/pull/33653 Test Plan: Verified old usages of combinations of `blurOnSubmit` and `multiline` matched previous behavior and that the new `returnKeyAction` prop behaves as expected. | Android | iOS | | --- | -- | | ![android-returnkeyaction-test](https://user-images.githubusercontent.com/22553678/163597864-2e306f98-7b6e-4ddf-8a35-625d397d3dce.gif) | ![ios-returnkeyaction-test](https://user-images.githubusercontent.com/22553678/163598407-9e059f74-3549-4b46-8e03-c19bfaa6dd3d.gif) | With the changes, the TODO list example from before now looks like this: ![multiline-no-momentary-blur](https://user-images.githubusercontent.com/22553678/163598810-f3a71d62-5514-486e-bf6a-79169fe86378.gif) Reviewed By: yungsters Differential Revision: D35735249 Pulled By: makovkastar fbshipit-source-id: 1f2237a2a5e11dd141165d7568c91c9824bd6f25 --- .../AndroidTextInputNativeComponent.js | 29 +++++- .../TextInput/RCTTextInputViewConfig.js | 2 +- Libraries/Components/TextInput/TextInput.js | 77 +++++++++++++--- .../__snapshots__/TextInput-test.js.snap | 4 +- .../Multiline/RCTMultilineTextInputView.m | 3 - .../TextInput/RCTBackedTextInputDelegate.h | 4 +- .../RCTBackedTextInputDelegateAdapter.m | 8 +- .../Text/TextInput/RCTBaseTextInputView.h | 2 +- .../Text/TextInput/RCTBaseTextInputView.m | 31 ++++--- .../TextInput/RCTBaseTextInputViewManager.m | 2 +- .../Singleline/RCTSinglelineTextInputView.m | 4 +- .../TextInput/RCTTextInputComponentView.mm | 28 ++++-- .../react/tests/TextInputTestCase.java | 10 +-- .../react/views/textinput/ReactEditText.java | 54 ++++++++--- .../textinput/ReactTextInputManager.java | 44 ++++----- .../textinput/ReactTextInputPropertyTest.java | 2 +- .../AndroidTextInputProps.cpp | 10 +-- .../androidtextinput/AndroidTextInputProps.h | 2 +- .../textinput/iostextinput/conversions.h | 20 +++++ .../textinput/iostextinput/primitives.h | 12 ++- .../textinput/iostextinput/propsConversions.h | 8 +- .../TextInput/TextInputSharedExamples.js | 90 +++++++++++++++++++ 22 files changed, 351 insertions(+), 95 deletions(-) diff --git a/Libraries/Components/TextInput/AndroidTextInputNativeComponent.js b/Libraries/Components/TextInput/AndroidTextInputNativeComponent.js index e896a77f810f..e12b1ad054c5 100644 --- a/Libraries/Components/TextInput/AndroidTextInputNativeComponent.js +++ b/Libraries/Components/TextInput/AndroidTextInputNativeComponent.js @@ -66,6 +66,8 @@ export type ReturnKeyType = | 'route' | 'yahoo'; +export type SubmitBehavior = 'submit' | 'blurAndSubmit' | 'newline'; + export type NativeProps = $ReadOnly<{| // This allows us to inherit everything from ViewProps except for style (see below) // This must be commented for Fabric codegen to work. @@ -520,9 +522,34 @@ export type NativeProps = $ReadOnly<{| * multiline fields. Note that for multiline fields, setting `blurOnSubmit` * to `true` means that pressing return will blur the field and trigger the * `onSubmitEditing` event instead of inserting a newline into the field. + * + * @deprecated + * Note that `submitBehavior` now takes the place of `blurOnSubmit` and will + * override any behavior defined by `blurOnSubmit`. + * @see submitBehavior */ blurOnSubmit?: ?boolean, + /** + * When the return key is pressed, + * + * For single line inputs: + * + * - `'newline`' defaults to `'blurAndSubmit'` + * - `undefined` defaults to `'blurAndSubmit'` + * + * For multiline inputs: + * + * - `'newline'` adds a newline + * - `undefined` defaults to `'newline'` + * + * For both single line and multiline inputs: + * + * - `'submit'` will only send a submit event and not blur the input + * - `'blurAndSubmit`' will both blur the input and send a submit event + */ + submitBehavior?: ?SubmitBehavior, + /** * Note that not all Text styles are supported, an incomplete list of what is not supported includes: * @@ -657,7 +684,7 @@ export const __INTERNAL_VIEW_CONFIG: PartialViewConfig = { process: require('../../StyleSheet/processColor'), }, textDecorationLine: true, - blurOnSubmit: true, + submitBehavior: true, textAlignVertical: true, fontStyle: true, textShadowOffset: true, diff --git a/Libraries/Components/TextInput/RCTTextInputViewConfig.js b/Libraries/Components/TextInput/RCTTextInputViewConfig.js index 52134db4419f..68ee77143d1b 100644 --- a/Libraries/Components/TextInput/RCTTextInputViewConfig.js +++ b/Libraries/Components/TextInput/RCTTextInputViewConfig.js @@ -128,7 +128,7 @@ const RCTTextInputViewConfig = { keyboardType: true, selection: true, returnKeyType: true, - blurOnSubmit: true, + submitBehavior: true, mostRecentEventCount: true, scrollEnabled: true, selectionColor: {process: require('../../StyleSheet/processColor')}, diff --git a/Libraries/Components/TextInput/TextInput.js b/Libraries/Components/TextInput/TextInput.js index 8fa117192fa0..8e3296f5d2cf 100644 --- a/Libraries/Components/TextInput/TextInput.js +++ b/Libraries/Components/TextInput/TextInput.js @@ -173,6 +173,8 @@ export type ReturnKeyType = | 'route' | 'yahoo'; +export type SubmitBehavior = 'submit' | 'blurAndSubmit' | 'newline'; + export type AutoCapitalize = 'none' | 'sentences' | 'words' | 'characters'; export type TextContentType = @@ -502,15 +504,6 @@ export type Props = $ReadOnly<{| */ allowFontScaling?: ?boolean, - /** - * If `true`, the text field will blur when submitted. - * The default value is true for single-line fields and false for - * multiline fields. Note that for multiline fields, setting `blurOnSubmit` - * to `true` means that pressing return will blur the field and trigger the - * `onSubmitEditing` event instead of inserting a newline into the field. - */ - blurOnSubmit?: ?boolean, - /** * If `true`, caret is hidden. The default value is `false`. * @@ -775,6 +768,40 @@ export type Props = $ReadOnly<{| */ selectTextOnFocus?: ?boolean, + /** + * If `true`, the text field will blur when submitted. + * The default value is true for single-line fields and false for + * multiline fields. Note that for multiline fields, setting `blurOnSubmit` + * to `true` means that pressing return will blur the field and trigger the + * `onSubmitEditing` event instead of inserting a newline into the field. + * + * @deprecated + * Note that `submitBehavior` now takes the place of `blurOnSubmit` and will + * override any behavior defined by `blurOnSubmit`. + * @see submitBehavior + */ + blurOnSubmit?: ?boolean, + + /** + * When the return key is pressed, + * + * For single line inputs: + * + * - `'newline`' defaults to `'blurAndSubmit'` + * - `undefined` defaults to `'blurAndSubmit'` + * + * For multiline inputs: + * + * - `'newline'` adds a newline + * - `undefined` defaults to `'newline'` + * + * For both single line and multiline inputs: + * + * - `'submit'` will only send a submit event and not blur the input + * - `'blurAndSubmit`' will both blur the input and send a submit event + */ + submitBehavior?: ?SubmitBehavior, + /** * Note that not all Text styles are supported, an incomplete list of what is not supported includes: * @@ -1185,9 +1212,31 @@ function InternalTextInput(props: Props): React.Node { let textInput = null; - // The default value for `blurOnSubmit` is true for single-line fields and - // false for multi-line fields. - const blurOnSubmit = props.blurOnSubmit ?? !props.multiline; + const multiline = props.multiline ?? false; + + let submitBehavior: SubmitBehavior; + if (props.submitBehavior != null) { + // `submitBehavior` is set explicitly + if (!multiline && props.submitBehavior === 'newline') { + // For single line text inputs, `'newline'` is not a valid option + submitBehavior = 'blurAndSubmit'; + } else { + submitBehavior = props.submitBehavior; + } + } else if (multiline) { + if (props.blurOnSubmit === true) { + submitBehavior = 'blurAndSubmit'; + } else { + submitBehavior = 'newline'; + } + } else { + // Single line + if (props.blurOnSubmit !== false) { + submitBehavior = 'blurAndSubmit'; + } else { + submitBehavior = 'submit'; + } + } const accessible = props.accessible !== false; const focusable = props.focusable !== false; @@ -1246,7 +1295,7 @@ function InternalTextInput(props: Props): React.Node { {...props} {...eventHandlers} accessible={accessible} - blurOnSubmit={blurOnSubmit} + submitBehavior={submitBehavior} caretHidden={caretHidden} dataDetectorTypes={props.dataDetectorTypes} focusable={focusable} @@ -1294,7 +1343,7 @@ function InternalTextInput(props: Props): React.Node { {...eventHandlers} accessible={accessible} autoCapitalize={autoCapitalize} - blurOnSubmit={blurOnSubmit} + submitBehavior={submitBehavior} caretHidden={caretHidden} children={children} disableFullscreenUI={props.disableFullscreenUI} diff --git a/Libraries/Components/TextInput/__tests__/__snapshots__/TextInput-test.js.snap b/Libraries/Components/TextInput/__tests__/__snapshots__/TextInput-test.js.snap index 874fae2b158a..d83ac32fe9bf 100644 --- a/Libraries/Components/TextInput/__tests__/__snapshots__/TextInput-test.js.snap +++ b/Libraries/Components/TextInput/__tests__/__snapshots__/TextInput-test.js.snap @@ -4,7 +4,6 @@ exports[`TextInput tests should render as expected: should deep render when mock @@ -33,7 +33,6 @@ exports[`TextInput tests should render as expected: should deep render when not diff --git a/Libraries/Text/TextInput/Multiline/RCTMultilineTextInputView.m b/Libraries/Text/TextInput/Multiline/RCTMultilineTextInputView.m index 0cbaea87b42c..51d70e0c684c 100644 --- a/Libraries/Text/TextInput/Multiline/RCTMultilineTextInputView.m +++ b/Libraries/Text/TextInput/Multiline/RCTMultilineTextInputView.m @@ -19,9 +19,6 @@ @implementation RCTMultilineTextInputView - (instancetype)initWithBridge:(RCTBridge *)bridge { if (self = [super initWithBridge:bridge]) { - // `blurOnSubmit` defaults to `false` for by design. - self.blurOnSubmit = NO; - _backedTextInputView = [[RCTUITextView alloc] initWithFrame:self.bounds]; _backedTextInputView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; _backedTextInputView.textInputDelegate = self; diff --git a/Libraries/Text/TextInput/RCTBackedTextInputDelegate.h b/Libraries/Text/TextInput/RCTBackedTextInputDelegate.h index c2a4362f028b..0f073dce9921 100644 --- a/Libraries/Text/TextInput/RCTBackedTextInputDelegate.h +++ b/Libraries/Text/TextInput/RCTBackedTextInputDelegate.h @@ -19,9 +19,11 @@ NS_ASSUME_NONNULL_BEGIN - (BOOL)textInputShouldEndEditing; // Return `YES` to allow editing to stop and to resign first responder status. `NO` to disallow the editing session to end. - (void)textInputDidEndEditing; // May be called if forced even if `textInputShouldEndEditing` returns `NO` (e.g. view removed from window) or `[textInput endEditing:YES]` called. -- (BOOL)textInputShouldReturn; // May be called right before `textInputShouldEndEditing` if "Return" button was pressed. +- (BOOL)textInputShouldReturn; // May be called right before `textInputShouldEndEditing` if "Return" button was pressed. Dismisses keyboard if true - (void)textInputDidReturn; +- (BOOL)textInputShouldSubmitOnReturn; // Checks whether to submit when return is pressed and emits an event if true. + /* * Called before any change in the TextInput. The delegate has the opportunity to change the replacement string or reject the change completely. * To change the replacement, return the changed version of the `text`. diff --git a/Libraries/Text/TextInput/RCTBackedTextInputDelegateAdapter.m b/Libraries/Text/TextInput/RCTBackedTextInputDelegateAdapter.m index c6c254ce5dbe..f46fa1232417 100644 --- a/Libraries/Text/TextInput/RCTBackedTextInputDelegateAdapter.m +++ b/Libraries/Text/TextInput/RCTBackedTextInputDelegateAdapter.m @@ -100,6 +100,8 @@ - (BOOL)textField:(__unused UITextField *)textField shouldChangeCharactersInRang - (BOOL)textFieldShouldReturn:(__unused UITextField *)textField { + // Ignore the value of whether we submitted; just make sure the submit event is called if necessary. + [_backedTextInputView.textInputDelegate textInputShouldSubmitOnReturn]; return [_backedTextInputView.textInputDelegate textInputShouldReturn]; } @@ -209,10 +211,14 @@ - (BOOL)textView:(__unused UITextView *)textView shouldChangeTextInRange:(NSRang { // Custom implementation of `textInputShouldReturn` and `textInputDidReturn` pair for `UITextView`. if (!_backedTextInputView.textWasPasted && [text isEqualToString:@"\n"]) { - if ([_backedTextInputView.textInputDelegate textInputShouldReturn]) { + const BOOL shouldSubmit = [_backedTextInputView.textInputDelegate textInputShouldSubmitOnReturn]; + const BOOL shouldReturn = [_backedTextInputView.textInputDelegate textInputShouldReturn]; + if (shouldReturn) { [_backedTextInputView.textInputDelegate textInputDidReturn]; [_backedTextInputView endEditing:NO]; return NO; + } else if (shouldSubmit) { + return NO; } } diff --git a/Libraries/Text/TextInput/RCTBaseTextInputView.h b/Libraries/Text/TextInput/RCTBaseTextInputView.h index 5c6c5cfcfa4b..967101da6244 100644 --- a/Libraries/Text/TextInput/RCTBaseTextInputView.h +++ b/Libraries/Text/TextInput/RCTBaseTextInputView.h @@ -42,7 +42,7 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, assign) NSInteger mostRecentEventCount; @property (nonatomic, assign, readonly) NSInteger nativeEventCount; @property (nonatomic, assign) BOOL autoFocus; -@property (nonatomic, assign) BOOL blurOnSubmit; +@property (nonatomic, copy) NSString *submitBehavior; @property (nonatomic, assign) BOOL selectTextOnFocus; @property (nonatomic, assign) BOOL clearTextOnFocus; @property (nonatomic, assign) BOOL secureTextEntry; diff --git a/Libraries/Text/TextInput/RCTBaseTextInputView.m b/Libraries/Text/TextInput/RCTBaseTextInputView.m index a4924923f190..c719b5628917 100644 --- a/Libraries/Text/TextInput/RCTBaseTextInputView.m +++ b/Libraries/Text/TextInput/RCTBaseTextInputView.m @@ -350,20 +350,27 @@ - (void)textInputDidEndEditing eventCount:_nativeEventCount]; } +- (BOOL)textInputShouldSubmitOnReturn +{ + const BOOL shouldSubmit = [_submitBehavior isEqualToString:@"blurAndSubmit"] || [_submitBehavior isEqualToString:@"submit"]; + if (shouldSubmit) { + // We send `submit` event here, in `textInputShouldSubmit` + // (not in `textInputDidReturn)`, because of semantic of the event: + // `onSubmitEditing` is called when "Submit" button + // (the blue key on onscreen keyboard) did pressed + // (no connection to any specific "submitting" process). + [_eventDispatcher sendTextEventWithType:RCTTextEventTypeSubmit + reactTag:self.reactTag + text:[self.backedTextInputView.attributedText.string copy] + key:nil + eventCount:_nativeEventCount]; + } + return shouldSubmit; +} + - (BOOL)textInputShouldReturn { - // We send `submit` event here, in `textInputShouldReturn` - // (not in `textInputDidReturn)`, because of semantic of the event: - // `onSubmitEditing` is called when "Submit" button - // (the blue key on onscreen keyboard) did pressed - // (no connection to any specific "submitting" process). - [_eventDispatcher sendTextEventWithType:RCTTextEventTypeSubmit - reactTag:self.reactTag - text:[self.backedTextInputView.attributedText.string copy] - key:nil - eventCount:_nativeEventCount]; - - return _blurOnSubmit; + return [_submitBehavior isEqualToString:@"blurAndSubmit"]; } - (void)textInputDidReturn diff --git a/Libraries/Text/TextInput/RCTBaseTextInputViewManager.m b/Libraries/Text/TextInput/RCTBaseTextInputViewManager.m index b1ecf854330b..fc59b088fe67 100644 --- a/Libraries/Text/TextInput/RCTBaseTextInputViewManager.m +++ b/Libraries/Text/TextInput/RCTBaseTextInputViewManager.m @@ -49,7 +49,7 @@ @implementation RCTBaseTextInputViewManager RCT_REMAP_VIEW_PROPERTY(scrollEnabled, backedTextInputView.scrollEnabled, BOOL) RCT_REMAP_VIEW_PROPERTY(secureTextEntry, backedTextInputView.secureTextEntry, BOOL) RCT_EXPORT_VIEW_PROPERTY(autoFocus, BOOL) -RCT_EXPORT_VIEW_PROPERTY(blurOnSubmit, BOOL) +RCT_EXPORT_VIEW_PROPERTY(submitBehavior, NSString) RCT_EXPORT_VIEW_PROPERTY(clearTextOnFocus, BOOL) RCT_EXPORT_VIEW_PROPERTY(keyboardType, UIKeyboardType) RCT_EXPORT_VIEW_PROPERTY(showSoftInputOnFocus, BOOL) diff --git a/Libraries/Text/TextInput/Singleline/RCTSinglelineTextInputView.m b/Libraries/Text/TextInput/Singleline/RCTSinglelineTextInputView.m index 51feea12f866..f2d6ee4c8497 100644 --- a/Libraries/Text/TextInput/Singleline/RCTSinglelineTextInputView.m +++ b/Libraries/Text/TextInput/Singleline/RCTSinglelineTextInputView.m @@ -19,8 +19,8 @@ @implementation RCTSinglelineTextInputView - (instancetype)initWithBridge:(RCTBridge *)bridge { if (self = [super initWithBridge:bridge]) { - // `blurOnSubmit` defaults to `true` for by design. - self.blurOnSubmit = YES; + // `submitBehavior` defaults to `"blurAndSubmit"` for by design. + self.submitBehavior = @"blurAndSubmit"; _backedTextInputView = [[RCTUITextField alloc] initWithFrame:self.bounds]; _backedTextInputView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; diff --git a/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm b/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm index 3631fb45cbc1..c7c0f1d1a793 100644 --- a/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm +++ b/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm @@ -300,20 +300,25 @@ - (void)textInputDidEndEditing } } -- (BOOL)textInputShouldReturn +- (BOOL)textInputShouldSubmitOnReturn { - // We send `submit` event here, in `textInputShouldReturn` + const SubmitBehavior submitBehavior = [self getSubmitBehavior]; + const BOOL shouldSubmit = submitBehavior == SubmitBehavior::Submit || submitBehavior == SubmitBehavior::BlurAndSubmit; + // We send `submit` event here, in `textInputShouldSubmitOnReturn` // (not in `textInputDidReturn)`, because of semantic of the event: // `onSubmitEditing` is called when "Submit" button // (the blue key on onscreen keyboard) did pressed // (no connection to any specific "submitting" process). - if (_eventEmitter) { + if (_eventEmitter && shouldSubmit) { std::static_pointer_cast(_eventEmitter)->onSubmitEditing([self _textInputMetrics]); } + return shouldSubmit; +} - auto const &props = *std::static_pointer_cast(_props); - return props.traits.blurOnSubmit; +- (BOOL)textInputShouldReturn +{ + return [self getSubmitBehavior] == SubmitBehavior::BlurAndSubmit; } - (void)textInputDidReturn @@ -644,6 +649,19 @@ - (BOOL)_textOf:(NSAttributedString *)newText equals:(NSAttributedString *)oldTe } } +- (SubmitBehavior)getSubmitBehavior +{ + auto const &props = *std::static_pointer_cast(_props); + const SubmitBehavior submitBehaviorDefaultable = props.traits.submitBehavior; + + // We should always have a non-default `submitBehavior`, but in case we don't, set it based on multiline. + if (submitBehaviorDefaultable == SubmitBehavior::Default) { + return props.traits.multiline ? SubmitBehavior::Newline : SubmitBehavior::BlurAndSubmit; + } + + return submitBehaviorDefaultable; +} + @end Class RCTTextInputCls(void) diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/tests/TextInputTestCase.java b/ReactAndroid/src/androidTest/java/com/facebook/react/tests/TextInputTestCase.java index b4b3aaa7b4b5..f58bd22b301b 100644 --- a/ReactAndroid/src/androidTest/java/com/facebook/react/tests/TextInputTestCase.java +++ b/ReactAndroid/src/androidTest/java/com/facebook/react/tests/TextInputTestCase.java @@ -232,12 +232,12 @@ public void run() { private void fireEditorActionAndCheckRecording( final ReactEditText reactEditText, final int actionId) throws Throwable { - fireEditorActionAndCheckRecording(reactEditText, actionId, true); - fireEditorActionAndCheckRecording(reactEditText, actionId, false); + fireEditorActionAndCheckRecording(reactEditText, actionId, "blurAndSubmit"); + fireEditorActionAndCheckRecording(reactEditText, actionId, "newline"); } private void fireEditorActionAndCheckRecording( - final ReactEditText reactEditText, final int actionId, final boolean blurOnSubmit) + final ReactEditText reactEditText, final int actionId, final String submitBehavior) throws Throwable { mRecordingModule.reset(); @@ -246,14 +246,14 @@ private void fireEditorActionAndCheckRecording( @Override public void run() { reactEditText.requestFocusFromJS(); - reactEditText.setBlurOnSubmit(blurOnSubmit); + reactEditText.setSubmitBehavior(submitBehavior); reactEditText.onEditorAction(actionId); } }); waitForBridgeAndUIIdle(); assertEquals(1, mRecordingModule.getCalls().size()); - assertEquals(!blurOnSubmit, reactEditText.isFocused()); + assertEquals(!submitBehavior.equals("blurAndSubmit"), reactEditText.isFocused()); } /** diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java index 4847b9b5d86e..14863e498018 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java @@ -95,7 +95,7 @@ public class ReactEditText extends AppCompatEditText private @Nullable TextWatcherDelegator mTextWatcherDelegator; private int mStagedInputType; protected boolean mContainsImages; - private @Nullable Boolean mBlurOnSubmit; + private @Nullable String mSubmitBehavior = null; private boolean mDisableFullscreen; private @Nullable String mReturnKeyType; private @Nullable SelectionWatcher mSelectionWatcher; @@ -135,7 +135,6 @@ public ReactEditText(Context context) { mDefaultGravityVertical = getGravity() & Gravity.VERTICAL_GRAVITY_MASK; mNativeEventCount = 0; mIsSettingTextFromJS = false; - mBlurOnSubmit = null; mDisableFullscreen = false; mListeners = null; mTextWatcherDelegator = null; @@ -256,7 +255,7 @@ public InputConnection onCreateInputConnection(EditorInfo outAttrs) { inputConnection, reactContext, this, mEventDispatcher); } - if (isMultiline() && getBlurOnSubmit()) { + if (isMultiline() && (shouldBlurOnReturn() || shouldSubmitOnReturn())) { // Remove IME_FLAG_NO_ENTER_ACTION to keep the original IME_OPTION outAttrs.imeOptions &= ~EditorInfo.IME_FLAG_NO_ENTER_ACTION; } @@ -380,21 +379,52 @@ public void setSelectionWatcher(SelectionWatcher selectionWatcher) { mSelectionWatcher = selectionWatcher; } - public void setBlurOnSubmit(@Nullable Boolean blurOnSubmit) { - mBlurOnSubmit = blurOnSubmit; - } - public void setOnKeyPress(boolean onKeyPress) { mOnKeyPress = onKeyPress; } - public boolean getBlurOnSubmit() { - if (mBlurOnSubmit == null) { - // Default blurOnSubmit - return isMultiline() ? false : true; + public boolean shouldBlurOnReturn() { + String submitBehavior = getSubmitBehavior(); + boolean shouldBlur; + + // Default shouldBlur + if (submitBehavior == null) { + if (!isMultiline()) { + shouldBlur = true; + } else { + shouldBlur = false; + } + } else { + shouldBlur = submitBehavior.equals("blurAndSubmit"); + } + + return shouldBlur; + } + + public boolean shouldSubmitOnReturn() { + String submitBehavior = getSubmitBehavior(); + boolean shouldSubmit; + + // Default shouldSubmit + if (submitBehavior == null) { + if (!isMultiline()) { + shouldSubmit = true; + } else { + shouldSubmit = false; + } + } else { + shouldSubmit = submitBehavior.equals("submit") || submitBehavior.equals("blurAndSubmit"); } - return mBlurOnSubmit; + return shouldSubmit; + } + + public String getSubmitBehavior() { + return mSubmitBehavior; + } + + public void setSubmitBehavior(String submitBehavior) { + mSubmitBehavior = submitBehavior; } public void setDisableFullscreenUI(boolean disableFullscreenUI) { diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java index f3134f9cb1dc..aac043da34f2 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java @@ -441,9 +441,9 @@ public void setOnSelectionChange(final ReactEditText view, boolean onSelectionCh } } - @ReactProp(name = "blurOnSubmit") - public void setBlurOnSubmit(ReactEditText view, @Nullable Boolean blurOnSubmit) { - view.setBlurOnSubmit(blurOnSubmit); + @ReactProp(name = "submitBehavior") + public void setSubmitBehavior(ReactEditText view, @Nullable String submitBehavior) { + view.setSubmitBehavior(submitBehavior); } @ReactProp(name = "onContentSizeChange", defaultBoolean = false) @@ -1077,36 +1077,38 @@ public void onFocusChange(View v, boolean hasFocus) { @Override public boolean onEditorAction(TextView v, int actionId, KeyEvent keyEvent) { if ((actionId & EditorInfo.IME_MASK_ACTION) != 0 || actionId == EditorInfo.IME_NULL) { - boolean blurOnSubmit = editText.getBlurOnSubmit(); boolean isMultiline = editText.isMultiline(); + boolean shouldSubmit = editText.shouldSubmitOnReturn(); + boolean shouldBlur = editText.shouldBlurOnReturn(); + // Motivation: - // * blurOnSubmit && isMultiline => Clear focus; prevent default behaviour (return - // true); - // * blurOnSubmit && !isMultiline => Clear focus; prevent default behaviour (return + // * shouldSubmit => Clear focus; prevent default behavior (return true); + // * shouldBlur => Submit; prevent default behavior (return true); + // * !shouldBlur && !shouldSubmit && isMultiline => Perform default behavior (return + // false); + // * !shouldBlur && !shouldSubmit && !isMultiline => Prevent default behavior (return // true); - // * !blurOnSubmit && isMultiline => Perform default behaviour (return false); - // * !blurOnSubmit && !isMultiline => Prevent default behaviour (return true). - // Additionally we always generate a `submit` event. - - EventDispatcher eventDispatcher = getEventDispatcher(reactContext, editText); - eventDispatcher.dispatchEvent( - new ReactTextInputSubmitEditingEvent( - reactContext.getSurfaceId(), - editText.getId(), - editText.getText().toString())); + if (shouldSubmit) { + EventDispatcher eventDispatcher = getEventDispatcher(reactContext, editText); + eventDispatcher.dispatchEvent( + new ReactTextInputSubmitEditingEvent( + reactContext.getSurfaceId(), + editText.getId(), + editText.getText().toString())); + } - if (blurOnSubmit) { + if (shouldBlur) { editText.clearFocus(); } // Prevent default behavior except when we want it to insert a newline. - if (blurOnSubmit || !isMultiline) { + if (shouldBlur || shouldSubmit || !isMultiline) { return true; } - // If we've reached this point, it means that the TextInput has 'blurOnSubmit' set to - // false and 'multiline' set to true. But it's still possible to get IME_ACTION_NEXT + // If we've reached this point, it means that the TextInput has 'submitBehavior' set + // nullish and 'multiline' set to true. But it's still possible to get IME_ACTION_NEXT // and IME_ACTION_PREVIOUS here in case if 'disableFullscreenUI' is false and Android // decides to render this EditText in the full screen mode (when a phone has the // landscape orientation for example). The full screen EditText also renders an action diff --git a/ReactAndroid/src/test/java/com/facebook/react/views/textinput/ReactTextInputPropertyTest.java b/ReactAndroid/src/test/java/com/facebook/react/views/textinput/ReactTextInputPropertyTest.java index a817b810d416..edf798ab86e2 100644 --- a/ReactAndroid/src/test/java/com/facebook/react/views/textinput/ReactTextInputPropertyTest.java +++ b/ReactAndroid/src/test/java/com/facebook/react/views/textinput/ReactTextInputPropertyTest.java @@ -194,7 +194,7 @@ public void testBlurMultiline() { ReactEditText view = mManager.createViewInstance(mThemedContext); mManager.updateProperties(view, buildStyles("multiline", true)); - mManager.updateProperties(view, buildStyles("blurOnSubmit", true)); + mManager.updateProperties(view, buildStyles("submitBehavior", "blurAndSubmit")); EditorInfo editorInfo = new EditorInfo(); editorInfo.imeOptions = EditorInfo.IME_ACTION_DONE | EditorInfo.IME_FLAG_NO_ENTER_ACTION; diff --git a/ReactCommon/react/renderer/components/textinput/androidtextinput/react/renderer/components/androidtextinput/AndroidTextInputProps.cpp b/ReactCommon/react/renderer/components/textinput/androidtextinput/react/renderer/components/androidtextinput/AndroidTextInputProps.cpp index becfec590be7..b3950b9eacb5 100644 --- a/ReactCommon/react/renderer/components/textinput/androidtextinput/react/renderer/components/androidtextinput/AndroidTextInputProps.cpp +++ b/ReactCommon/react/renderer/components/textinput/androidtextinput/react/renderer/components/androidtextinput/AndroidTextInputProps.cpp @@ -145,10 +145,10 @@ AndroidTextInputProps::AndroidTextInputProps( "selectTextOnFocus", sourceProps.selectTextOnFocus, {false})), - blurOnSubmit(convertRawProp(context, rawProps, - "blurOnSubmit", - sourceProps.blurOnSubmit, - {false})), + submitBehavior(convertRawProp(context, rawProps, + "submitBehavior", + sourceProps.submitBehavior, + {})), caretHidden(convertRawProp(context, rawProps, "caretHidden", sourceProps.caretHidden, @@ -298,7 +298,7 @@ folly::dynamic AndroidTextInputProps::getDynamic() const { props["value"] = value; props["defaultValue"] = defaultValue; props["selectTextOnFocus"] = selectTextOnFocus; - props["blurOnSubmit"] = blurOnSubmit; + props["submitBehavior"] = submitBehavior; props["caretHidden"] = caretHidden; props["contextMenuHidden"] = contextMenuHidden; props["textShadowColor"] = toAndroidRepr(textShadowColor); diff --git a/ReactCommon/react/renderer/components/textinput/androidtextinput/react/renderer/components/androidtextinput/AndroidTextInputProps.h b/ReactCommon/react/renderer/components/textinput/androidtextinput/react/renderer/components/androidtextinput/AndroidTextInputProps.h index 6843425b1901..e487bddd34ac 100644 --- a/ReactCommon/react/renderer/components/textinput/androidtextinput/react/renderer/components/androidtextinput/AndroidTextInputProps.h +++ b/ReactCommon/react/renderer/components/textinput/androidtextinput/react/renderer/components/androidtextinput/AndroidTextInputProps.h @@ -143,7 +143,7 @@ class AndroidTextInputProps final : public ViewProps, public BaseTextProps { const std::string value{}; const std::string defaultValue{}; const bool selectTextOnFocus{false}; - const bool blurOnSubmit{false}; + const std::string submitBehavior{}; const bool caretHidden{false}; const bool contextMenuHidden{false}; const SharedColor textShadowColor{}; diff --git a/ReactCommon/react/renderer/components/textinput/iostextinput/conversions.h b/ReactCommon/react/renderer/components/textinput/iostextinput/conversions.h index 98e44fd7c070..f8b16d24addb 100644 --- a/ReactCommon/react/renderer/components/textinput/iostextinput/conversions.h +++ b/ReactCommon/react/renderer/components/textinput/iostextinput/conversions.h @@ -126,6 +126,26 @@ inline void fromRawValue( abort(); } +inline void fromRawValue( + const PropsParserContext &context, + const RawValue &value, + SubmitBehavior &result) { + auto string = (std::string)value; + if (string == "newline") { + result = SubmitBehavior::Newline; + return; + } + if (string == "submit") { + result = SubmitBehavior::Submit; + return; + } + if (string == "blurAndSubmit") { + result = SubmitBehavior::BlurAndSubmit; + return; + } + abort(); +} + inline void fromRawValue( const PropsParserContext &context, const RawValue &value, diff --git a/ReactCommon/react/renderer/components/textinput/iostextinput/primitives.h b/ReactCommon/react/renderer/components/textinput/iostextinput/primitives.h index 1747a98bf4cd..bbb56d26d9a4 100644 --- a/ReactCommon/react/renderer/components/textinput/iostextinput/primitives.h +++ b/ReactCommon/react/renderer/components/textinput/iostextinput/primitives.h @@ -48,6 +48,14 @@ enum class ReturnKeyType { Continue, }; +// iOS & Android. +enum class SubmitBehavior { + Default, + Submit, + BlurAndSubmit, + Newline, +}; + // iOS-only enum class TextInputAccessoryVisibilityMode { Never, @@ -170,9 +178,9 @@ class TextInputTraits final { /* * iOS & Android - * Default value: `false`. + * Default value: `Default`. */ - bool blurOnSubmit{false}; + SubmitBehavior submitBehavior{SubmitBehavior::Default}; /* * iOS-only (implemented only on iOS for now) diff --git a/ReactCommon/react/renderer/components/textinput/iostextinput/propsConversions.h b/ReactCommon/react/renderer/components/textinput/iostextinput/propsConversions.h index 84c52eeace6c..15dc0004596d 100644 --- a/ReactCommon/react/renderer/components/textinput/iostextinput/propsConversions.h +++ b/ReactCommon/react/renderer/components/textinput/iostextinput/propsConversions.h @@ -93,12 +93,12 @@ static TextInputTraits convertRawProp( "secureTextEntry", sourceTraits.secureTextEntry, defaultTraits.secureTextEntry); - traits.blurOnSubmit = convertRawProp( + traits.submitBehavior = convertRawProp( context, rawProps, - "blurOnSubmit", - sourceTraits.blurOnSubmit, - defaultTraits.blurOnSubmit); + "submitBehavior", + sourceTraits.submitBehavior, + defaultTraits.submitBehavior); traits.clearTextOnFocus = convertRawProp( context, rawProps, diff --git a/packages/rn-tester/js/examples/TextInput/TextInputSharedExamples.js b/packages/rn-tester/js/examples/TextInput/TextInputSharedExamples.js index 2e9a4d754dcb..9b8e62126e5d 100644 --- a/packages/rn-tester/js/examples/TextInput/TextInputSharedExamples.js +++ b/packages/rn-tester/js/examples/TextInput/TextInputSharedExamples.js @@ -248,6 +248,90 @@ class BlurOnSubmitExample extends React.Component<{...}> { } } +class SubmitBehaviorExample extends React.Component<{...}> { + ref1 = React.createRef(); + ref2 = React.createRef(); + ref3 = React.createRef(); + ref4 = React.createRef(); + ref5 = React.createRef(); + ref6 = React.createRef(); + ref7 = React.createRef(); + ref8 = React.createRef(); + ref9 = React.createRef(); + ref10 = React.createRef(); + ref11 = React.createRef(); + + render() { + return ( + + this.ref2.current?.focus()} + /> + this.ref3.current?.focus()} + /> + this.ref4.current?.focus()} + /> + this.ref5.current?.focus()} + /> + this.ref6.current?.focus()} + /> + this.ref7.current?.focus()} + /> + this.ref8.current?.focus()} + /> + this.ref9.current?.focus()} + /> + + + + + ); + } +} + class TextEventsExample extends React.Component<{...}, $FlowFixMeState> { state = { curText: '', @@ -620,6 +704,12 @@ module.exports = ([ return ; }, }, + { + title: 'Submit behavior', + render: function (): React.Element { + return ; + }, + }, { title: 'Event handling', render: function (): React.Element { From ee4ce2df2f57b07e523bfb4d4728543d73b5a009 Mon Sep 17 00:00:00 2001 From: Chatura Atapattu Date: Fri, 22 Jul 2022 15:19:12 -0700 Subject: [PATCH 0044/1165] Use an SDKRoot based Foundation framework Summary: When building `igios-no-extensions` with buck2 on linux, we the following analysis error: ``` When running analysis for `fbsource//fbobjc/Apps/Instagram/Instagram:InstagramNoExtensions (fbsource//tools/build_defs/config/platform/apple:Instagram-125ae32099392ce8)` Caused by: 0: When running analysis for `fbsource//fbobjc/Apps/Instagram/Instagram:InstagramARVRFrameworkDylibFramework (fbsource//tools/build_defs/config/platform/apple:Instagram-125ae32099392ce8)` 1: When running analysis for `fbsource//fbobjc/Apps/Instagram/Instagram:InstagramDependencyPoolForLinkGroupsFramework (fbsource//tools/build_defs/config/platform/apple:Instagram-125ae32099392ce8)` 2: When running analysis for `fbsource//fbobjc/Libraries/FBReactKit:RCTNetInfo (fbsource//tools/build_defs/config/platform/apple:Instagram-125ae32099392ce8)` 3: When running analysis for `fbsource//xplat/js/RKJSModules/Libraries/NetInfo:FBReactNativeNetInfoSpecApple (fbsource//tools/build_defs/config/platform/apple:Instagram-125ae32099392ce8)` 4: When running analysis for `fbsource//xplat/js/react-native-github:RCTTypeSafety (fbsource//tools/build_defs/config/platform/apple:Instagram-125ae32099392ce8)` 5: Traceback (most recent call last): * fbcode/buck2/prelude/apple/apple_library.bzl:48, in constructor_params, swift_providers = apple_library_rule_constructor_params_a... * fbcode/buck2/prelude/apple/apple_library.bzl:111, in apple_library_rule_constructor_params_and_swift_providers args = [cmd_args(get_framework_search_path_flags(ctx))], * fbcode/buck2/prelude/apple/apple_frameworks.bzl:46, in get_framework_search_path_flags return _get_framework_search_path_flags(_get_non_sdk_framework_directories(ct... * fbcode/buck2/prelude/apple/apple_frameworks.bzl:59, in _get_non_sdk_framework_directories return dedupe(filter(None, [_non_sdk_framework_directory(ctx, x) for x in fra... * fbcode/buck2/prelude/apple/apple_frameworks.bzl:95, in _non_sdk_framework_directory expanded_framework_path = _expand_sdk_framework_path(ctx, framework_path) * fbcode/buck2/prelude/apple/apple_frameworks.bzl:81, in _expand_sdk_framework_path expanded_path = expanded_path.replace(path_variable, path_value) error: Type of parameter `new` doesn't match, expected `str`, actual `artifact` --> fbcode/buck2/prelude/apple/apple_frameworks.bzl:81:25 | 81 | expanded_path = expanded_path.replace(path_variable, path_value) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ``` This is related to running on Linux with buck2 and how we get the framework paths for linux/pika toolchains for non SDK frameworks. However, Foundation is an SDK framework, and updating it to be as such allows us to build, both with buck1 and buck2. Differential Revision: D38080376 fbshipit-source-id: b226c3511e3312d0bf0ddb792dbe4ca99768cad1 --- BUCK | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BUCK b/BUCK index 7780ff8e1f66..d9ee7b3fc65c 100644 --- a/BUCK +++ b/BUCK @@ -600,7 +600,7 @@ rn_apple_library( contacts = ["oncall+react_native@xmail.facebook.com"], extension_api_only = True, frameworks = [ - "$PLATFORM_DIR/Developer/Library/Frameworks/Foundation.framework", + "Foundation", ], inherited_buck_flags = get_static_library_ios_flags(), labels = [ From 000bbe8013ec72d20f969c5c3a1f655b3f20c6ba Mon Sep 17 00:00:00 2001 From: Robbie Coomber Date: Fri, 22 Jul 2022 15:41:32 -0700 Subject: [PATCH 0045/1165] Add support for "preferred" AlertButton (#32538) Summary: Currently, with the Alert API on iOS, the only way to bold one of the buttons is by setting the style to "cancel". This has the side-effect of moving it to the left. The underlying UIKit API has a way of setting a "preferred" button, which does not have this negative side-effect, so this PR wires this up. See preferredAction on UIAlertController https://developer.apple.com/documentation/uikit/uialertcontroller/ Docs PR: https://github.com/facebook/react-native-website/pull/2839 ## Changelog [iOS] [Added] - Support setting an Alert button as "preferred", to emphasize it without needing to set it as a "cancel" button. Pull Request resolved: https://github.com/facebook/react-native/pull/32538 Test Plan: I ran the RNTesterPods app and added an example. It has a button styled with "preferred" and another with "cancel", to demonstrate that the "preferred" button takes emphasis over the "cancel" button. ![Simulator Screen Shot - iPhone 11 - 2021-11-04 at 09 48 35](https://user-images.githubusercontent.com/2056078/140292801-df880c43-c330-40df-b8e4-c1476c1645d6.png) Luna: * Also tested this on Catalyst {F754959632} Reviewed By: sammy-SC Differential Revision: D34357811 Pulled By: lunaleaps fbshipit-source-id: 3d860702c49cb219f950904ae0b9fabef03b5588 --- Libraries/Alert/Alert.js | 5 ++ Libraries/Alert/NativeAlertManager.js | 1 + React/CoreModules/RCTAlertManager.mm | 58 +++++++------- .../js/examples/Alert/AlertExample.js | 76 +++++++++++++++---- .../js/examples/Alert/AlertIOSExample.js | 2 +- .../js/utils/RNTesterList.android.js | 2 +- 6 files changed, 103 insertions(+), 41 deletions(-) diff --git a/Libraries/Alert/Alert.js b/Libraries/Alert/Alert.js index 1a943e1bbd7b..3e011e4cd727 100644 --- a/Libraries/Alert/Alert.js +++ b/Libraries/Alert/Alert.js @@ -22,6 +22,7 @@ export type AlertButtonStyle = 'default' | 'cancel' | 'destructive'; export type Buttons = Array<{ text?: string, onPress?: ?Function, + isPreferred?: boolean, style?: AlertButtonStyle, ... }>; @@ -126,6 +127,7 @@ class Alert { const buttons = []; let cancelButtonKey; let destructiveButtonKey; + let preferredButtonKey; if (typeof callbackOrButtons === 'function') { callbacks = [callbackOrButtons]; } else if (Array.isArray(callbackOrButtons)) { @@ -135,6 +137,8 @@ class Alert { cancelButtonKey = String(index); } else if (btn.style === 'destructive') { destructiveButtonKey = String(index); + } else if (btn.isPreferred) { + preferredButtonKey = String(index); } if (btn.text || index < (callbackOrButtons || []).length - 1) { const btnDef: {[number]: string} = {}; @@ -153,6 +157,7 @@ class Alert { defaultValue, cancelButtonKey, destructiveButtonKey, + preferredButtonKey, keyboardType, userInterfaceStyle: options?.userInterfaceStyle || undefined, }, diff --git a/Libraries/Alert/NativeAlertManager.js b/Libraries/Alert/NativeAlertManager.js index 9597ef155a52..65d815ec7962 100644 --- a/Libraries/Alert/NativeAlertManager.js +++ b/Libraries/Alert/NativeAlertManager.js @@ -19,6 +19,7 @@ export type Args = {| defaultValue?: string, cancelButtonKey?: string, destructiveButtonKey?: string, + preferredButtonKey?: string, keyboardType?: string, userInterfaceStyle?: string, |}; diff --git a/React/CoreModules/RCTAlertManager.mm b/React/CoreModules/RCTAlertManager.mm index 7480580d9865..532e898faf05 100644 --- a/React/CoreModules/RCTAlertManager.mm +++ b/React/CoreModules/RCTAlertManager.mm @@ -94,6 +94,7 @@ - (void)invalidate NSString *defaultValue = [RCTConvert NSString:args.defaultValue()]; NSString *cancelButtonKey = [RCTConvert NSString:args.cancelButtonKey()]; NSString *destructiveButtonKey = [RCTConvert NSString:args.destructiveButtonKey()]; + NSString *preferredButtonKey = [RCTConvert NSString:args.preferredButtonKey()]; UIKeyboardType keyboardType = [RCTConvert UIKeyboardType:args.keyboardType()]; if (!title && !message) { @@ -175,32 +176,37 @@ - (void)invalidate buttonStyle = UIAlertActionStyleDestructive; } __weak RCTAlertController *weakAlertController = alertController; - [alertController - addAction:[UIAlertAction - actionWithTitle:buttonTitle - style:buttonStyle - handler:^(__unused UIAlertAction *action) { - switch (type) { - case RCTAlertViewStylePlainTextInput: - case RCTAlertViewStyleSecureTextInput: - callback(@[ buttonKey, [weakAlertController.textFields.firstObject text] ]); - [weakAlertController hide]; - break; - case RCTAlertViewStyleLoginAndPasswordInput: { - NSDictionary *loginCredentials = @{ - @"login" : [weakAlertController.textFields.firstObject text], - @"password" : [weakAlertController.textFields.lastObject text] - }; - callback(@[ buttonKey, loginCredentials ]); - [weakAlertController hide]; - break; - } - case RCTAlertViewStyleDefault: - callback(@[ buttonKey ]); - [weakAlertController hide]; - break; - } - }]]; + + UIAlertAction *alertAction = + [UIAlertAction actionWithTitle:buttonTitle + style:buttonStyle + handler:^(__unused UIAlertAction *action) { + switch (type) { + case RCTAlertViewStylePlainTextInput: + case RCTAlertViewStyleSecureTextInput: + callback(@[ buttonKey, [weakAlertController.textFields.firstObject text] ]); + [weakAlertController hide]; + break; + case RCTAlertViewStyleLoginAndPasswordInput: { + NSDictionary *loginCredentials = @{ + @"login" : [weakAlertController.textFields.firstObject text], + @"password" : [weakAlertController.textFields.lastObject text] + }; + callback(@[ buttonKey, loginCredentials ]); + [weakAlertController hide]; + break; + } + case RCTAlertViewStyleDefault: + callback(@[ buttonKey ]); + [weakAlertController hide]; + break; + } + }]; + [alertController addAction:alertAction]; + + if ([buttonKey isEqualToString:preferredButtonKey]) { + [alertController setPreferredAction:alertAction]; + } } if (!_alertControllers) { diff --git a/packages/rn-tester/js/examples/Alert/AlertExample.js b/packages/rn-tester/js/examples/Alert/AlertExample.js index 4e22ba4b6c62..94f16e951115 100644 --- a/packages/rn-tester/js/examples/Alert/AlertExample.js +++ b/packages/rn-tester/js/examples/Alert/AlertExample.js @@ -5,13 +5,15 @@ * LICENSE file in the root directory of this source tree. * * @format + * @flow */ -import React, {useState} from 'react'; +import * as React from 'react'; +import type {RNTesterModule} from '../../types/RNTesterTypes'; import {Alert, StyleSheet, Text, TouchableHighlight, View} from 'react-native'; // Shows log on the screen -const Log = ({message}) => +const Log = ({message}: {message: string}) => message ? ( @@ -42,7 +44,7 @@ const AlertWithDefaultButton = () => { }; const AlertWithTwoButtons = () => { - const [message, setMessage] = useState(''); + const [message, setMessage] = React.useState(''); const alertMessage = 'Your subscription has expired!'; @@ -66,7 +68,7 @@ const AlertWithTwoButtons = () => { }; const AlertWithThreeButtons = () => { - const [message, setMessage] = useState(''); + const [message, setMessage] = React.useState(''); const alertMessage = 'Do you want to save your changes?'; @@ -92,7 +94,7 @@ const AlertWithThreeButtons = () => { }; const AlertWithManyButtons = () => { - const [message, setMessage] = useState(''); + const [message, setMessage] = React.useState(''); const alertMessage = 'Credibly reintermediate next-generation potentialities after goal-oriented ' + @@ -122,7 +124,7 @@ const AlertWithManyButtons = () => { }; const AlertWithCancelableTrue = () => { - const [message, setMessage] = useState(''); + const [message, setMessage] = React.useState(''); const alertMessage = 'Tapping outside this dialog will dismiss this alert.'; @@ -154,7 +156,7 @@ const AlertWithCancelableTrue = () => { }; const AlertWithStyles = () => { - const [message, setMessage] = useState(''); + const [message, setMessage] = React.useState(''); const alertMessage = 'Look at the button styles!'; @@ -190,6 +192,39 @@ const AlertWithStyles = () => { ); }; +const AlertWithStylesPreferred = () => { + const [message, setMessage] = React.useState(''); + + const alertMessage = + "The Preferred button is styled with 'preferred', so it is emphasized over the cancel button."; + + return ( + + + Alert.alert('Foo Title', alertMessage, [ + { + text: 'Preferred', + isPreferred: true, + onPress: () => setMessage('Preferred Pressed!'), + }, + { + text: 'Cancel', + style: 'cancel', + onPress: () => setMessage('Cancel Pressed!'), + }, + ]) + }> + + Tap to view alert + + + + + ); +}; + const styles = StyleSheet.create({ wrapper: { borderRadius: 5, @@ -208,12 +243,7 @@ const styles = StyleSheet.create({ }, }); -exports.title = 'Alerts'; -exports.description = - 'Alerts display a concise and informative message ' + - 'and prompt the user to make a decision.'; -exports.documentationURL = 'https://reactnative.dev/docs/alert'; -exports.examples = [ +export const examples = [ { title: 'Alert with default Button', description: @@ -262,4 +292,24 @@ exports.examples = [ return ; }, }, + { + title: 'Alert with styles + preferred', + platform: 'ios', + description: + "Alert buttons with 'isPreferred' will be emphasized, even over cancel buttons", + render(): React.Node { + return ; + }, + }, ]; + +export default ({ + framework: 'React', + title: 'Alerts', + category: 'UI', + documentationURL: 'https://reactnative.dev/docs/alert', + description: + 'Alerts display a concise and informative messageand prompt the user to make a decision.', + showIndividualExamples: true, + examples, +}: RNTesterModule); diff --git a/packages/rn-tester/js/examples/Alert/AlertIOSExample.js b/packages/rn-tester/js/examples/Alert/AlertIOSExample.js index 984ff8b6324c..47d796393561 100644 --- a/packages/rn-tester/js/examples/Alert/AlertIOSExample.js +++ b/packages/rn-tester/js/examples/Alert/AlertIOSExample.js @@ -19,7 +19,7 @@ const { Alert, } = require('react-native'); -const {examples: SharedAlertExamples} = require('./AlertExample'); +import {examples as SharedAlertExamples} from './AlertExample'; import type {RNTesterModuleExample} from '../../types/RNTesterTypes'; diff --git a/packages/rn-tester/js/utils/RNTesterList.android.js b/packages/rn-tester/js/utils/RNTesterList.android.js index f150ea666b11..97ffe9759a1b 100644 --- a/packages/rn-tester/js/utils/RNTesterList.android.js +++ b/packages/rn-tester/js/utils/RNTesterList.android.js @@ -142,7 +142,7 @@ const APIs: Array = [ { key: 'AlertExample', category: 'UI', - module: require('../examples/Alert/AlertExample'), + module: require('../examples/Alert/AlertExample').default, }, { key: 'AnimatedIndex', From a67360b0f3aec0e679be32715b02467429002c31 Mon Sep 17 00:00:00 2001 From: Michael Sokolnicki Date: Fri, 22 Jul 2022 17:07:26 -0700 Subject: [PATCH 0046/1165] Remove MaskedViewIOS from react-native-github Summary: Remove MaskedViewIOS from react-native-github, update deprecation warnings, rebuild CocoaPods. Changelog: [General][Removed] - Remove MaskedViewIOS Reviewed By: lunaleaps Differential Revision: D37860775 fbshipit-source-id: 963b4b9891eecf5610cfad1e93ac8bf83f29f521 --- .../MaskedView/MaskedViewIOS.android.js | 13 --- .../MaskedView/MaskedViewIOS.ios.js | 93 ------------------- .../RCTMaskedViewNativeComponent.js | 21 ----- .../__tests__/MaskedViewIOS-test.js | 40 -------- .../__snapshots__/MaskedViewIOS-test.js.snap | 77 --------------- React/Views/RCTMaskedView.h | 14 --- React/Views/RCTMaskedView.m | 34 ------- React/Views/RCTMaskedViewManager.h | 12 --- React/Views/RCTMaskedViewManager.m | 26 ------ index.js | 25 +++-- packages/rn-tester/Podfile.lock | 2 +- 11 files changed, 16 insertions(+), 341 deletions(-) delete mode 100644 Libraries/Components/MaskedView/MaskedViewIOS.android.js delete mode 100644 Libraries/Components/MaskedView/MaskedViewIOS.ios.js delete mode 100644 Libraries/Components/MaskedView/RCTMaskedViewNativeComponent.js delete mode 100644 Libraries/Components/MaskedView/__tests__/MaskedViewIOS-test.js delete mode 100644 Libraries/Components/MaskedView/__tests__/__snapshots__/MaskedViewIOS-test.js.snap delete mode 100644 React/Views/RCTMaskedView.h delete mode 100644 React/Views/RCTMaskedView.m delete mode 100644 React/Views/RCTMaskedViewManager.h delete mode 100644 React/Views/RCTMaskedViewManager.m diff --git a/Libraries/Components/MaskedView/MaskedViewIOS.android.js b/Libraries/Components/MaskedView/MaskedViewIOS.android.js deleted file mode 100644 index d9faa8e64e6b..000000000000 --- a/Libraries/Components/MaskedView/MaskedViewIOS.android.js +++ /dev/null @@ -1,13 +0,0 @@ -/** - * 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 - * @flow strict-local - */ - -'use strict'; - -module.exports = require('../UnimplementedViews/UnimplementedView'); diff --git a/Libraries/Components/MaskedView/MaskedViewIOS.ios.js b/Libraries/Components/MaskedView/MaskedViewIOS.ios.js deleted file mode 100644 index 9ae245ab6f35..000000000000 --- a/Libraries/Components/MaskedView/MaskedViewIOS.ios.js +++ /dev/null @@ -1,93 +0,0 @@ -/** - * 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 - * @flow - */ - -import * as React from 'react'; -import StyleSheet from '../../StyleSheet/StyleSheet'; -import View from '../View/View'; - -import type {ViewProps} from '../View/ViewPropTypes'; -import RCTMaskedViewNativeComponent from './RCTMaskedViewNativeComponent'; - -type Props = $ReadOnly<{| - ...ViewProps, - - children: React.Node, - /** - * Should be a React element to be rendered and applied as the - * mask for the child element. - */ - maskElement: React.Element, -|}>; - -/** - * Renders the child view with a mask specified in the `maskElement` prop. - * - * ``` - * import React from 'react'; - * import { MaskedViewIOS, Text, View } from 'react-native'; - * - * class MyMaskedView extends React.Component { - * render() { - * return ( - * - * - * Basic Mask - * - * - * } - * > - * - * - * ); - * } - * } - * ``` - * - * The above example will render a view with a blue background that fills its - * parent, and then mask that view with text that says "Basic Mask". - * - * The alpha channel of the view rendered by the `maskElement` prop determines how - * much of the view's content and background shows through. Fully or partially - * opaque pixels allow the underlying content to show through but fully - * transparent pixels block that content. - * - */ -class MaskedViewIOS extends React.Component { - _hasWarnedInvalidRenderMask = false; - - render(): React.Node { - const {maskElement, children, ...otherViewProps} = this.props; - - if (!React.isValidElement(maskElement)) { - if (!this._hasWarnedInvalidRenderMask) { - console.warn( - 'MaskedView: Invalid `maskElement` prop was passed to MaskedView. ' + - 'Expected a React Element. No mask will render.', - ); - this._hasWarnedInvalidRenderMask = true; - } - return {children}; - } - - return ( - - - {maskElement} - - {children} - - ); - } -} - -module.exports = MaskedViewIOS; diff --git a/Libraries/Components/MaskedView/RCTMaskedViewNativeComponent.js b/Libraries/Components/MaskedView/RCTMaskedViewNativeComponent.js deleted file mode 100644 index 73448de16c11..000000000000 --- a/Libraries/Components/MaskedView/RCTMaskedViewNativeComponent.js +++ /dev/null @@ -1,21 +0,0 @@ -/** - * 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 - * @flow strict-local - */ - -import type {ViewProps} from '../View/ViewPropTypes'; -import codegenNativeComponent from '../../Utilities/codegenNativeComponent'; -import type {HostComponent} from '../../Renderer/shims/ReactNativeTypes'; - -type NativeProps = $ReadOnly<{| - ...ViewProps, -|}>; - -export default (codegenNativeComponent( - 'RCTMaskedView', -): HostComponent); diff --git a/Libraries/Components/MaskedView/__tests__/MaskedViewIOS-test.js b/Libraries/Components/MaskedView/__tests__/MaskedViewIOS-test.js deleted file mode 100644 index 0abfd11da654..000000000000 --- a/Libraries/Components/MaskedView/__tests__/MaskedViewIOS-test.js +++ /dev/null @@ -1,40 +0,0 @@ -/** - * 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 - * @emails oncall+react_native - * @flow strict-local - */ - -'use strict'; - -const React = require('react'); -const Text = require('../../../Text/Text'); -const View = require('../../View/View'); -const MaskedViewIOS = require('../MaskedViewIOS'); - -const ReactNativeTestTools = require('../../../Utilities/ReactNativeTestTools'); - -describe('', () => { - it('should render as expected', () => { - ReactNativeTestTools.expectRendersMatchingSnapshot( - 'MaskedViewIOS', - () => ( - - Basic Mask - - }> - - - ), - () => { - jest.dontMock('../MaskedViewIOS'); - }, - ); - }); -}); diff --git a/Libraries/Components/MaskedView/__tests__/__snapshots__/MaskedViewIOS-test.js.snap b/Libraries/Components/MaskedView/__tests__/__snapshots__/MaskedViewIOS-test.js.snap deleted file mode 100644 index 65d8046eb1a1..000000000000 --- a/Libraries/Components/MaskedView/__tests__/__snapshots__/MaskedViewIOS-test.js.snap +++ /dev/null @@ -1,77 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[` should render as expected: should deep render when mocked (please verify output manually) 1`] = ` - - - - - Basic Mask - - - - - -`; - -exports[` should render as expected: should deep render when not mocked (please verify output manually) 1`] = ` - - - - - Basic Mask - - - - - -`; - -exports[` should render as expected: should shallow render as when mocked 1`] = ` - - - Basic Mask - - - } -> - - -`; - -exports[` should render as expected: should shallow render as when not mocked 1`] = ` - - - Basic Mask - - - } -> - - -`; diff --git a/React/Views/RCTMaskedView.h b/React/Views/RCTMaskedView.h deleted file mode 100644 index cab90b6cdca3..000000000000 --- a/React/Views/RCTMaskedView.h +++ /dev/null @@ -1,14 +0,0 @@ -/* - * 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. - */ - -#import - -#import - -@interface RCTMaskedView : RCTView - -@end diff --git a/React/Views/RCTMaskedView.m b/React/Views/RCTMaskedView.m deleted file mode 100644 index bf9bd88edf84..000000000000 --- a/React/Views/RCTMaskedView.m +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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. - */ - -#import "RCTMaskedView.h" - -#import - -@implementation RCTMaskedView - -- (void)didUpdateReactSubviews -{ - // RCTMaskedView expects that the first subview rendered is the mask. - UIView *maskView = [self.reactSubviews firstObject]; - self.maskView = maskView; - - // Add the other subviews to the view hierarchy - for (NSUInteger i = 1; i < self.reactSubviews.count; i++) { - UIView *subview = [self.reactSubviews objectAtIndex:i]; - [self addSubview:subview]; - } -} - -- (void)displayLayer:(__unused CALayer *)layer -{ - // RCTView uses displayLayer to do border rendering. - // We don't need to do that in RCTMaskedView, so we - // stub this method and override the default implementation. -} - -@end diff --git a/React/Views/RCTMaskedViewManager.h b/React/Views/RCTMaskedViewManager.h deleted file mode 100644 index 6aaf61fa281d..000000000000 --- a/React/Views/RCTMaskedViewManager.h +++ /dev/null @@ -1,12 +0,0 @@ -/* - * 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. - */ - -#import - -@interface RCTMaskedViewManager : RCTViewManager - -@end diff --git a/React/Views/RCTMaskedViewManager.m b/React/Views/RCTMaskedViewManager.m deleted file mode 100644 index 808f2e805fed..000000000000 --- a/React/Views/RCTMaskedViewManager.m +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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. - */ - -#import "RCTMaskedViewManager.h" - -#import "RCTMaskedView.h" -#import "RCTUIManager.h" - -@implementation RCTMaskedViewManager - -RCT_EXPORT_MODULE() - -- (UIView *)view -{ - RCTNewArchitectureValidationPlaceholder( - RCTNotAllowedInFabricWithoutLegacy, - self, - @"This native component is still using the legacy interop layer -- please migrate it to use a Fabric specific implementation."); - return [RCTMaskedView new]; -} - -@end diff --git a/index.js b/index.js index d59ba3454e9c..434289fff4cb 100644 --- a/index.js +++ b/index.js @@ -21,7 +21,6 @@ import typeof Image from './Libraries/Image/Image'; import typeof ImageBackground from './Libraries/Image/ImageBackground'; import typeof InputAccessoryView from './Libraries/Components/TextInput/InputAccessoryView'; import typeof KeyboardAvoidingView from './Libraries/Components/Keyboard/KeyboardAvoidingView'; -import typeof MaskedViewIOS from './Libraries/Components/MaskedView/MaskedViewIOS'; import typeof Modal from './Libraries/Modal/Modal'; import typeof Pressable from './Libraries/Components/Pressable/Pressable'; import typeof ProgressBarAndroid from './Libraries/Components/ProgressBarAndroid/ProgressBarAndroid'; @@ -145,15 +144,6 @@ module.exports = { return require('./Libraries/Components/Keyboard/KeyboardAvoidingView') .default; }, - get MaskedViewIOS(): MaskedViewIOS { - warnOnce( - 'maskedviewios-moved', - 'MaskedViewIOS has been extracted from react-native core and will be removed in a future release. ' + - "It can now be installed and imported from '@react-native-masked-view/masked-view' instead of 'react-native'. " + - 'See https://github.com/react-native-masked-view/masked-view', - ); - return require('./Libraries/Components/MaskedView/MaskedViewIOS'); - }, get Modal(): Modal { return require('./Libraries/Modal/Modal'); }, @@ -736,4 +726,19 @@ if (__DEV__) { ); }, }); + /* $FlowFixMe[prop-missing] This is intentional: Flow will error when + * attempting to access MaskedViewIOS. */ + /* $FlowFixMe[invalid-export] This is intentional: Flow will error when + * attempting to access MaskedViewIOS. */ + Object.defineProperty(module.exports, 'MaskedViewIOS', { + configurable: true, + get() { + invariant( + false, + 'MaskedViewIOS has been removed from React Native. ' + + "It can now be installed and imported from '@react-native-community/react-native-masked-view' instead of 'react-native'. " + + 'See https://github.com/react-native-masked-view/masked-view', + ); + }, + }); } diff --git a/packages/rn-tester/Podfile.lock b/packages/rn-tester/Podfile.lock index 96fed7c9a97f..3c6574fec14d 100644 --- a/packages/rn-tester/Podfile.lock +++ b/packages/rn-tester/Podfile.lock @@ -934,7 +934,7 @@ SPEC CHECKSUMS: React-RCTTest: 06c388632dc7b30df17af01c8f9e89e641b4d31c React-RCTText: a861fbf2835299d3cc4189697cddd8bd8602afb9 React-RCTVibration: 0386f50996a153b3f39cecbe7d139763ac9a9fdf - React-rncore: 6daa27c74047a9e13ce3412b99660274a5780603 + React-rncore: 2a6ad37560e94cf7ff32e3f2ae1e708491b4c1f3 React-runtimeexecutor: 97dca9247f4d3cfe0733384b189c6930fbd402b7 ReactCommon: 6cef8ed13ee2a9d7d4cf9660dbe6dd2ea6ba7104 ScreenshotManager: 71d047abd38a77310985b87f8136b620c5c61e88 From a70354df12ef71aec08583cca4f1fed5fb77d874 Mon Sep 17 00:00:00 2001 From: Chatura Atapattu Date: Sun, 24 Jul 2022 13:46:21 -0700 Subject: [PATCH 0047/1165] Apply lint updates from buildifier in xplat Summary: In D37873933, we update the buildifier binaries, which apply some minor changes to existing lint. Specifically, entries are now properly sorted. Update the files in xplat such that updating buildifier does not cause lint changes in users diffs. drop-conflicts allow_many_files #nocancel #forcetdhashing (Note: this ignores all push blocking failures!) Reviewed By: d16r Differential Revision: D37873936 fbshipit-source-id: f31d9c50d64ae99f99298977b471bf13e7ed5262 --- BUCK | 4 ++-- ReactAndroid/src/main/libraries/fbjni/BUCK | 2 +- .../main/libraries/soloader/java/com/facebook/soloader/BUCK | 2 +- ReactAndroid/src/main/third-party/kotlin/BUCK | 4 ++-- packages/react-native-codegen/BUCK | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/BUCK b/BUCK index d9ee7b3fc65c..d860f24002a2 100644 --- a/BUCK +++ b/BUCK @@ -57,9 +57,9 @@ fb_native.genrule( ) + [ react_native_root_target("packages/rn-tester:nativecomponent-srcs"), ], - labels = ["uses_hg"], - cmd = "$(exe {}) $OUT $SRCS".format(react_native_root_target("packages/react-native-codegen:write_to_json")), out = "schema-rncore.json", + cmd = "$(exe {}) $OUT $SRCS".format(react_native_root_target("packages/react-native-codegen:write_to_json")), + labels = ["uses_hg"], ) rn_codegen_components( diff --git a/ReactAndroid/src/main/libraries/fbjni/BUCK b/ReactAndroid/src/main/libraries/fbjni/BUCK index 4d6d134811ab..f9b1d33925cd 100644 --- a/ReactAndroid/src/main/libraries/fbjni/BUCK +++ b/ReactAndroid/src/main/libraries/fbjni/BUCK @@ -2,10 +2,10 @@ load("//tools/build_defs:fb_native_wrapper.bzl", "fb_native") fb_native.android_library( name = "java", + visibility = ["PUBLIC"], exported_deps = [ ":fbjni-binary", ], - visibility = ["PUBLIC"], ) fb_native.android_prebuilt_aar( diff --git a/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/BUCK b/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/BUCK index 2421d56d1c17..7b29b5186710 100644 --- a/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/BUCK +++ b/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/BUCK @@ -2,12 +2,12 @@ load("//tools/build_defs:fb_native_wrapper.bzl", "fb_native") fb_native.android_library( name = "soloader", + visibility = ["PUBLIC"], exported_deps = [ ":annotation-binary", ":nativeloader-binary", ":soloader-binary", ], - visibility = ["PUBLIC"], ) fb_native.prebuilt_jar( diff --git a/ReactAndroid/src/main/third-party/kotlin/BUCK b/ReactAndroid/src/main/third-party/kotlin/BUCK index c1d09721a553..b96b7417e97d 100644 --- a/ReactAndroid/src/main/third-party/kotlin/BUCK +++ b/ReactAndroid/src/main/third-party/kotlin/BUCK @@ -83,7 +83,6 @@ fb_native.remote_file( fb_native.genrule( name = "kotlin-compiler-download", - type = "copy", srcs = [ ":annotations-13.0.jar", ":kotlin-annotation-processing.jar", @@ -94,9 +93,10 @@ fb_native.genrule( ":kotlin-stdlib.jar", ":trove4j.jar", ], + out = "kotlin-compiler-out", cmd = "mkdir ${OUT} && cp ${SRCS} ${OUT}", cmd_exe = "@powershell -Command Copy-Item '${SRCS}' '${OUT}'", - out = "kotlin-compiler-out", + type = "copy", ) fb_native.remote_file( diff --git a/packages/react-native-codegen/BUCK b/packages/react-native-codegen/BUCK index 4a7708056982..d06563f4a08c 100644 --- a/packages/react-native-codegen/BUCK +++ b/packages/react-native-codegen/BUCK @@ -17,8 +17,8 @@ fb_native.genrule( "**/e2e/__test_fixtures__/modules/Native*.js", ], ), - cmd = "$(exe {}) $OUT $SRCS".format(react_native_root_target("packages/react-native-codegen:write_to_json")), out = "schema-codegen_tests.json", + cmd = "$(exe {}) $OUT $SRCS".format(react_native_root_target("packages/react-native-codegen:write_to_json")), ) rn_codegen_components( From 653a19a8cde60e7ab337559492c17d3aa0a860f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danilo=20B=C3=BCrger?= Date: Mon, 25 Jul 2022 10:19:06 -0700 Subject: [PATCH 0048/1165] Allow preferred Alert button regardless of the style (#34253) Summary: See https://github.com/facebook/react-native/pull/32538 for the discussion cc robbie-c ## Changelog [iOS] [Fixed] - Allow preferred Alert button regardless of the style Pull Request resolved: https://github.com/facebook/react-native/pull/34253 Test Plan: Same test plan as PR mentioned above Reviewed By: lunaleaps Differential Revision: D38112619 Pulled By: cipolleschi fbshipit-source-id: 2ac4fc6226a859e69f0df27913898effa5e092eb --- Libraries/Alert/Alert.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Libraries/Alert/Alert.js b/Libraries/Alert/Alert.js index 3e011e4cd727..68bf6fea03c5 100644 --- a/Libraries/Alert/Alert.js +++ b/Libraries/Alert/Alert.js @@ -137,7 +137,8 @@ class Alert { cancelButtonKey = String(index); } else if (btn.style === 'destructive') { destructiveButtonKey = String(index); - } else if (btn.isPreferred) { + } + if (btn.isPreferred) { preferredButtonKey = String(index); } if (btn.text || index < (callbackOrButtons || []).length - 1) { From 246c74724bd4100955bab93bcaebe1db7d77f203 Mon Sep 17 00:00:00 2001 From: Lorenzo Sciandra Date: Mon, 25 Jul 2022 13:19:01 -0700 Subject: [PATCH 0049/1165] add 0.69.3 changelog (#34270) Summary: Adds changelog for new patch. ## Changelog [Internal] [Changed] - add changelog entry for 0.69.3 Pull Request resolved: https://github.com/facebook/react-native/pull/34270 Test Plan: N/A Reviewed By: lunaleaps Differential Revision: D38116297 Pulled By: dmitryrykun fbshipit-source-id: 962e34b4cfd58947cf6d95ae05affda7b9271716 --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 296ea125c320..e416a0c7d77c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## v0.69.3 + +### Fixed + +#### iOS specific + +- Fix React-bridging header not found for third party modules ([fa2acc32d1](https://github.com/facebook/react-native/commit/fa2acc32d1490f6e418689dec321f8bd4ef7bb28) by [@Kudo](https://github.com/Kudo)) + ## v0.69.2 ### Changed From e7a8d21df563e48e1812caace7fbe1f7cbc1c015 Mon Sep 17 00:00:00 2001 From: Harold Pratt <38818465+htpiv@users.noreply.github.com> Date: Mon, 25 Jul 2022 15:35:25 -0700 Subject: [PATCH 0050/1165] Rewrite CompactValue to avoid undefined behavior from the use of a union for type-punning (#1154) Summary: C++ does not, pedantically, allow the use of unions for type-punning in the way that C does. Most compilers, in practice, do support it; however, recent versions of MSVC appear to have a bug that cause bad code to be generated due to this U.B. (see: https://developercommunity.visualstudio.com/t/Bad-code-generated-for-std::isnan-compil/10082631). This led to a series of issues in the react-native-windows project, see: * https://github.com/microsoft/react-native-windows/issues/4122 * https://github.com/microsoft/react-native-windows/issues/8675 In C++20, the `` header and `bit_cast` function provide a pleasant API for type-punning. Since C++20 is not universally available, if the feature-test macro for `bit_cast` is not defined, memcpy is used instead. X-link: https://github.com/facebook/yoga/pull/1154 Reviewed By: Andrey-Mishanin Differential Revision: D38082048 Pulled By: rozele fbshipit-source-id: a5da08cfb7d4296c725fb44871c55dbb12dc71e5 --- ReactCommon/yoga/yoga/CompactValue.h | 78 +++++++++++++++++----------- 1 file changed, 49 insertions(+), 29 deletions(-) diff --git a/ReactCommon/yoga/yoga/CompactValue.h b/ReactCommon/yoga/yoga/CompactValue.h index 1f03cf721aaf..6568c48ad2c1 100644 --- a/ReactCommon/yoga/yoga/CompactValue.h +++ b/ReactCommon/yoga/yoga/CompactValue.h @@ -9,6 +9,11 @@ #ifdef __cplusplus +#ifdef __cpp_lib_bit_cast +#include +#else +#include +#endif #include "YGValue.h" #include "YGMacros.h" #include @@ -55,7 +60,7 @@ class YOGA_EXPORT CompactValue { if (value == 0.0f || (value < LOWER_BOUND && value > -LOWER_BOUND)) { constexpr auto zero = Unit == YGUnitPercent ? ZERO_BITS_PERCENT : ZERO_BITS_POINT; - return {Payload{zero}}; + return {zero}; } constexpr auto upperBound = @@ -65,9 +70,9 @@ class YOGA_EXPORT CompactValue { } uint32_t unitBit = Unit == YGUnitPercent ? PERCENT_BIT : 0; - auto data = Payload{value}; - data.repr -= BIAS; - data.repr |= unitBit; + auto data = asU32(value); + data -= BIAS; + data |= unitBit; return {data}; } @@ -78,7 +83,7 @@ class YOGA_EXPORT CompactValue { } static constexpr CompactValue ofZero() noexcept { - return CompactValue{Payload{ZERO_BITS_POINT}}; + return CompactValue{ZERO_BITS_POINT}; } static constexpr CompactValue ofUndefined() noexcept { @@ -86,13 +91,12 @@ class YOGA_EXPORT CompactValue { } static constexpr CompactValue ofAuto() noexcept { - return CompactValue{Payload{AUTO_BITS}}; + return CompactValue{AUTO_BITS}; } - constexpr CompactValue() noexcept - : payload_(std::numeric_limits::quiet_NaN()) {} + constexpr CompactValue() noexcept : repr_(0x7FC00000) {} - CompactValue(const YGValue& x) noexcept : payload_(uint32_t{0}) { + CompactValue(const YGValue& x) noexcept : repr_(uint32_t{0}) { switch (x.unit) { case YGUnitUndefined: *this = ofUndefined(); @@ -110,7 +114,7 @@ class YOGA_EXPORT CompactValue { } operator YGValue() const noexcept { - switch (payload_.repr) { + switch (repr_) { case AUTO_BITS: return YGValueAuto; case ZERO_BITS_POINT: @@ -119,34 +123,28 @@ class YOGA_EXPORT CompactValue { return YGValue{0.0f, YGUnitPercent}; } - if (std::isnan(payload_.value)) { + if (std::isnan(asFloat(repr_))) { return YGValueUndefined; } - auto data = payload_; - data.repr &= ~PERCENT_BIT; - data.repr += BIAS; + auto data = repr_; + data &= ~PERCENT_BIT; + data += BIAS; return YGValue{ - data.value, payload_.repr & 0x40000000 ? YGUnitPercent : YGUnitPoint}; + asFloat(data), repr_ & 0x40000000 ? YGUnitPercent : YGUnitPoint}; } bool isUndefined() const noexcept { return ( - payload_.repr != AUTO_BITS && payload_.repr != ZERO_BITS_POINT && - payload_.repr != ZERO_BITS_PERCENT && std::isnan(payload_.value)); + repr_ != AUTO_BITS && repr_ != ZERO_BITS_POINT && + repr_ != ZERO_BITS_PERCENT && std::isnan(asFloat(repr_))); } - bool isAuto() const noexcept { return payload_.repr == AUTO_BITS; } + bool isAuto() const noexcept { return repr_ == AUTO_BITS; } private: - union Payload { - float value; - uint32_t repr; - Payload() = delete; - constexpr Payload(uint32_t r) : repr(r) {} - constexpr Payload(float v) : value(v) {} - }; + uint32_t repr_; static constexpr uint32_t BIAS = 0x20000000; static constexpr uint32_t PERCENT_BIT = 0x40000000; @@ -157,11 +155,33 @@ class YOGA_EXPORT CompactValue { static constexpr uint32_t ZERO_BITS_POINT = 0x7f8f0f0f; static constexpr uint32_t ZERO_BITS_PERCENT = 0x7f80f0f0; - constexpr CompactValue(Payload data) noexcept : payload_(data) {} + constexpr CompactValue(uint32_t data) noexcept : repr_(data) {} - Payload payload_; + VISIBLE_FOR_TESTING uint32_t repr() { return repr_; } - VISIBLE_FOR_TESTING uint32_t repr() { return payload_.repr; } + static uint32_t asU32(float f) { +#ifdef __cpp_lib_bit_cast + return std::bit_cast(f); +#else + uint32_t u; + static_assert( + sizeof(u) == sizeof(f), "uint32_t and float must have the same size"); + std::memcpy(&u, &f, sizeof(f)); + return u; +#endif + } + + static float asFloat(uint32_t u) { +#ifdef __cpp_lib_bit_cast + return std::bit_cast(u); +#else + float f; + static_assert( + sizeof(f) == sizeof(u), "uint32_t and float must have the same size"); + std::memcpy(&f, &u, sizeof(u)); + return f; +#endif + } }; template <> @@ -174,7 +194,7 @@ template <> CompactValue CompactValue::ofMaybe(float) noexcept = delete; constexpr bool operator==(CompactValue a, CompactValue b) noexcept { - return a.payload_.repr == b.payload_.repr; + return a.repr_ == b.repr_; } constexpr bool operator!=(CompactValue a, CompactValue b) noexcept { From 7db6c080f5992df76b10930908c2373634cd1911 Mon Sep 17 00:00:00 2001 From: Christoph Purrer Date: Mon, 25 Jul 2022 17:17:11 -0700 Subject: [PATCH 0051/1165] Fix exception thrown by [RCTTextView description] on macOS Summary: This method assumes a semicolon existed before the closing bracket (`>`), but only does on iOS. This instead puts the content before the closing bracket, which is always there on both platforms. Changelog: [macOS][Fixed] - Fix exception thrown by [RCTTextView description] on macOS Reviewed By: sammy-SC Differential Revision: D38074642 fbshipit-source-id: f46d15c2bf2d966d1c1430568f083e4d501d4b40 --- Libraries/Text/Text/RCTTextView.m | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Libraries/Text/Text/RCTTextView.m b/Libraries/Text/Text/RCTTextView.m index 6726e12deab0..de294585f2e5 100644 --- a/Libraries/Text/Text/RCTTextView.m +++ b/Libraries/Text/Text/RCTTextView.m @@ -38,9 +38,9 @@ - (instancetype)initWithFrame:(CGRect)frame - (NSString *)description { NSString *superDescription = super.description; - NSRange semicolonRange = [superDescription rangeOfString:@";"]; - NSString *replacement = [NSString stringWithFormat:@"; reactTag: %@; text: %@", self.reactTag, _textStorage.string]; - return [superDescription stringByReplacingCharactersInRange:semicolonRange withString:replacement]; + NSRange replacementRange = [superDescription rangeOfString:@">"]; + NSString *replacement = [NSString stringWithFormat:@"; reactTag: %@; text: %@>", self.reactTag, _textStorage.string]; + return [superDescription stringByReplacingCharactersInRange:replacementRange withString:replacement]; } - (void)setSelectable:(BOOL)selectable @@ -113,7 +113,7 @@ - (void)drawRect:(CGRect)rect // CATextLayer disables font smoothing by default now on macOS; we follow suit. CGContextSetShouldSmoothFonts(context, NO); #endif - + NSRange glyphRange = [layoutManager glyphRangeForTextContainer:textContainer]; [layoutManager drawBackgroundForGlyphRange:glyphRange atPoint:_contentFrame.origin]; [layoutManager drawGlyphsForGlyphRange:glyphRange atPoint:_contentFrame.origin]; @@ -157,7 +157,7 @@ - (void)drawRect:(CGRect)rect [_highlightLayer removeFromSuperlayer]; _highlightLayer = nil; } - + #if TARGET_OS_MACCATALYST CGContextRestoreGState(context); #endif From 4cbd263173b992c0a0dc7c640e39794f39ce1b34 Mon Sep 17 00:00:00 2001 From: David Vacca Date: Mon, 25 Jul 2022 17:48:14 -0700 Subject: [PATCH 0052/1165] Un-deprecate DisplayMetrics.getWindowDisplayMetrics() method Summary: The purpose of this diff is to un-deprecate the method DisplayMetrics.getWindowDisplayMetrics(). As React Native is used in devices with multiple screens and displays, we need to provide a non-deprecated way to access display metrics (e.g. screen density) for the window that's used to render react native views. This diff doesn't make any change in behavior, but it un-deprecates the API changelog: [Android][Added] Un-deprecate DisplayMetrics.getWindowDisplayMetrics() method Reviewed By: javache Differential Revision: D37871954 fbshipit-source-id: d8eb97cfae096f2f62ed1389a6de17a892a46b43 --- .../react/uimanager/DisplayMetricsHolder.java | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/DisplayMetricsHolder.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/DisplayMetricsHolder.java index c3a2c630563f..2d9d1def01c9 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/DisplayMetricsHolder.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/DisplayMetricsHolder.java @@ -18,21 +18,13 @@ /** * Holds an instance of the current DisplayMetrics so we don't have to thread it through all the - * classes that need it. Note: windowDisplayMetrics are deprecated in favor of ScreenDisplayMetrics: - * window metrics are supposed to return the drawable area but there's no guarantee that they - * correspond to the actual size of the {@link ReactRootView}. Moreover, they are not consistent - * with what iOS returns. Screen metrics returns the metrics of the entire screen, is consistent - * with iOS and should be used instead. + * classes that need it. */ public class DisplayMetricsHolder { private static @Nullable DisplayMetrics sWindowDisplayMetrics; private static @Nullable DisplayMetrics sScreenDisplayMetrics; - /** - * @deprecated Use {@link #setScreenDisplayMetrics(DisplayMetrics)} instead. See comment above as - * to why this is not correct to use. - */ public static void setWindowDisplayMetrics(DisplayMetrics displayMetrics) { sWindowDisplayMetrics = displayMetrics; } @@ -63,11 +55,7 @@ public static void initDisplayMetrics(Context context) { DisplayMetricsHolder.setScreenDisplayMetrics(screenDisplayMetrics); } - /** - * @deprecated Use {@link #getScreenDisplayMetrics()} instead. See comment above as to why this is - * not correct to use. - */ - @Deprecated + /** Returns the metrics of the window associated to the Context used to initialize ReactNative */ public static DisplayMetrics getWindowDisplayMetrics() { return sWindowDisplayMetrics; } @@ -76,6 +64,7 @@ public static void setScreenDisplayMetrics(DisplayMetrics screenDisplayMetrics) sScreenDisplayMetrics = screenDisplayMetrics; } + /** Screen metrics returns the metrics of the default screen on the device. */ public static DisplayMetrics getScreenDisplayMetrics() { return sScreenDisplayMetrics; } From 8b174a57c8e732bbfe7c69e7a5f66f48cb300539 Mon Sep 17 00:00:00 2001 From: Christoph Purrer Date: Mon, 25 Jul 2022 18:14:46 -0700 Subject: [PATCH 0053/1165] Possible fix for convertIdToFollyDynamic crash in RCTBaseTextInputView and RCTEventDispatcher Summary: A crash encountered in react-native-macOS is very similar to one fixed by https://github.com/microsoft/react-native-macos/pull/489#discussion_r451789471 (see discussion), and it's possible this `replacement` string also suffers from sharing the same backing store as the attributed string (maybe only when the range encompasses the entire string?) and therefore should be copied as well. Changelog: [iOS][Fixed] - Possible fix for convertIdToFollyDynamic crash in RCTBaseTextInputView and RCTEventDispatcher Reviewed By: sammy-SC Differential Revision: D38064551 fbshipit-source-id: 9c15f2a980155ab3cbb3fde79fcb93b24ee2091a --- Libraries/Text/TextInput/RCTBaseTextInputView.m | 3 ++- React/CoreModules/RCTEventDispatcher.mm | 8 ++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Libraries/Text/TextInput/RCTBaseTextInputView.m b/Libraries/Text/TextInput/RCTBaseTextInputView.m index c719b5628917..8b0c4c192fa9 100644 --- a/Libraries/Text/TextInput/RCTBaseTextInputView.m +++ b/Libraries/Text/TextInput/RCTBaseTextInputView.m @@ -439,7 +439,8 @@ - (NSString *)textInputShouldChangeText:(NSString *)text inRange:(NSRange)range if (_onTextInput) { _onTextInput(@{ - @"text": text, + // We copy the string here because if it's a mutable string it may get released before we stop using it on a different thread, causing a crash. + @"text": [text copy], @"previousText": previousText, @"range": @{ @"start": @(range.location), diff --git a/React/CoreModules/RCTEventDispatcher.mm b/React/CoreModules/RCTEventDispatcher.mm index f2cf17c947ee..3669e2e7d64b 100644 --- a/React/CoreModules/RCTEventDispatcher.mm +++ b/React/CoreModules/RCTEventDispatcher.mm @@ -86,7 +86,9 @@ - (void)sendTextEventWithType:(RCTTextEventType)type }]; if (text) { - body[@"text"] = text; + // We copy the string here because if it's a mutable string it may get released before we dispatch the event on a + // different thread, causing a crash. + body[@"text"] = [text copy]; } if (key) { @@ -103,7 +105,9 @@ - (void)sendTextEventWithType:(RCTTextEventType)type break; } } - body[@"key"] = key; + // We copy the string here because if it's a mutable string it may get released before we dispatch the event on a + // different thread, causing a crash. + body[@"key"] = [key copy]; } RCTComponentEvent *event = [[RCTComponentEvent alloc] initWithName:events[type] viewTag:reactTag body:body]; From 0d068a569998525e77a71bd6e7f5579ec26178ba Mon Sep 17 00:00:00 2001 From: Antoine Doubovetzky Date: Tue, 26 Jul 2022 04:12:40 -0700 Subject: [PATCH 0054/1165] (AppState) remove outdated TODO (#34264) Summary: We are already returning the `remove` function, and the `removeEventListener` method has been removed in this PR: https://github.com/facebook/react-native/issues/33580. So I believe this comment is now outdated and no longer relevant. ## Changelog [Internal] [Removed] - Remove outdated TODO in AppState Pull Request resolved: https://github.com/facebook/react-native/pull/34264 Reviewed By: dmitryrykun Differential Revision: D38120344 Pulled By: GijsWeterings fbshipit-source-id: c6c4d42f5b631a67bb6ad49c14df1a772f1cc71b --- Libraries/AppState/AppState.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Libraries/AppState/AppState.js b/Libraries/AppState/AppState.js index 99e731bd43fb..560049479810 100644 --- a/Libraries/AppState/AppState.js +++ b/Libraries/AppState/AppState.js @@ -82,11 +82,6 @@ class AppState { } } - // TODO: now that AppState is a subclass of NativeEventEmitter, we could - // deprecate `addEventListener` and `removeEventListener` and just use - // addListener` and `listener.remove()` directly. That will be a breaking - // change though, as both the method and event names are different - // (addListener events are currently required to be globally unique). /** * Add a handler to AppState changes by listening to the `change` event type * and providing the handler. From 743f9ff63bf1e3825a1788978a9f6bad8ebddc0d Mon Sep 17 00:00:00 2001 From: Gijs Weterings Date: Tue, 26 Jul 2022 04:17:11 -0700 Subject: [PATCH 0055/1165] mitigate CVE-2022-25858 for hermes inspector by bumping terser version Summary: Changelog: [General][Security] bump terser minor version to mitigate CVE-2022-25858 Reviewed By: jacdebug Differential Revision: D38115818 fbshipit-source-id: 79a4513fc5345c158c92912559217bdbed608b7f --- ReactCommon/hermes/inspector/tools/msggen/yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ReactCommon/hermes/inspector/tools/msggen/yarn.lock b/ReactCommon/hermes/inspector/tools/msggen/yarn.lock index 40a02746282e..cf72d2b1e3fc 100644 --- a/ReactCommon/hermes/inspector/tools/msggen/yarn.lock +++ b/ReactCommon/hermes/inspector/tools/msggen/yarn.lock @@ -5517,9 +5517,9 @@ terser-webpack-plugin@^1.4.3: worker-farm "^1.7.0" terser@^4.1.2: - version "4.8.0" - resolved "https://registry.yarnpkg.com/terser/-/terser-4.8.0.tgz#63056343d7c70bb29f3af665865a46fe03a0df17" - integrity sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw== + version "4.8.1" + resolved "https://registry.yarnpkg.com/terser/-/terser-4.8.1.tgz#a00e5634562de2239fd404c649051bf6fc21144f" + integrity sha512-4GnLC0x667eJG0ewJTa6z/yXrbLGv80D9Ru6HIpCQmO+Q4PfEtBFi0ObSckqwL6VyQv/7ENJieXHo2ANmdQwgw== dependencies: commander "^2.20.0" source-map "~0.6.1" From aabb5df7ec884b7e08b8b8bef658727653406fd9 Mon Sep 17 00:00:00 2001 From: Nick Gerleman Date: Tue, 26 Jul 2022 04:34:28 -0700 Subject: [PATCH 0056/1165] Add types for onFocusCapture/onBlurCapture Summary: Add capture-phase focus events to the type system, for use in the refactored VirtualizedList https://github.com/facebook/react-native/pull/32646/files Tracking the last focused child is done via focus events. Focus events are bubbling (vs direct events like onLayout), and are given both a "capture" phase, and "bubbling phase", like DOM events on the web. https://stackoverflow.com/questions/4616694/what-is-event-bubbling-and-capturing The VirtualizedList change wants to know if a child will receive focus. This is not possible to reliably capture in the bubbling phase, since a child may stop propagation. See https://github.com/react-native-community/discussions-and-proposals/pull/335#discussion_r584851337 for some discussion with Scott Kyle about this issue back in the day This is done by convention in React by adding a "capture" variant of the `onXXX` method. For all platforms I've seen with focus events, these map the `topFocus` native event to `onFocus` for bubbling phase, and `onFocusCapture` for capture phase. See https://reactjs.org/docs/events.html#supported-events Changelog: [General][Added] - Add types for onFocusCapture/onBlurCapture Reviewed By: javache Differential Revision: D38013861 fbshipit-source-id: 7bda22e1a4d5e36ac5e34e804abf6fb318a41baf --- Libraries/Components/View/ViewPropTypes.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/Libraries/Components/View/ViewPropTypes.js b/Libraries/Components/View/ViewPropTypes.js index 4a97e85f669e..c7ee1baa63a1 100644 --- a/Libraries/Components/View/ViewPropTypes.js +++ b/Libraries/Components/View/ViewPropTypes.js @@ -33,11 +33,6 @@ import type { export type ViewLayout = Layout; export type ViewLayoutEvent = LayoutEvent; -type BubblingEventProps = $ReadOnly<{| - onBlur?: ?(event: BlurEvent) => mixed, - onFocus?: ?(event: FocusEvent) => mixed, -|}>; - type DirectEventProps = $ReadOnly<{| /** * When `accessible` is true, the system will try to invoke this function @@ -105,6 +100,13 @@ type PointerEventProps = $ReadOnly<{| onPointerUpCapture?: ?(e: PointerEvent) => void, |}>; +type FocusEventProps = $ReadOnly<{| + onBlur?: ?(event: BlurEvent) => void, + onBlurCapture?: ?(event: BlurEvent) => void, + onFocus?: ?(event: FocusEvent) => void, + onFocusCapture?: ?(event: FocusEvent) => void, +|}>; + type TouchEventProps = $ReadOnly<{| onTouchCancel?: ?(e: PressEvent) => void, onTouchCancelCapture?: ?(e: PressEvent) => void, @@ -394,11 +396,11 @@ type IOSViewProps = $ReadOnly<{| |}>; export type ViewProps = $ReadOnly<{| - ...BubblingEventProps, ...DirectEventProps, ...GestureResponderEventProps, ...MouseEventProps, ...PointerEventProps, + ...FocusEventProps, ...TouchEventProps, ...AndroidViewProps, ...IOSViewProps, From 8441c4a6f7bfeda73f89f076fe7d8d1132e4b9be Mon Sep 17 00:00:00 2001 From: Lorenzo Sciandra Date: Tue, 26 Jul 2022 06:47:51 -0700 Subject: [PATCH 0057/1165] fix npm lifecycle hook (#34273) Summary: In `0.70-stable` we started seeing `yarn run lint` fail; turns out, this is happening because the latest release of `react-native/eslint-plugin-specs` 0.0.4 (from https://github.com/facebook/react-native/commit/ea8d8e2f49ea3ce15faeab500b661a1cacacf8a8) is faulty: the underlying reason is that since 0.0.2 there was this local workaround in place https://github.com/facebook/react-native/commit/2d06e6a4c9261bb7790cf217b66145415301bc54 (that changes a flag from false to true) but in NPM 8 the lifecycle hook `prepublish` has [been deprecated](https://docs.npmjs.com/cli/v8/using-npm/scripts#life-cycle-scripts) so this pre publishing script to change the flag was not run (you can easily verify by checking the node_module and see `react-native-modules.js` the flag on L17 is set to false). This PR addresses it by moving to the new lifecycle hook `prepack` (and modifies the other files accordingly). After this PR is merged, we'll need to cherry pick it into 0.70 and do both a new release from the 0.70 branch and one from the main branch to have new versions of this module with the flag set correctly. ## Changelog [General] [Fixed] - Fix eslint-plugin-specs prepack npm lifecycle hook now that we use npm 8 Pull Request resolved: https://github.com/facebook/react-native/pull/34273 Test Plan: Go in the `eslint-plugin-specs` folder, run `npm pack`, unzip the generated tar file, go into `package`, verify that L17 of `react-native-modules.js` is correctly changed to `const PACKAGE_USAGE = true;` (instead of false - which is what happen without this fix). Reviewed By: GijsWeterings Differential Revision: D38151433 Pulled By: dmitryrykun fbshipit-source-id: 7c4f13dae70eb731d57cbafa90f7be05c9bb8576 --- packages/eslint-plugin-specs/package.json | 2 +- packages/eslint-plugin-specs/{prepublish.js => prepack.js} | 0 packages/eslint-plugin-specs/react-native-modules.js | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename packages/eslint-plugin-specs/{prepublish.js => prepack.js} (100%) diff --git a/packages/eslint-plugin-specs/package.json b/packages/eslint-plugin-specs/package.json index 8339cd008eea..0b404bee8c34 100644 --- a/packages/eslint-plugin-specs/package.json +++ b/packages/eslint-plugin-specs/package.json @@ -9,7 +9,7 @@ "directory": "packages/eslint-plugin-specs" }, "scripts": { - "prepublish": "node prepublish.js" + "prepack": "node prepack.js" }, "dependencies": { "@babel/core": "^7.14.0", diff --git a/packages/eslint-plugin-specs/prepublish.js b/packages/eslint-plugin-specs/prepack.js similarity index 100% rename from packages/eslint-plugin-specs/prepublish.js rename to packages/eslint-plugin-specs/prepack.js diff --git a/packages/eslint-plugin-specs/react-native-modules.js b/packages/eslint-plugin-specs/react-native-modules.js index ae0041b04844..d0b5aab0ac4c 100644 --- a/packages/eslint-plugin-specs/react-native-modules.js +++ b/packages/eslint-plugin-specs/react-native-modules.js @@ -13,7 +13,7 @@ const path = require('path'); const withBabelRegister = require('./with-babel-register'); -// We run yarn prepublish before publishing package which will set this value to true +// We use the prepack hook before publishing package to set this value to true const PACKAGE_USAGE = false; const ERRORS = { misnamedHasteModule(hasteModuleName) { From 546c4b4c6cbbae0339a9c23ea2bd7f34bb552247 Mon Sep 17 00:00:00 2001 From: Vincent Riemer Date: Tue, 26 Jul 2022 11:41:48 -0700 Subject: [PATCH 0058/1165] Add isPrimary property implementation to the PointerEvent object Summary: Changelog: [iOS][Internal] - Add isPrimary property implementation to the PointerEvent object This diff adds the `isPrimary` property to the PointerEvent object iOS implementation. In addition this adds a related change where we "reserve" the 0 touch identifier for mouse events and the 1 identifier for apple pencil events. This is an easy way to ensure that these pointers are always consistent no matter what happens. Since mouse & pencil pointers should always be considered the primary pointer, that allows us to focus the more advanced primary pointer differentiation purely on touch events. The logic for this touch event primary pointer differentiation is essentially setting the first touch it recieves as a primary pointer, setting it on touch registration, and sets all subsequent touchs (while the first touch is down) as not the primary pointers. When that primary pointer is lifted, the class property keeping track of the primary pointer is reset and then the **next** pointer (secondary pointers which had already started before the previous primary pointer was lifted are not "upgraded" to primary) is marked as primary. A new platform test is also included in this diff in order to verify the aforementioned behavior. Reviewed By: lunaleaps Differential Revision: D37961707 fbshipit-source-id: ae8b78c5bfea6902fb73094fca1552e4e648ea44 --- React/Fabric/RCTSurfaceTouchHandler.mm | 70 ++++++++- .../renderer/components/view/PointerEvent.cpp | 1 + .../renderer/components/view/PointerEvent.h | 5 + .../components/view/TouchEventEmitter.cpp | 1 + .../PointerEventPrimaryTouchPointer.js | 144 ++++++++++++++++++ .../Experimental/W3CPointerEventsExample.js | 9 ++ 6 files changed, 227 insertions(+), 3 deletions(-) create mode 100644 packages/rn-tester/js/examples/Experimental/W3CPointerEventPlatformTests/PointerEventPrimaryTouchPointer.js diff --git a/React/Fabric/RCTSurfaceTouchHandler.mm b/React/Fabric/RCTSurfaceTouchHandler.mm index d748a99641c5..67c6aa9b60dc 100644 --- a/React/Fabric/RCTSurfaceTouchHandler.mm +++ b/React/Fabric/RCTSurfaceTouchHandler.mm @@ -88,6 +88,11 @@ typedef NS_ENUM(NSInteger, RCTTouchEventType) { */ UIKeyModifierFlags modifierFlags; + /* + * Indicates if the active touch represents the primary pointer of this pointer type. + */ + bool isPrimary; + /* * A component view on which the touch was begun. */ @@ -108,6 +113,15 @@ bool operator()(const ActiveTouch &lhs, const ActiveTouch &rhs) const }; }; +// Mouse and Pen pointers get reserved IDs so they stay consistent no matter the order +// at which events come in +static int const kMousePointerId = 0; +static int const kPencilPointerId = 1; + +// If a new reserved ID is added above this should be incremented to ensure touch events +// do not conflict +static int const kTouchIdentifierPoolOffset = 2; + // Returns a CGPoint which represents the tiltX/Y values (in RADIANS) // Adapted from https://gist.github.com/k3a/2903719bb42b48c9198d20c2d6f73ac1 static CGPoint SphericalToTilt(CGFloat altitudeAngleRad, CGFloat azimuthAngleRad) @@ -309,6 +323,7 @@ static PointerEvent CreatePointerEventFromActiveTouch(ActiveTouch activeTouch, R event.tangentialPressure = 0.0; event.twist = 0; + event.isPrimary = activeTouch.isPrimary; return event; } @@ -324,7 +339,7 @@ static PointerEvent CreatePointerEventFromIncompleteHoverData( // "touch" events produced from a mouse cursor on iOS always have the ID 0 so // we can just assume that here since these sort of hover events only ever come // from the mouse - event.pointerId = 0; + event.pointerId = kMousePointerId; event.pressure = 0.0; event.pointerType = "mouse"; event.clientPoint = RCTPointFromCGPoint(clientLocation); @@ -339,6 +354,7 @@ static PointerEvent CreatePointerEventFromIncompleteHoverData( UpdatePointerEventModifierFlags(event, modifierFlags); event.tangentialPressure = 0.0; event.twist = 0; + event.isPrimary = true; return event; } @@ -412,6 +428,8 @@ @implementation RCTSurfaceTouchHandler { UIHoverGestureRecognizer *_hoverRecognizer API_AVAILABLE(ios(13.0)); NSOrderedSet *_currentlyHoveredViews; + + int _primaryTouchPointerId; } - (instancetype)init @@ -429,6 +447,7 @@ - (instancetype)init _hoverRecognizer = nil; _currentlyHoveredViews = [NSOrderedSet orderedSet]; + _primaryTouchPointerId = -1; } return self; @@ -469,7 +488,34 @@ - (void)_registerTouches:(NSSet *)touches withEvent:(UIEvent *)event { for (UITouch *touch in touches) { auto activeTouch = CreateTouchWithUITouch(touch, event, _rootComponentView, _viewOriginOffset); - activeTouch.touch.identifier = _identifierPool.dequeue(); + + if (@available(iOS 13.4, *)) { + switch (touch.type) { + case UITouchTypeIndirectPointer: + activeTouch.touch.identifier = kMousePointerId; + activeTouch.isPrimary = true; + break; + case UITouchTypePencil: + activeTouch.touch.identifier = kPencilPointerId; + activeTouch.isPrimary = true; + break; + default: + // use the identifier pool offset to ensure no conflicts between the reserved IDs and the + // touch IDs + activeTouch.touch.identifier = _identifierPool.dequeue() + kTouchIdentifierPoolOffset; + if (_primaryTouchPointerId == -1) { + _primaryTouchPointerId = activeTouch.touch.identifier; + activeTouch.isPrimary = true; + } + break; + } + } else { + activeTouch.touch.identifier = _identifierPool.dequeue(); + if (_primaryTouchPointerId == -1) { + _primaryTouchPointerId = activeTouch.touch.identifier; + activeTouch.isPrimary = true; + } + } _activeTouches.emplace(touch, activeTouch); } } @@ -496,7 +542,25 @@ - (void)_unregisterTouches:(NSSet *)touches continue; } auto &activeTouch = iterator->second; - _identifierPool.enqueue(activeTouch.touch.identifier); + + if (activeTouch.touch.identifier == _primaryTouchPointerId) { + _primaryTouchPointerId = -1; + } + + if (@available(iOS 13.4, *)) { + // only need to enqueue if the touch type isn't one with a reserved identifier + switch (touch.type) { + case UITouchTypeIndirectPointer: + case UITouchTypePencil: + break; + default: + // since the touch's identifier has been offset we need to re-normalize it to 0-based + // which is what the identifier pool expects + _identifierPool.enqueue(activeTouch.touch.identifier - kTouchIdentifierPoolOffset); + } + } else { + _identifierPool.enqueue(activeTouch.touch.identifier); + } _activeTouches.erase(touch); } } diff --git a/ReactCommon/react/renderer/components/view/PointerEvent.cpp b/ReactCommon/react/renderer/components/view/PointerEvent.cpp index ce0627986f91..7c5c1869dca7 100644 --- a/ReactCommon/react/renderer/components/view/PointerEvent.cpp +++ b/ReactCommon/react/renderer/components/view/PointerEvent.cpp @@ -39,6 +39,7 @@ std::vector getDebugProps( {"shiftKey", getDebugDescription(pointerEvent.shiftKey, options)}, {"altKey", getDebugDescription(pointerEvent.altKey, options)}, {"metaKey", getDebugDescription(pointerEvent.metaKey, options)}, + {"isPrimary", getDebugDescription(pointerEvent.isPrimary, options)}, }; } diff --git a/ReactCommon/react/renderer/components/view/PointerEvent.h b/ReactCommon/react/renderer/components/view/PointerEvent.h index abe80ead9020..4812e55b3315 100644 --- a/ReactCommon/react/renderer/components/view/PointerEvent.h +++ b/ReactCommon/react/renderer/components/view/PointerEvent.h @@ -100,6 +100,11 @@ struct PointerEvent { * Returns true if the meta key was down when the event was fired. */ bool metaKey; + /* + * Indicates if the pointer represents the primary pointer of this pointer + * type. + */ + bool isPrimary; }; #if RN_DEBUG_STRING_CONVERTIBLE diff --git a/ReactCommon/react/renderer/components/view/TouchEventEmitter.cpp b/ReactCommon/react/renderer/components/view/TouchEventEmitter.cpp index 8eb4bc8d1444..5d5b17f28b65 100644 --- a/ReactCommon/react/renderer/components/view/TouchEventEmitter.cpp +++ b/ReactCommon/react/renderer/components/view/TouchEventEmitter.cpp @@ -91,6 +91,7 @@ static jsi::Value pointerEventPayload( object.setProperty(runtime, "shiftKey", event.shiftKey); object.setProperty(runtime, "altKey", event.altKey); object.setProperty(runtime, "metaKey", event.metaKey); + object.setProperty(runtime, "isPrimary", event.isPrimary); return object; } diff --git a/packages/rn-tester/js/examples/Experimental/W3CPointerEventPlatformTests/PointerEventPrimaryTouchPointer.js b/packages/rn-tester/js/examples/Experimental/W3CPointerEventPlatformTests/PointerEventPrimaryTouchPointer.js new file mode 100644 index 000000000000..8516d2656479 --- /dev/null +++ b/packages/rn-tester/js/examples/Experimental/W3CPointerEventPlatformTests/PointerEventPrimaryTouchPointer.js @@ -0,0 +1,144 @@ +/** + * 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 + * @flow + */ + +import type {PlatformTestComponentBaseProps} from '../PlatformTest/RNTesterPlatformTestTypes'; +import type {PointerEvent} from 'react-native/Libraries/Types/CoreEventTypes'; + +import {useTestEventHandler} from './PointerEventSupport'; +import RNTesterPlatformTest from '../PlatformTest/RNTesterPlatformTest'; +import * as React from 'react'; +import {useRef, useCallback, useMemo} from 'react'; +import {StyleSheet, View} from 'react-native'; + +const styles = StyleSheet.create({ + root: { + flexDirection: 'row', + justifyContent: 'space-around', + paddingTop: 20, + }, + box: { + width: 80, + height: 80, + }, +}); + +const listenedEvents = ['pointerDown', 'pointerUp']; + +const expectedOrder = [ + ['red', 'pointerDown', true], + ['green', 'pointerDown', false], + ['red', 'pointerUp', true], + ['blue', 'pointerDown', true], + ['green', 'pointerUp', false], + ['blue', 'pointerUp', true], +]; + +function PointerEventPrimaryTouchPointerTestCase( + props: PlatformTestComponentBaseProps, +) { + const {harness} = props; + + const detected_eventsRef = useRef({}); + + const handleIncomingPointerEvent = useCallback( + (boxLabel: string, eventType: string, isPrimary: boolean) => { + const detected_events = detected_eventsRef.current; + + const pointerEventIdentifier = `${boxLabel}-${eventType}-${String( + isPrimary, + )}`; + if (detected_events[pointerEventIdentifier]) { + return; + } + + const [expectedBoxLabel, expectedEventType, expectedIsPrimary] = + expectedOrder[Object.keys(detected_events).length]; + detected_events[pointerEventIdentifier] = true; + + harness.test(({assert_equals}) => { + assert_equals( + boxLabel, + expectedBoxLabel, + 'event should be coming from the correct box', + ); + assert_equals( + eventType, + expectedEventType.toLowerCase(), + 'event should have the right type', + ); + assert_equals( + isPrimary, + expectedIsPrimary, + 'event should be correctly primary', + ); + }, `${expectedBoxLabel} box's ${expectedEventType} should${!expectedIsPrimary ? ' not' : ''} be marked as the primary pointer`); + }, + [harness], + ); + + const createBoxHandler = useCallback( + (boxLabel: string) => (event: PointerEvent, eventName: string) => { + if ( + Object.keys(detected_eventsRef.current).length < expectedOrder.length + ) { + handleIncomingPointerEvent( + boxLabel, + eventName, + event.nativeEvent.isPrimary, + ); + } + }, + [handleIncomingPointerEvent], + ); + + const {handleBoxAEvent, handleBoxBEvent, handleBoxCEvent} = useMemo( + () => ({ + handleBoxAEvent: createBoxHandler('red'), + handleBoxBEvent: createBoxHandler('green'), + handleBoxCEvent: createBoxHandler('blue'), + }), + [createBoxHandler], + ); + + const boxAHandlers = useTestEventHandler(listenedEvents, handleBoxAEvent); + const boxBHandlers = useTestEventHandler(listenedEvents, handleBoxBEvent); + const boxCHandlers = useTestEventHandler(listenedEvents, handleBoxCEvent); + + return ( + + + + + + ); +} + +type Props = $ReadOnly<{}>; +export default function PointerEventPrimaryTouchPointer( + props: Props, +): React.MixedElement { + return ( + + ); +} diff --git a/packages/rn-tester/js/examples/Experimental/W3CPointerEventsExample.js b/packages/rn-tester/js/examples/Experimental/W3CPointerEventsExample.js index 0e1745d25045..2663e95fb227 100644 --- a/packages/rn-tester/js/examples/Experimental/W3CPointerEventsExample.js +++ b/packages/rn-tester/js/examples/Experimental/W3CPointerEventsExample.js @@ -16,6 +16,7 @@ import type {ViewProps} from 'react-native/Libraries/Components/View/ViewPropTyp import PointerEventAttributesHoverablePointers from './W3CPointerEventPlatformTests/PointerEventAttributesHoverablePointers'; import PointerEventPointerMove from './W3CPointerEventPlatformTests/PointerEventPointerMove'; import CompatibilityAnimatedPointerMove from './Compatibility/CompatibilityAnimatedPointerMove'; +import PointerEventPrimaryTouchPointer from './W3CPointerEventPlatformTests/PointerEventPrimaryTouchPointer'; function EventfulView(props: {| name: string, @@ -247,6 +248,14 @@ export default { return ; }, }, + { + name: 'pointerevent_primary_touch_pointer', + description: '', + title: 'Pointer Event primary touch pointer test', + render(): React.Node { + return ; + }, + }, CompatibilityAnimatedPointerMove, ], }; From 547220fee47478666298bba51d75f6e65cb5de9b Mon Sep 17 00:00:00 2001 From: Christoph Purrer Date: Tue, 26 Jul 2022 12:01:16 -0700 Subject: [PATCH 0059/1165] Avoid sharing mutable attributed string across threads in RCTBaseTextInputShadowView Summary: The `NSMutableAttributedString` was initialized with the same backing store as the cached attributed string on the shadow queue (background thread), but then passed to the main thread and ultimately the JS thread. This explicitly copies the mutable attributed string into an immutable one on the shadow thread before passed off to other threads, which hopefully will address the `convertIdToFollyDynamic` crash that always includes `RCTBaseTextInputShadowView` touching an attributed string on the shadow queue in the trace. Changelog: [iOS][Fixed] - Possible fix for convertIdToFollyDynamic crash in RCTBaseTextInputView and RCTEventDispatcher Reviewed By: sammy-SC Differential Revision: D38133150 fbshipit-source-id: f371da5d17a32c3341287cd3e9730b31a98495f9 --- .../Text/TextInput/RCTBaseTextInputShadowView.m | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/Libraries/Text/TextInput/RCTBaseTextInputShadowView.m b/Libraries/Text/TextInput/RCTBaseTextInputShadowView.m index 19d202cb3494..bc480aa04999 100644 --- a/Libraries/Text/TextInput/RCTBaseTextInputShadowView.m +++ b/Libraries/Text/TextInput/RCTBaseTextInputShadowView.m @@ -144,8 +144,7 @@ - (void)uiManagerWillPerformMounting RCTTextAttributes *textAttributes = [self.textAttributes copy]; - NSMutableAttributedString *attributedText = - [[NSMutableAttributedString alloc] initWithAttributedString:[self attributedTextWithBaseTextAttributes:nil]]; + NSMutableAttributedString *attributedText = [[self attributedTextWithBaseTextAttributes:nil] mutableCopy]; // Removing all references to Shadow Views and tags to avoid unnecessary retaining // and problems with comparing the strings. @@ -162,13 +161,13 @@ - (void)uiManagerWillPerformMounting [attributedText insertAttributedString:propertyAttributedText atIndex:0]; } - BOOL isAttributedTextChanged = NO; + NSAttributedString *newAttributedText; if (![_previousAttributedText isEqualToAttributedString:attributedText]) { // We have to follow `set prop` pattern: // If the value has not changed, we must not notify the view about the change, // otherwise we may break local (temporary) state of the text input. - isAttributedTextChanged = YES; - _previousAttributedText = [attributedText copy]; + newAttributedText = [attributedText copy]; + _previousAttributedText = newAttributedText; } NSNumber *tag = self.reactTag; @@ -183,10 +182,10 @@ - (void)uiManagerWillPerformMounting baseTextInputView.reactBorderInsets = borderInsets; baseTextInputView.reactPaddingInsets = paddingInsets; - if (isAttributedTextChanged) { + if (newAttributedText) { // Don't set `attributedText` if length equal to zero, otherwise it would shrink when attributes contain like `lineHeight`. - if (attributedText.length != 0) { - baseTextInputView.attributedText = attributedText; + if (newAttributedText.length != 0) { + baseTextInputView.attributedText = newAttributedText; } else { baseTextInputView.attributedText = nil; } From f1d624823fe23eb3d30de00cf78beb71dc1b8413 Mon Sep 17 00:00:00 2001 From: Lorenzo Sciandra Date: Tue, 26 Jul 2022 17:31:18 -0700 Subject: [PATCH 0060/1165] bump CLI to v9.0.0-alpha.5 (#34275) Summary: Bumping main to latest version of CLI available; in particular, we want to ensure to propagate this fix https://github.com/react-native-community/cli/pull/1655. After merging, we'll cherry-pick in the `0.70-stable` branch. ## Changelog [General] [Changed] - bump CLI to v9.0.0-alpha.5 Pull Request resolved: https://github.com/facebook/react-native/pull/34275 Test Plan: CI Reviewed By: NickGerleman Differential Revision: D38151383 Pulled By: dmitryrykun fbshipit-source-id: afdafb496a159ad766dd322a4aab4bda6146edf0 --- package.json | 6 +- yarn.lock | 721 +++++++++++++++++---------------------------------- 2 files changed, 245 insertions(+), 482 deletions(-) diff --git a/package.json b/package.json index bf0ecc57ca7f..aa9ba2818296 100644 --- a/package.json +++ b/package.json @@ -104,9 +104,9 @@ }, "dependencies": { "@jest/create-cache-key-function": "^27.0.1", - "@react-native-community/cli": "^9.0.0-alpha.3", - "@react-native-community/cli-platform-android": "^9.0.0-alpha.3", - "@react-native-community/cli-platform-ios": "^9.0.0-alpha.3", + "@react-native-community/cli": "^9.0.0-alpha.5", + "@react-native-community/cli-platform-android": "^9.0.0-alpha.5", + "@react-native-community/cli-platform-ios": "^9.0.0-alpha.5", "@react-native/assets": "1.0.0", "@react-native/normalize-color": "2.0.0", "@react-native/polyfills": "2.0.0", diff --git a/yarn.lock b/yarn.lock index 4d30f85bd10c..135a809bd0fc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -738,14 +738,7 @@ core-js-pure "^3.19.0" regenerator-runtime "^0.13.4" -"@babel/runtime@^7.0.0", "@babel/runtime@^7.10.2", "@babel/runtime@^7.8.4": - version "7.17.9" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.9.tgz#d19fbf802d01a8cb6cf053a64e472d42c434ba72" - integrity sha512-lSiBBvodq29uShpWGNbgFdKYNiFDo5/HIYsaCEY9ff4sb10x9jizo2+pRrSyF4jKZCXqgzuqBOQKbUm90gQwJg== - dependencies: - regenerator-runtime "^0.13.4" - -"@babel/runtime@^7.18.3": +"@babel/runtime@^7.0.0", "@babel/runtime@^7.10.2", "@babel/runtime@^7.18.3", "@babel/runtime@^7.8.4": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.18.6.tgz#6a1ef59f838debd670421f8c7f2cbb8da9751580" integrity sha512-t9wi7/AW6XtKahAe20Yw0/mMljKq0B1r2fPdvaAdV/KPDZewFXdaaa6K7lxmZBZ8FBNpCiAT6iHPmd6QO9bKfQ== @@ -1042,10 +1035,10 @@ "@types/yargs" "^15.0.0" chalk "^4.0.0" -"@jest/types@^27.0.1", "@jest/types@^27.4.2": - version "27.4.2" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-27.4.2.tgz#96536ebd34da6392c2b7c7737d693885b5dd44a5" - integrity sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg== +"@jest/types@^27.0.1", "@jest/types@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-27.5.1.tgz#3c79ec4a8ba61c170bf937bcf9e98a9df175ec80" + integrity sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw== dependencies: "@types/istanbul-lib-coverage" "^2.0.0" "@types/istanbul-reports" "^3.0.0" @@ -1087,42 +1080,42 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@react-native-community/cli-clean@^9.0.0-alpha.3": - version "9.0.0-alpha.3" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-clean/-/cli-clean-9.0.0-alpha.3.tgz#d3cbd491c40cb23d933a221ed8e2481cb42efdda" - integrity sha512-djo73BdQ+O+KhsPGwfT9vZvWfkXyQLu2B31r9alOhREganoMMv2AogBIMQbRP0F/FLC3Ker/EzgJkuyqDUK28Q== +"@react-native-community/cli-clean@^9.0.0-alpha.5": + version "9.0.0-alpha.5" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-clean/-/cli-clean-9.0.0-alpha.5.tgz#db101bdd5ff56e7c75797a385d51c5d1c0786dc4" + integrity sha512-ML/80mmSMi+x1r2nkGas19bk/956cNewSEmKSTv0L/dHTlzxuPdbrvrRw6st4MY7LtZtJ+duulPdD4+obyHuNg== dependencies: - "@react-native-community/cli-tools" "^9.0.0-alpha.3" + "@react-native-community/cli-tools" "^9.0.0-alpha.5" chalk "^4.1.2" execa "^1.0.0" prompts "^2.4.0" -"@react-native-community/cli-config@^9.0.0-alpha.3": - version "9.0.0-alpha.3" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-config/-/cli-config-9.0.0-alpha.3.tgz#00bcebd691984120f970cb563511562da424bb1e" - integrity sha512-Eh2zX9hx1vp5nY6UMvATNiqs424i2eTBxewSr3Tp03esn83mdJlah0r70/rdPSAeU77Hp7KtibG82NxPwH8abg== +"@react-native-community/cli-config@^9.0.0-alpha.5": + version "9.0.0-alpha.5" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-config/-/cli-config-9.0.0-alpha.5.tgz#7a8d48a493c44dd0e9b9d808de9914af4ffd4c90" + integrity sha512-6m4FGPfYsTeg9z+PZ7PBFBkQ2oHNDsyCdyvjO/jOC7QB2wboe39oRYOnGy+TqYMyT0jJEOceTcxUsG2q2b1vwQ== dependencies: - "@react-native-community/cli-tools" "^9.0.0-alpha.3" + "@react-native-community/cli-tools" "^9.0.0-alpha.5" cosmiconfig "^5.1.0" deepmerge "^3.2.0" glob "^7.1.3" joi "^17.2.1" -"@react-native-community/cli-debugger-ui@^8.0.0": - version "8.0.0" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-debugger-ui/-/cli-debugger-ui-8.0.0.tgz#98263dc525e65015e2d6392c940114028f87e8e9" - integrity sha512-u2jq06GZwZ9sRERzd9FIgpW6yv4YOW4zz7Ym/B8eSzviLmy3yI/8mxJtvlGW+J8lBsfMcQoqJpqI6Rl1nZy9yQ== +"@react-native-community/cli-debugger-ui@^9.0.0-alpha.4": + version "9.0.0-alpha.4" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-debugger-ui/-/cli-debugger-ui-9.0.0-alpha.4.tgz#700d04b6020ba609e4b381dd4c9c9aee4147711e" + integrity sha512-UD4X2dRb26JB6elQjogkzx22EXj4VlRSE8q5O7zQDs7miEi+LEjfucs9N3U6pHmtMqan2D9VO8HVV2tBDhB2wA== dependencies: serve-static "^1.13.1" -"@react-native-community/cli-doctor@^9.0.0-alpha.3": - version "9.0.0-alpha.3" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-doctor/-/cli-doctor-9.0.0-alpha.3.tgz#8e9bdccfd7b326199f5814e8e755ad615cdfb17b" - integrity sha512-iriyxzBVnadJBglcxrmUsjsJr+bpr1MafyeBp0ZuvOglZ7SNMbb3Q9dNhoS/2sYQ/1WQeWR92r8Zb0f6eSMFTA== +"@react-native-community/cli-doctor@^9.0.0-alpha.5": + version "9.0.0-alpha.5" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-doctor/-/cli-doctor-9.0.0-alpha.5.tgz#9be8217d9d9e9d437fd4705bcb1410ef5a4d2b75" + integrity sha512-IM9Rwc9cGjpE1haUY86AJ3gYPHkFhUwt0Oxk3XqP8bD+nhKKx6YOQx6J9Wl0EhpM5lnyoCj4mls2LVWPZ6lQpQ== dependencies: - "@react-native-community/cli-config" "^9.0.0-alpha.3" - "@react-native-community/cli-platform-ios" "^9.0.0-alpha.3" - "@react-native-community/cli-tools" "^9.0.0-alpha.3" + "@react-native-community/cli-config" "^9.0.0-alpha.5" + "@react-native-community/cli-platform-ios" "^9.0.0-alpha.5" + "@react-native-community/cli-tools" "^9.0.0-alpha.5" chalk "^4.1.2" command-exists "^1.2.8" envinfo "^7.7.2" @@ -1137,23 +1130,23 @@ sudo-prompt "^9.0.0" wcwidth "^1.0.1" -"@react-native-community/cli-hermes@^9.0.0-alpha.3": - version "9.0.0-alpha.3" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-hermes/-/cli-hermes-9.0.0-alpha.3.tgz#cbed6ac366944bf12f83b7a6a567661c0dde3a57" - integrity sha512-uHLeB6OvGYcPtL0/Qar/ae9xlP0yquzmwznm6XHAoMZe0aUmlaiHEE/TSjnLN2jvHqDxr9B/C/X/KZWADol+IA== +"@react-native-community/cli-hermes@^9.0.0-alpha.5": + version "9.0.0-alpha.5" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-hermes/-/cli-hermes-9.0.0-alpha.5.tgz#0675083be64348d0a10043b07ce8820336729e47" + integrity sha512-PKuT14qmjBm2YTDGyTp/pWk7azq5RzULCiGh0b0Q4FAFjMSTcV9I1AWu4pahn46H78G4H0cU4qSApV1z5hy/nw== dependencies: - "@react-native-community/cli-platform-android" "^9.0.0-alpha.3" - "@react-native-community/cli-tools" "^9.0.0-alpha.3" + "@react-native-community/cli-platform-android" "^9.0.0-alpha.5" + "@react-native-community/cli-tools" "^9.0.0-alpha.5" chalk "^4.1.2" hermes-profile-transformer "^0.0.6" ip "^1.1.5" -"@react-native-community/cli-platform-android@^9.0.0-alpha.3": - version "9.0.0-alpha.3" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-platform-android/-/cli-platform-android-9.0.0-alpha.3.tgz#c66ce62f2d371bd6e8cdf5e66101e20c0d486d5a" - integrity sha512-yBNre6AfSJ1qvM8jwI/MFBS6s6hkK01cB2pKVNk1TOn9zj4lrd3ASocpLQt4C6jp1v37hZi9S4C7xM9zCT0FCw== +"@react-native-community/cli-platform-android@^9.0.0-alpha.5": + version "9.0.0-alpha.5" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-platform-android/-/cli-platform-android-9.0.0-alpha.5.tgz#2713cbe90bb8f4e45edd8676d0b0a544d1f03b4f" + integrity sha512-ZnYC9HR9QurwjN84vmBajk8krHsoKLrgILGnSYtMJzQl70oTV4mxl33VDPBJ5JjV8jiWiACGw2NaOUOOw5zqbQ== dependencies: - "@react-native-community/cli-tools" "^9.0.0-alpha.3" + "@react-native-community/cli-tools" "^9.0.0-alpha.5" chalk "^4.1.2" execa "^1.0.0" fs-extra "^8.1.0" @@ -1163,12 +1156,12 @@ logkitty "^0.7.1" slash "^3.0.0" -"@react-native-community/cli-platform-ios@^9.0.0-alpha.3": - version "9.0.0-alpha.3" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-platform-ios/-/cli-platform-ios-9.0.0-alpha.3.tgz#f6e5400f2144f9e3a9a618e8f23a4ff622356638" - integrity sha512-EYycuZ2deeccRHPaxasnxUMxrv0gRSAqCcmQYkX0Wbvh236JWHiIMc6QhMInmcd79GZi+v9ByRiQ+lqk2LXfGA== +"@react-native-community/cli-platform-ios@^9.0.0-alpha.5": + version "9.0.0-alpha.5" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-platform-ios/-/cli-platform-ios-9.0.0-alpha.5.tgz#7b1fa6ac098c942e0aa0d167078f019d94e1cb42" + integrity sha512-MFeZgQpZIQVBqoOA1tt2/VUaT6BsxS3lBjVK8R8I32DW/lq1zjnNDsR5vDprVXsyMgfkvIrt2/oeXK/rn/QHLg== dependencies: - "@react-native-community/cli-tools" "^9.0.0-alpha.3" + "@react-native-community/cli-tools" "^9.0.0-alpha.5" chalk "^4.1.2" execa "^1.0.0" glob "^7.1.3" @@ -1177,29 +1170,29 @@ ora "^5.4.1" plist "^3.0.2" -"@react-native-community/cli-plugin-metro@^9.0.0-alpha.3": - version "9.0.0-alpha.3" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-plugin-metro/-/cli-plugin-metro-9.0.0-alpha.3.tgz#a068d64e5f95d5affd4a5e22bca988f1a76bb001" - integrity sha512-IBOairc/gu7F13DK2trRKZ0GMZ7wU0ux8GGtkl2thCzeif2TG1mrdZfZkulYCGkKtEIJg43SjfsJyYe4oeh0VQ== +"@react-native-community/cli-plugin-metro@^9.0.0-alpha.5": + version "9.0.0-alpha.5" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-plugin-metro/-/cli-plugin-metro-9.0.0-alpha.5.tgz#ab5ba5bd54d90298dd85c3a52b3935e5fea442eb" + integrity sha512-3/FnnK2/AePMZxnTWNFugfxfTq1mXznmp3XlCPZo7M3m1PTiV+0HU0f+zDOmh1D0agvIy5UUnx+i1qcpW2B83Q== dependencies: - "@react-native-community/cli-server-api" "^9.0.0-alpha.3" - "@react-native-community/cli-tools" "^9.0.0-alpha.3" + "@react-native-community/cli-server-api" "^9.0.0-alpha.5" + "@react-native-community/cli-tools" "^9.0.0-alpha.5" chalk "^4.1.2" - metro "^0.70.1" - metro-config "^0.70.1" - metro-core "^0.70.1" - metro-react-native-babel-transformer "^0.70.1" - metro-resolver "^0.70.1" - metro-runtime "^0.70.1" + metro "^0.71.3" + metro-config "^0.71.3" + metro-core "^0.71.3" + metro-react-native-babel-transformer "^0.71.3" + metro-resolver "^0.71.3" + metro-runtime "^0.71.3" readline "^1.3.0" -"@react-native-community/cli-server-api@^9.0.0-alpha.3": - version "9.0.0-alpha.3" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-server-api/-/cli-server-api-9.0.0-alpha.3.tgz#ca39aa1494a71b0aa36494806a898014233473ee" - integrity sha512-iusGOqtWhnXUwIgLdMq821V03okOm7jDVwPYW8aQd6qpX1l2oTa15kubSMNYtBCZ3bAjYRTXPJp4WNpiLDPKQA== +"@react-native-community/cli-server-api@^9.0.0-alpha.5": + version "9.0.0-alpha.5" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-server-api/-/cli-server-api-9.0.0-alpha.5.tgz#764dee34dd5ab5afb39406491412fb8d2b00d85d" + integrity sha512-74z9fkcnwrSSxNEKKlNdFJqDDytdzaNHq/9hPCuXi24cK5yyuL8E79Ku7sBva3tKEIVzWKdFsWJqzB7QIkBk1Q== dependencies: - "@react-native-community/cli-debugger-ui" "^8.0.0" - "@react-native-community/cli-tools" "^9.0.0-alpha.3" + "@react-native-community/cli-debugger-ui" "^9.0.0-alpha.4" + "@react-native-community/cli-tools" "^9.0.0-alpha.5" compression "^1.7.1" connect "^3.6.5" errorhandler "^1.5.0" @@ -1208,13 +1201,14 @@ serve-static "^1.13.1" ws "^7.5.1" -"@react-native-community/cli-tools@^9.0.0-alpha.3": - version "9.0.0-alpha.3" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-tools/-/cli-tools-9.0.0-alpha.3.tgz#a6d3b96b0f680926c391ae6dec67f50dbd9d019b" - integrity sha512-yW908uJNGYXxO9fYOx3KMGIkDaW83BkxPeUCMRJ65DrVGy6KGaclWCwPqp1iWBmiqwCVRXwQbeRyQ+mYU1nc8w== +"@react-native-community/cli-tools@^9.0.0-alpha.5": + version "9.0.0-alpha.5" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-tools/-/cli-tools-9.0.0-alpha.5.tgz#693956fcf6d96112f3034de6c138f13fd806b68c" + integrity sha512-Sm8mxLLQ2Hh1hMwbmWJj1yA55tfdE5Ep7x4z/JWdAURs9UmUkaiKvH+9XPMqPBZgiSLhUitT2NwDuQDjnHGCVQ== dependencies: appdirsjs "^1.2.4" chalk "^4.1.2" + find-up "^5.0.0" lodash "^4.17.15" mime "^2.4.1" node-fetch "^2.6.0" @@ -1230,19 +1224,19 @@ dependencies: joi "^17.2.1" -"@react-native-community/cli@^9.0.0-alpha.3": - version "9.0.0-alpha.3" - resolved "https://registry.yarnpkg.com/@react-native-community/cli/-/cli-9.0.0-alpha.3.tgz#794cfa5828fff8cea305830ac8ba5fcb68aebb51" - integrity sha512-XAMlrQGK6BVDTl9X2tyAgyp0GPHyr6Lm2WFLStYW9wh8Vm4ja/txbEKZw1vi3NPMhB/sTBarNRtoZ65MV0JguQ== - dependencies: - "@react-native-community/cli-clean" "^9.0.0-alpha.3" - "@react-native-community/cli-config" "^9.0.0-alpha.3" - "@react-native-community/cli-debugger-ui" "^8.0.0" - "@react-native-community/cli-doctor" "^9.0.0-alpha.3" - "@react-native-community/cli-hermes" "^9.0.0-alpha.3" - "@react-native-community/cli-plugin-metro" "^9.0.0-alpha.3" - "@react-native-community/cli-server-api" "^9.0.0-alpha.3" - "@react-native-community/cli-tools" "^9.0.0-alpha.3" +"@react-native-community/cli@^9.0.0-alpha.5": + version "9.0.0-alpha.5" + resolved "https://registry.yarnpkg.com/@react-native-community/cli/-/cli-9.0.0-alpha.5.tgz#8410eb408d20da26fc9139171d4684f3d061fdb5" + integrity sha512-6ihMoYaGKjWJ/uyJLDDnckOAGJg2XVofnuG8WvOw1Sk3vnEaIQTF+PVZF2q2VSGmWLvzNZTVtY5+aBIJFvkApA== + dependencies: + "@react-native-community/cli-clean" "^9.0.0-alpha.5" + "@react-native-community/cli-config" "^9.0.0-alpha.5" + "@react-native-community/cli-debugger-ui" "^9.0.0-alpha.4" + "@react-native-community/cli-doctor" "^9.0.0-alpha.5" + "@react-native-community/cli-hermes" "^9.0.0-alpha.5" + "@react-native-community/cli-plugin-metro" "^9.0.0-alpha.5" + "@react-native-community/cli-server-api" "^9.0.0-alpha.5" + "@react-native-community/cli-tools" "^9.0.0-alpha.5" "@react-native-community/cli-types" "^9.0.0-alpha.0" chalk "^4.1.2" commander "^2.19.0" @@ -1513,12 +1507,7 @@ acorn@^7.1.1: resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== -acorn@^8.2.4: - version "8.7.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.0.tgz#90951fde0f8f09df93549481e5fc141445b791cf" - integrity sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ== - -acorn@^8.7.1: +acorn@^8.2.4, acorn@^8.7.1: version "8.7.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.1.tgz#0197122c843d1bf6d0a5e83220a788f278f63c30" integrity sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A== @@ -1642,17 +1631,6 @@ arr-union@^3.1.0: resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= -array-includes@^3.1.3: - version "3.1.4" - resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.4.tgz#f5b493162c760f3539631f005ba2bb46acb45ba9" - integrity sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.1" - get-intrinsic "^1.1.1" - is-string "^1.0.7" - array-includes@^3.1.5: version "3.1.5" resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.5.tgz#2c320010db8d31031fd2a5f6b3bbd4b1aad31bdb" @@ -2429,14 +2407,7 @@ debug@2.6.9, debug@^2.2.0, debug@^2.3.3: dependencies: ms "2.0.0" -debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.2: - version "4.3.3" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" - integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== - dependencies: - ms "2.1.2" - -debug@^4.3.4: +debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.4: version "4.3.4" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== @@ -2480,14 +2451,7 @@ defaults@^1.0.3: dependencies: clone "^1.0.2" -define-properties@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" - integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== - dependencies: - object-keys "^1.0.12" - -define-properties@^1.1.4: +define-properties@^1.1.3, define-properties@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.4.tgz#0b14d7bd7fbeb2f3572c3a7eda80ea5d57fb05b1" integrity sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA== @@ -2647,33 +2611,7 @@ errorhandler@^1.5.0: accepts "~1.3.3" escape-html "~1.0.3" -es-abstract@^1.19.0, es-abstract@^1.19.1: - version "1.19.1" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.19.1.tgz#d4885796876916959de78edaa0df456627115ec3" - integrity sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w== - dependencies: - call-bind "^1.0.2" - es-to-primitive "^1.2.1" - function-bind "^1.1.1" - get-intrinsic "^1.1.1" - get-symbol-description "^1.0.0" - has "^1.0.3" - has-symbols "^1.0.2" - internal-slot "^1.0.3" - is-callable "^1.2.4" - is-negative-zero "^2.0.1" - is-regex "^1.1.4" - is-shared-array-buffer "^1.0.1" - is-string "^1.0.7" - is-weakref "^1.0.1" - object-inspect "^1.11.0" - object-keys "^1.1.1" - object.assign "^4.1.2" - string.prototype.trimend "^1.0.4" - string.prototype.trimstart "^1.0.4" - unbox-primitive "^1.0.1" - -es-abstract@^1.19.2, es-abstract@^1.19.5: +es-abstract@^1.19.0, es-abstract@^1.19.1, es-abstract@^1.19.2, es-abstract@^1.19.5: version "1.20.1" resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.20.1.tgz#027292cd6ef44bd12b1913b828116f54787d1814" integrity sha512-WEm2oBhfoI2sImeM4OF2zE2V3BYdSF+KnSi9Sidz51fQHd7+JuF8Xgcj9/0o+OWeIeIS/MiuNnlruQrJf16GQA== @@ -2973,12 +2911,7 @@ estraverse@^4.1.1: resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" integrity sha1-De4/7TH81GlhjOc0IJn8GvoL2xM= -estraverse@^5.1.0, estraverse@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.2.0.tgz#307df42547e6cc7324d3cf03c155d5cdb8c53880" - integrity sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ== - -estraverse@^5.3.0: +estraverse@^5.1.0, estraverse@^5.2.0, estraverse@^5.3.0: version "5.3.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== @@ -3227,6 +3160,14 @@ find-up@^4.0.0, find-up@^4.1.0: locate-path "^5.0.0" path-exists "^4.0.0" +find-up@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + flat-cache@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" @@ -3318,7 +3259,7 @@ fs.realpath@^1.0.0: resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= -fsevents@^2.1.2, fsevents@^2.3.2: +fsevents@^2.1.2: version "2.3.2" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== @@ -3456,10 +3397,10 @@ globby@^11.1.0: merge2 "^1.4.1" slash "^3.0.0" -graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.3, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@^4.2.0, graceful-fs@^4.2.4: - version "4.2.4" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb" - integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw== +graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.3, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@^4.2.0, graceful-fs@^4.2.4, graceful-fs@^4.2.9: + version "4.2.10" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" + integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== "graphql@^14.0.0 || ^15.0.0": version "15.7.2" @@ -3484,12 +3425,7 @@ har-validator@~5.1.3: ajv "^6.12.3" har-schema "^2.0.0" -has-bigints@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.1.tgz#64fe6acb020673e3b78db035a5af69aa9d07b113" - integrity sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA== - -has-bigints@^1.0.2: +has-bigints@^1.0.1, has-bigints@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ== @@ -3511,12 +3447,7 @@ has-property-descriptors@^1.0.0: dependencies: get-intrinsic "^1.1.1" -has-symbols@^1.0.1, has-symbols@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.2.tgz#165d3070c00309752a1236a479331e3ac56f1423" - integrity sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw== - -has-symbols@^1.0.3: +has-symbols@^1.0.1, has-symbols@^1.0.2, has-symbols@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== @@ -3575,23 +3506,11 @@ hermes-eslint@0.8.0: hermes-estree "0.8.0" hermes-parser "0.8.0" -hermes-estree@0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/hermes-estree/-/hermes-estree-0.6.0.tgz#e866fddae1b80aec65fe2ae450a5f2070ad54033" - integrity sha512-2YTGzJCkhdmT6VuNprWjXnvTvw/3iPNw804oc7yknvQpNKo+vJGZmtvLLCghOZf0OwzKaNAzeIMp71zQbNl09w== - hermes-estree@0.8.0: version "0.8.0" resolved "https://registry.yarnpkg.com/hermes-estree/-/hermes-estree-0.8.0.tgz#530be27243ca49f008381c1f3e8b18fb26bf9ec0" integrity sha512-W6JDAOLZ5pMPMjEiQGLCXSSV7pIBEgRR5zGkxgmzGSXHOxqV5dC/M1Zevqpbm9TZDE5tu358qZf8Vkzmsc+u7Q== -hermes-parser@0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/hermes-parser/-/hermes-parser-0.6.0.tgz#00d14e91bca830b3c1457050fa4187400cb96328" - integrity sha512-Vf58jBZca2+QBLR9h7B7mdg8oFz2g5ILz1iVouZ5DOrOrAfBmPfJjdjDT8jrO0f+iJ4/hSRrQHqHIjSnTaLUDQ== - dependencies: - hermes-estree "0.6.0" - hermes-parser@0.8.0: version "0.8.0" resolved "https://registry.yarnpkg.com/hermes-parser/-/hermes-parser-0.8.0.tgz#116dceaba32e45b16d6aefb5c4c830eaeba2d257" @@ -3676,12 +3595,7 @@ ieee754@^1.1.13: resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== -ignore@^5.0.5: - version "5.1.9" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.9.tgz#9ec1a5cbe8e1446ec60d4420060d43aa6e7382fb" - integrity sha512-2zeMQpbKz5dhZ9IwL0gbxSW5w0NK/MSAMtNuhgIHEPmaU3vPdKPL0UdvUCXs5SS4JAwsBxysK5sFMW8ocFiVjQ== - -ignore@^5.2.0: +ignore@^5.0.5, ignore@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== @@ -3932,11 +3846,6 @@ is-interactive@^1.0.0: resolved "https://registry.yarnpkg.com/is-interactive/-/is-interactive-1.0.0.tgz#cea6e6ae5c870a7b0a0004070b7b587e0252912e" integrity sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w== -is-negative-zero@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.1.tgz#3de746c18dda2319241a53675908d8f766f11c24" - integrity sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w== - is-negative-zero@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" @@ -3981,11 +3890,6 @@ is-regex@^1.1.4: call-bind "^1.0.2" has-tostringtag "^1.0.0" -is-shared-array-buffer@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz#97b0c85fbdacb59c9c446fe653b82cf2b5b7cfe6" - integrity sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA== - is-shared-array-buffer@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79" @@ -4027,13 +3931,6 @@ is-unicode-supported@^0.1.0: resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== -is-weakref@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.1.tgz#842dba4ec17fa9ac9850df2d6efbc1737274f2a2" - integrity sha512-b2jKc2pQZjaeFYWEf7ScFj+Be1I+PXmlu572Q8coTXZ+LD/QQZ7ShPMst8h16riVgyXTQwUsFEl74mDvc/3MHQ== - dependencies: - call-bind "^1.0.0" - is-weakref@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" @@ -4273,26 +4170,6 @@ jest-haste-map@^26.6.2: optionalDependencies: fsevents "^2.1.2" -jest-haste-map@^27.3.1: - version "27.4.6" - resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-27.4.6.tgz#c60b5233a34ca0520f325b7e2cc0a0140ad0862a" - integrity sha512-0tNpgxg7BKurZeFkIOvGCkbmOHbLFf4LUQOxrQSMjvrQaQe3l6E8x6jYC1NuWkGo5WDdbr8FEzUxV2+LWNawKQ== - dependencies: - "@jest/types" "^27.4.2" - "@types/graceful-fs" "^4.1.2" - "@types/node" "*" - anymatch "^3.0.3" - fb-watchman "^2.0.0" - graceful-fs "^4.2.4" - jest-regex-util "^27.4.0" - jest-serializer "^27.4.0" - jest-util "^27.4.2" - jest-worker "^27.4.6" - micromatch "^4.0.4" - walker "^1.0.7" - optionalDependencies: - fsevents "^2.3.2" - jest-jasmine2@^26.6.3: version "26.6.3" resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-26.6.3.tgz#adc3cf915deacb5212c93b9f3547cd12958f2edd" @@ -4379,10 +4256,10 @@ jest-regex-util@^26.0.0: resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-26.0.0.tgz#d25e7184b36e39fd466c3bc41be0971e821fee28" integrity sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A== -jest-regex-util@^27.4.0: - version "27.4.0" - resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-27.4.0.tgz#e4c45b52653128843d07ad94aec34393ea14fbca" - integrity sha512-WeCpMpNnqJYMQoOjm1nTtsgbR4XHAk1u00qDoNBQoykM280+/TmgA5Qh5giC1ecy6a5d4hbSsHzpBtu5yvlbEg== +jest-regex-util@^27.0.6: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-27.5.1.tgz#4da143f7e9fd1e542d4aa69617b38e4a78365b95" + integrity sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg== jest-resolve-dependencies@^26.6.3: version "26.6.3" @@ -4474,13 +4351,13 @@ jest-serializer@^26.6.2: "@types/node" "*" graceful-fs "^4.2.4" -jest-serializer@^27.4.0: - version "27.4.0" - resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-27.4.0.tgz#34866586e1cae2388b7d12ffa2c7819edef5958a" - integrity sha512-RDhpcn5f1JYTX2pvJAGDcnsNTnsV9bjYPU8xcV+xPwOXnUPOQwf4ZEuiU6G9H1UztH+OapMgu/ckEVwO87PwnQ== +jest-serializer@^27.0.6: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-27.5.1.tgz#81438410a30ea66fd57ff730835123dea1fb1f64" + integrity sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w== dependencies: "@types/node" "*" - graceful-fs "^4.2.4" + graceful-fs "^4.2.9" jest-snapshot@^26.6.2: version "26.6.2" @@ -4516,16 +4393,16 @@ jest-util@^26.6.2: is-ci "^2.0.0" micromatch "^4.0.2" -jest-util@^27.4.2: - version "27.4.2" - resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-27.4.2.tgz#ed95b05b1adfd761e2cda47e0144c6a58e05a621" - integrity sha512-YuxxpXU6nlMan9qyLuxHaMMOzXAl5aGZWCSzben5DhLHemYQxCc4YK+4L3ZrCutT8GPQ+ui9k5D8rUJoDioMnA== +jest-util@^27.2.0: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-27.5.1.tgz#3ba9771e8e31a0b85da48fe0b0891fb86c01c2f9" + integrity sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw== dependencies: - "@jest/types" "^27.4.2" + "@jest/types" "^27.5.1" "@types/node" "*" chalk "^4.0.0" ci-info "^3.2.0" - graceful-fs "^4.2.4" + graceful-fs "^4.2.9" picomatch "^2.2.3" jest-validate@^24.9.0: @@ -4574,7 +4451,7 @@ jest-worker@^26.6.2: merge-stream "^2.0.0" supports-color "^7.0.0" -jest-worker@^27.2.0, jest-worker@^27.4.6: +jest-worker@^27.2.0: version "27.5.1" resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.5.1.tgz#8d146f0900e8973b106b6f73cc1e9a8cb86f8db0" integrity sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg== @@ -4767,15 +4644,7 @@ jsprim@^1.2.2: json-schema "0.4.0" verror "1.10.0" -"jsx-ast-utils@^2.4.1 || ^3.0.0": - version "3.2.1" - resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.2.1.tgz#720b97bfe7d901b927d87c3773637ae8ea48781b" - integrity sha512-uP5vu8xfy2F9A6LGC22KO7e2/vGTS1MhP+18f++ZNlf0Ohaxbc9nIEwHAsejlJKyzfZzU5UIhe5ItYkitcZnZA== - dependencies: - array-includes "^3.1.3" - object.assign "^4.1.2" - -jsx-ast-utils@^3.3.1: +"jsx-ast-utils@^2.4.1 || ^3.0.0", jsx-ast-utils@^3.3.1: version "3.3.2" resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.3.2.tgz#afe5efe4332cd3515c065072bd4d6b0aa22152bd" integrity sha512-4ZCADZHRkno244xlNnn4AOG6sRQ7iBZ5BbgZ4vW4y5IZw7cVUD1PPeblm1xx/nfmMxPdt/LHsXZW8z/j58+l9Q== @@ -4877,6 +4746,13 @@ locate-path@^5.0.0: dependencies: p-locate "^4.1.0" +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + lodash.debounce@^4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" @@ -4998,16 +4874,6 @@ metro-babel-register@0.71.3: babel-plugin-replace-ts-export-assignment "^0.0.2" escape-string-regexp "^1.0.5" -metro-babel-transformer@0.70.3: - version "0.70.3" - resolved "https://registry.yarnpkg.com/metro-babel-transformer/-/metro-babel-transformer-0.70.3.tgz#dca61852be273824a4b641bd1ecafff07ff3ad1f" - integrity sha512-bWhZRMn+mIOR/s3BDpFevWScz9sV8FGktVfMlF1eJBLoX24itHDbXvTktKBYi38PWIKcHedh6THSFpJogfuwNA== - dependencies: - "@babel/core" "^7.14.0" - hermes-parser "0.6.0" - metro-source-map "0.70.3" - nullthrows "^1.1.1" - metro-babel-transformer@0.71.3: version "0.71.3" resolved "https://registry.yarnpkg.com/metro-babel-transformer/-/metro-babel-transformer-0.71.3.tgz#ca55850cc904178b740be123b77b58e81f156e4f" @@ -5018,49 +4884,68 @@ metro-babel-transformer@0.71.3: metro-source-map "0.71.3" nullthrows "^1.1.1" -metro-cache-key@0.70.3: - version "0.70.3" - resolved "https://registry.yarnpkg.com/metro-cache-key/-/metro-cache-key-0.70.3.tgz#898803db04178a8f440598afba7d82a9cf35abf7" - integrity sha512-0zpw+IcpM3hmGd5sKMdxNv3sbOIUYnMUvx1/yaM6vNRReSPmOLX0bP8fYf3CGgk8NEreZ1OHbVsuw7bdKt40Mw== +metro-cache-key@0.71.3: + version "0.71.3" + resolved "https://registry.yarnpkg.com/metro-cache-key/-/metro-cache-key-0.71.3.tgz#1f9a22476ff9ba717b296e2bcf0920ab371fab71" + integrity sha512-V7ZJaQgzsgDBlr3AjEj10UE1rnIxkiLx5StZfwwoVZ2PBe2ZWgG0yGq2dvyRtpC/8FLc/cIFbUVteLrDs1V/mg== -metro-cache@0.70.3: - version "0.70.3" - resolved "https://registry.yarnpkg.com/metro-cache/-/metro-cache-0.70.3.tgz#42cf3cdf8a7b3691f3bef9a86bed38d4c5f6201f" - integrity sha512-iCix/+z812fUqa6KlOxaTkY6LQQDoXIe/VljXkGIvpygSCmYyhjQpfQVZEVVPezFmUBYXNdabdQ6cYx6JX3yMg== +metro-cache@0.71.3: + version "0.71.3" + resolved "https://registry.yarnpkg.com/metro-cache/-/metro-cache-0.71.3.tgz#992ce0c609306025e36a7d05ed7f8a04c1e517a9" + integrity sha512-B7rHnbRnwCFpNPp//zqCpDpbLeb7NSOdFlLYGyADFbU/Bu35GlAmdf4q/PNLeDdbcLkvZaWelKMDXYWeCAn6FQ== dependencies: - metro-core "0.70.3" + metro-core "0.71.3" rimraf "^2.5.4" -metro-config@0.70.3, metro-config@^0.70.1: - version "0.70.3" - resolved "https://registry.yarnpkg.com/metro-config/-/metro-config-0.70.3.tgz#fe6f7330f679d5594e5724af7a69d4dbe1bb5bc3" - integrity sha512-SSCDjSTygoCgzoj61DdrBeJzZDRwQxUEfcgc6t6coxWSExXNR4mOngz0q4SAam49Bmjq9J2Jft6qUKnUTPrRgA== +metro-config@0.71.3, metro-config@^0.71.3: + version "0.71.3" + resolved "https://registry.yarnpkg.com/metro-config/-/metro-config-0.71.3.tgz#f876f96398fb8063a04adf68890c01f393d8b7b2" + integrity sha512-RLedw7x5GLSsDSkG2WQ59LDcna69C51/f086Ksr+Ey6fRZEjcdjzHs3dtZeJyiCylKwZL9ofr1OYrFixb/mHsg== dependencies: cosmiconfig "^5.0.5" jest-validate "^26.5.2" - metro "0.70.3" - metro-cache "0.70.3" - metro-core "0.70.3" - metro-runtime "0.70.3" + metro "0.71.3" + metro-cache "0.71.3" + metro-core "0.71.3" + metro-runtime "0.71.3" -metro-core@0.70.3, metro-core@^0.70.1: - version "0.70.3" - resolved "https://registry.yarnpkg.com/metro-core/-/metro-core-0.70.3.tgz#bf4dda15a5185f5a7931de463a1b97ac9ef680a0" - integrity sha512-NzfHB/w5R7yLaOeU1tzPTbBzCRsYSvpKJkLMP0yudszKZzIAZqNdjoEJ9GZ688Wi0ynZxcU0BxukXh4my80ZBw== +metro-core@0.71.3, metro-core@^0.71.3: + version "0.71.3" + resolved "https://registry.yarnpkg.com/metro-core/-/metro-core-0.71.3.tgz#5ffe3c4ab20c6a40d12746a538ef34e6d7ba1046" + integrity sha512-/c1X4+jsr2uxqN1p87gcwyd073apsQAy76zeD5ihDTF05IHLN6z407JuFZWi+WKhReFmdipXTjAoqzd3GZ+PwA== dependencies: - jest-haste-map "^27.3.1" lodash.throttle "^4.1.1" - metro-resolver "0.70.3" + metro-resolver "0.71.3" -metro-hermes-compiler@0.70.3: - version "0.70.3" - resolved "https://registry.yarnpkg.com/metro-hermes-compiler/-/metro-hermes-compiler-0.70.3.tgz#ac7ed656fbcf0a59adcd010d3639e4cfdbc76b4f" - integrity sha512-W6WttLi4E72JL/NyteQ84uxYOFMibe0PUr9aBKuJxxfCq6QRnJKOVcNY0NLW0He2tneXGk+8ZsNz8c0flEvYqg== +metro-file-map@0.71.3: + version "0.71.3" + resolved "https://registry.yarnpkg.com/metro-file-map/-/metro-file-map-0.71.3.tgz#6ea153574f259e84ee426240897c3764502e6acd" + integrity sha512-a4DlTkCoQsPtzMMVxsrEt0DC3/Ga+NaXueHqdGuCsY5rzjSoWDiyAdscuWjFKLSPaoPacBQpZgSo4MhjBSPYng== + dependencies: + abort-controller "^3.0.0" + anymatch "^3.0.3" + debug "^2.2.0" + fb-watchman "^2.0.0" + graceful-fs "^4.2.4" + invariant "^2.2.4" + jest-regex-util "^27.0.6" + jest-serializer "^27.0.6" + jest-util "^27.2.0" + jest-worker "^27.2.0" + micromatch "^4.0.4" + walker "^1.0.7" + optionalDependencies: + fsevents "^2.1.2" -metro-inspector-proxy@0.70.3: - version "0.70.3" - resolved "https://registry.yarnpkg.com/metro-inspector-proxy/-/metro-inspector-proxy-0.70.3.tgz#321c25b2261e76d8c4bcc39e092714adfcb50a14" - integrity sha512-qQoNdPGrmyoJSWYkxSDpTaAI8xyqVdNDVVj9KRm1PG8niSuYmrCCFGLLFsMvkVYwsCWUGHoGBx0UoAzVp14ejw== +metro-hermes-compiler@0.71.3: + version "0.71.3" + resolved "https://registry.yarnpkg.com/metro-hermes-compiler/-/metro-hermes-compiler-0.71.3.tgz#1b4c6b84e46e346b0def829493468a7577e5ee01" + integrity sha512-gqZSdUfzwcftXNwCFf/HiZhMMM7pAWQ2jMnLzIEINAp5qPxnIONvqJd5/yTnVzDjAf3kG9k1Pzt6NEsKQzuYIA== + +metro-inspector-proxy@0.71.3: + version "0.71.3" + resolved "https://registry.yarnpkg.com/metro-inspector-proxy/-/metro-inspector-proxy-0.71.3.tgz#616ba731719ac80400b9374c592b398a28af8e40" + integrity sha512-HbM2GBXcAWKtnysw8j+pK/hv20Gx6LT3lFkIr+hsIG+ejaGkOpUYAV3EBrfDuQ4bM4F8yvIT4ZWjD2Zvcm1f5Q== dependencies: connect "^3.6.5" debug "^2.2.0" @@ -5072,58 +4957,13 @@ metro-memory-fs@0.71.3: resolved "https://registry.yarnpkg.com/metro-memory-fs/-/metro-memory-fs-0.71.3.tgz#3e2f5925828df7b4444329c643564bff3a4b824b" integrity sha512-j+om4EqSDkXOGLuH9pnogPBeyJ6pJCZ7uedBIGw0v2YtanJc87ytkKIZDqOdU5SF12khaOvSwa13xRlmr+pZJQ== -metro-minify-uglify@0.70.3: - version "0.70.3" - resolved "https://registry.yarnpkg.com/metro-minify-uglify/-/metro-minify-uglify-0.70.3.tgz#2f28129ca5b8ef958f3e3fcf004c3707c7732e1e" - integrity sha512-oHyjV9WDqOlDE1FPtvs6tIjjeY/oP1PNUPYL1wqyYtqvjN+zzAOrcbsAAL1sv+WARaeiMsWkF2bwtNo+Hghoog== +metro-minify-uglify@0.71.3: + version "0.71.3" + resolved "https://registry.yarnpkg.com/metro-minify-uglify/-/metro-minify-uglify-0.71.3.tgz#cb5cc716e98dcf7fa1e261de2a7232de25e377e9" + integrity sha512-sV5IVePaqJQ1Nypf5fCJOtUtYLtZCcfcOTZvbcD1lkDTw8jZnNsTWd9s61lYg2ppXoUQu+QXfirGJI917c7bUw== dependencies: uglify-es "^3.1.9" -metro-react-native-babel-preset@0.70.3: - version "0.70.3" - resolved "https://registry.yarnpkg.com/metro-react-native-babel-preset/-/metro-react-native-babel-preset-0.70.3.tgz#1c77ec4544ecd5fb6c803e70b21284d7483e4842" - integrity sha512-4Nxc1zEiHEu+GTdEMEsHnRgfaBkg8f/Td3+FcQ8NTSvs+xL3LBrQy6N07idWSQZHIdGFf+tTHvRfSIWLD8u8Tg== - dependencies: - "@babel/core" "^7.14.0" - "@babel/plugin-proposal-async-generator-functions" "^7.0.0" - "@babel/plugin-proposal-class-properties" "^7.0.0" - "@babel/plugin-proposal-export-default-from" "^7.0.0" - "@babel/plugin-proposal-nullish-coalescing-operator" "^7.0.0" - "@babel/plugin-proposal-object-rest-spread" "^7.0.0" - "@babel/plugin-proposal-optional-catch-binding" "^7.0.0" - "@babel/plugin-proposal-optional-chaining" "^7.0.0" - "@babel/plugin-syntax-dynamic-import" "^7.0.0" - "@babel/plugin-syntax-export-default-from" "^7.0.0" - "@babel/plugin-syntax-flow" "^7.2.0" - "@babel/plugin-syntax-nullish-coalescing-operator" "^7.0.0" - "@babel/plugin-syntax-optional-chaining" "^7.0.0" - "@babel/plugin-transform-arrow-functions" "^7.0.0" - "@babel/plugin-transform-async-to-generator" "^7.0.0" - "@babel/plugin-transform-block-scoping" "^7.0.0" - "@babel/plugin-transform-classes" "^7.0.0" - "@babel/plugin-transform-computed-properties" "^7.0.0" - "@babel/plugin-transform-destructuring" "^7.0.0" - "@babel/plugin-transform-exponentiation-operator" "^7.0.0" - "@babel/plugin-transform-flow-strip-types" "^7.0.0" - "@babel/plugin-transform-function-name" "^7.0.0" - "@babel/plugin-transform-literals" "^7.0.0" - "@babel/plugin-transform-modules-commonjs" "^7.0.0" - "@babel/plugin-transform-named-capturing-groups-regex" "^7.0.0" - "@babel/plugin-transform-parameters" "^7.0.0" - "@babel/plugin-transform-react-display-name" "^7.0.0" - "@babel/plugin-transform-react-jsx" "^7.0.0" - "@babel/plugin-transform-react-jsx-self" "^7.0.0" - "@babel/plugin-transform-react-jsx-source" "^7.0.0" - "@babel/plugin-transform-runtime" "^7.0.0" - "@babel/plugin-transform-shorthand-properties" "^7.0.0" - "@babel/plugin-transform-spread" "^7.0.0" - "@babel/plugin-transform-sticky-regex" "^7.0.0" - "@babel/plugin-transform-template-literals" "^7.0.0" - "@babel/plugin-transform-typescript" "^7.5.0" - "@babel/plugin-transform-unicode-regex" "^7.0.0" - "@babel/template" "^7.0.0" - react-refresh "^0.4.0" - metro-react-native-babel-preset@0.71.3: version "0.71.3" resolved "https://registry.yarnpkg.com/metro-react-native-babel-preset/-/metro-react-native-babel-preset-0.71.3.tgz#8e30b87c39342d9ffb4ccc619e7790ac60e16929" @@ -5169,7 +5009,7 @@ metro-react-native-babel-preset@0.71.3: "@babel/template" "^7.0.0" react-refresh "^0.4.0" -metro-react-native-babel-transformer@0.71.3: +metro-react-native-babel-transformer@0.71.3, metro-react-native-babel-transformer@^0.71.3: version "0.71.3" resolved "https://registry.yarnpkg.com/metro-react-native-babel-transformer/-/metro-react-native-babel-transformer-0.71.3.tgz#7725cecffedf542fdb379fe59c1e19cf1d0f97b8" integrity sha512-DTRIldy5Dt4/+YN9DXg+9ltyk1VPZkT0d8XERQ6Ln4/uwmeEUpc1MeaA72Te9TkpznCQElAR0vhupdoaHkPcoQ== @@ -5182,54 +5022,20 @@ metro-react-native-babel-transformer@0.71.3: metro-source-map "0.71.3" nullthrows "^1.1.1" -metro-react-native-babel-transformer@^0.70.1: - version "0.70.3" - resolved "https://registry.yarnpkg.com/metro-react-native-babel-transformer/-/metro-react-native-babel-transformer-0.70.3.tgz#195597c32488f820aa9e441bbca7c04fe7de7a2d" - integrity sha512-WKBU6S/G50j9cfmFM4k4oRYprd8u3qjleD4so1E2zbTNILg+gYla7ZFGCAvi2G0ZcqS2XuGCR375c2hF6VVvwg== - dependencies: - "@babel/core" "^7.14.0" - babel-preset-fbjs "^3.4.0" - hermes-parser "0.6.0" - metro-babel-transformer "0.70.3" - metro-react-native-babel-preset "0.70.3" - metro-source-map "0.70.3" - nullthrows "^1.1.1" - -metro-resolver@0.70.3, metro-resolver@^0.70.1: - version "0.70.3" - resolved "https://registry.yarnpkg.com/metro-resolver/-/metro-resolver-0.70.3.tgz#c64fdd6d0a88fa62f3f99f87e539b5f603bd47bf" - integrity sha512-5Pc5S/Gs4RlLbziuIWtvtFd9GRoILlaRC8RZDVq5JZWcWHywKy/PjNmOBNhpyvtRlzpJfy/ssIfLhu8zINt1Mw== +metro-resolver@0.71.3, metro-resolver@^0.71.3: + version "0.71.3" + resolved "https://registry.yarnpkg.com/metro-resolver/-/metro-resolver-0.71.3.tgz#af58030209ff6176816684124c18a9250116cdb1" + integrity sha512-VeNlDVUZAKejtpV9ruZ3ivydhC2UtL6ZffYxAn1G6sPsW+B/lTywYigx32pY0xBkfkDnzul6bKOiKNe9LKW1uQ== dependencies: absolute-path "^0.0.0" -metro-runtime@0.70.3, metro-runtime@^0.70.1: - version "0.70.3" - resolved "https://registry.yarnpkg.com/metro-runtime/-/metro-runtime-0.70.3.tgz#09231b9d05dcbdfb5a13df0a45307273e6fe1168" - integrity sha512-22xU7UdXZacniTIDZgN2EYtmfau2pPyh97Dcs+cWrLcJYgfMKjWBtesnDcUAQy3PHekDYvBdJZkoQUeskYTM+w== - dependencies: - "@babel/runtime" "^7.0.0" - -metro-runtime@0.71.3: +metro-runtime@0.71.3, metro-runtime@^0.71.3: version "0.71.3" resolved "https://registry.yarnpkg.com/metro-runtime/-/metro-runtime-0.71.3.tgz#e17a3100bb61e7ea66d38f1dcaa971357572b59d" integrity sha512-1l7YYYY64wdphvPOUA3NDHVoYxuV6SEn8O6/WGGEqGj/M0focrue1ra3caoCPDUOJFWgHxh6FVaAXXTOltjNwg== dependencies: "@babel/runtime" "^7.0.0" -metro-source-map@0.70.3: - version "0.70.3" - resolved "https://registry.yarnpkg.com/metro-source-map/-/metro-source-map-0.70.3.tgz#f5976108c18d4661eaa4d188c96713e5d67a903b" - integrity sha512-zsYtZGrwRbbGEFHtmMqqeCH9K9aTGNVPsurMOWCUeQA3VGyVGXPGtLMC+CdAM9jLpUyg6jw2xh0esxi+tYH7Uw== - dependencies: - "@babel/traverse" "^7.14.0" - "@babel/types" "^7.0.0" - invariant "^2.2.4" - metro-symbolicate "0.70.3" - nullthrows "^1.1.1" - ob1 "0.70.3" - source-map "^0.5.6" - vlq "^1.0.0" - metro-source-map@0.71.3: version "0.71.3" resolved "https://registry.yarnpkg.com/metro-source-map/-/metro-source-map-0.71.3.tgz#ffbb21d3ab5a137234bcf225336283e7e669ee0b" @@ -5244,18 +5050,6 @@ metro-source-map@0.71.3: source-map "^0.5.6" vlq "^1.0.0" -metro-symbolicate@0.70.3: - version "0.70.3" - resolved "https://registry.yarnpkg.com/metro-symbolicate/-/metro-symbolicate-0.70.3.tgz#b039e5629c4ed0c999ea0496d580e1c98260f5cb" - integrity sha512-JTYkF1dpeDUssQ84juE1ycnhHki2ylJBBdJE1JHtfu5oC+z1ElDbBdPHq90Uvt8HbRov/ZAnxvv7Zy6asS+WCA== - dependencies: - invariant "^2.2.4" - metro-source-map "0.70.3" - nullthrows "^1.1.1" - source-map "^0.5.6" - through2 "^2.0.1" - vlq "^1.0.0" - metro-symbolicate@0.71.3: version "0.71.3" resolved "https://registry.yarnpkg.com/metro-symbolicate/-/metro-symbolicate-0.71.3.tgz#ba02b87742d2bed8e9a5a4cc0146ca8f6645c20b" @@ -5268,10 +5062,10 @@ metro-symbolicate@0.71.3: through2 "^2.0.1" vlq "^1.0.0" -metro-transform-plugins@0.70.3: - version "0.70.3" - resolved "https://registry.yarnpkg.com/metro-transform-plugins/-/metro-transform-plugins-0.70.3.tgz#7fe87cd0d8979b4d5d6e375751d86188fff38fd9" - integrity sha512-dQRIJoTkWZN2IVS2KzgS1hs7ZdHDX3fS3esfifPkqFAEwHiLctCf0EsPgIknp0AjMLvmGWfSLJigdRB/dc0ASw== +metro-transform-plugins@0.71.3: + version "0.71.3" + resolved "https://registry.yarnpkg.com/metro-transform-plugins/-/metro-transform-plugins-0.71.3.tgz#25798db10459533b497a66e3be0d01a0d6b731ff" + integrity sha512-Z4XeaGD0obC3dHIlLA4w7DW5enczLD1OfxUaCM92W+yYIhqn2SJDw6yzaj7CV0AWzeOxRF9itkvQHdy3X+/6Yg== dependencies: "@babel/core" "^7.14.0" "@babel/generator" "^7.14.0" @@ -5279,29 +5073,29 @@ metro-transform-plugins@0.70.3: "@babel/traverse" "^7.14.0" nullthrows "^1.1.1" -metro-transform-worker@0.70.3: - version "0.70.3" - resolved "https://registry.yarnpkg.com/metro-transform-worker/-/metro-transform-worker-0.70.3.tgz#62bfa28ebef98803531c4bcb558de5fc804c94ef" - integrity sha512-MtVVsnHhhBOp9GRLCdAb2mD1dTCsIzT4+m34KMRdBDCEbDIb90YafT5prpU8qbj5uKd0o2FOQdrJ5iy5zQilHw== +metro-transform-worker@0.71.3: + version "0.71.3" + resolved "https://registry.yarnpkg.com/metro-transform-worker/-/metro-transform-worker-0.71.3.tgz#474fa6f544891366f991a28b70d4f72f1de1cbd4" + integrity sha512-riaDvCfWRgkl0Cy2VUqGZOwzONQ7oqVg6UmgG1vhnTpGC3xJFXVV6np1pDLTHjlMFu4xjnb7zZxHm8emX6C4JQ== dependencies: "@babel/core" "^7.14.0" "@babel/generator" "^7.14.0" "@babel/parser" "^7.14.0" "@babel/types" "^7.0.0" babel-preset-fbjs "^3.4.0" - metro "0.70.3" - metro-babel-transformer "0.70.3" - metro-cache "0.70.3" - metro-cache-key "0.70.3" - metro-hermes-compiler "0.70.3" - metro-source-map "0.70.3" - metro-transform-plugins "0.70.3" + metro "0.71.3" + metro-babel-transformer "0.71.3" + metro-cache "0.71.3" + metro-cache-key "0.71.3" + metro-hermes-compiler "0.71.3" + metro-source-map "0.71.3" + metro-transform-plugins "0.71.3" nullthrows "^1.1.1" -metro@0.70.3, metro@^0.70.1: - version "0.70.3" - resolved "https://registry.yarnpkg.com/metro/-/metro-0.70.3.tgz#4290f538ab5446c7050e718b5c5823eea292c5c2" - integrity sha512-uEWS7xg8oTetQDABYNtsyeUjdLhH3KAvLFpaFFoJqUpOk2A3iygszdqmjobFl6W4zrvKDJS+XxdMR1roYvUhTw== +metro@0.71.3, metro@^0.71.3: + version "0.71.3" + resolved "https://registry.yarnpkg.com/metro/-/metro-0.71.3.tgz#3e3c90d4e7d5b3f957df5fb7784d79a3b5a56c66" + integrity sha512-1Rig6w7othfDHAQXsGTpUTYdKhYBJDgmCWmdD1WVLv1DaW6tqxTM1DPPi1L5x6w33LdPUjAANT3nwJp5Ki81tg== dependencies: "@babel/code-frame" "^7.0.0" "@babel/core" "^7.14.0" @@ -5321,27 +5115,27 @@ metro@0.70.3, metro@^0.70.1: error-stack-parser "^2.0.6" fs-extra "^1.0.0" graceful-fs "^4.2.4" - hermes-parser "0.6.0" + hermes-parser "0.8.0" image-size "^0.6.0" invariant "^2.2.4" - jest-haste-map "^27.3.1" jest-worker "^27.2.0" lodash.throttle "^4.1.1" - metro-babel-transformer "0.70.3" - metro-cache "0.70.3" - metro-cache-key "0.70.3" - metro-config "0.70.3" - metro-core "0.70.3" - metro-hermes-compiler "0.70.3" - metro-inspector-proxy "0.70.3" - metro-minify-uglify "0.70.3" - metro-react-native-babel-preset "0.70.3" - metro-resolver "0.70.3" - metro-runtime "0.70.3" - metro-source-map "0.70.3" - metro-symbolicate "0.70.3" - metro-transform-plugins "0.70.3" - metro-transform-worker "0.70.3" + metro-babel-transformer "0.71.3" + metro-cache "0.71.3" + metro-cache-key "0.71.3" + metro-config "0.71.3" + metro-core "0.71.3" + metro-file-map "0.71.3" + metro-hermes-compiler "0.71.3" + metro-inspector-proxy "0.71.3" + metro-minify-uglify "0.71.3" + metro-react-native-babel-preset "0.71.3" + metro-resolver "0.71.3" + metro-runtime "0.71.3" + metro-source-map "0.71.3" + metro-symbolicate "0.71.3" + metro-transform-plugins "0.71.3" + metro-transform-worker "0.71.3" mime-types "^2.1.27" node-fetch "^2.2.0" nullthrows "^1.1.1" @@ -5408,14 +5202,7 @@ mimic-fn@^2.1.0: resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== -minimatch@^3.0.2, minimatch@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== - dependencies: - brace-expansion "^1.1.7" - -minimatch@^3.1.2: +minimatch@^3.0.2, minimatch@^3.0.4, minimatch@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== @@ -5599,11 +5386,6 @@ oauth-sign@~0.9.0: resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== -ob1@0.70.3: - version "0.70.3" - resolved "https://registry.yarnpkg.com/ob1/-/ob1-0.70.3.tgz#f48cd5a5abf54b0c423b1b06b6d4ff4d049816cb" - integrity sha512-Vy9GGhuXgDRY01QA6kdhToPd8AkLdLpX9GjH5kpqluVqTu70mgOm7tpGoJDZGaNbr9nJlJgnipqHJQRPORixIQ== - ob1@0.71.3: version "0.71.3" resolved "https://registry.yarnpkg.com/ob1/-/ob1-0.71.3.tgz#aa98b76e1038d016f4e0e42b5d1e7b009db3f0e0" @@ -5623,17 +5405,12 @@ object-copy@^0.1.0: define-property "^0.2.5" kind-of "^3.0.3" -object-inspect@^1.11.0, object-inspect@^1.9.0: - version "1.11.0" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.11.0.tgz#9dceb146cedd4148a0d9e51ab88d34cf509922b1" - integrity sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg== - -object-inspect@^1.12.0: +object-inspect@^1.12.0, object-inspect@^1.9.0: version "1.12.2" resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.2.tgz#c0641f26394532f28ab8d796ab954e43c009a8ea" integrity sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ== -object-keys@^1.0.12, object-keys@^1.1.1: +object-keys@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== @@ -5791,6 +5568,13 @@ p-limit@^2.0.0, p-limit@^2.2.0: dependencies: p-try "^2.0.0" +p-limit@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + p-locate@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" @@ -5805,6 +5589,13 @@ p-locate@^4.1.0: dependencies: p-limit "^2.2.0" +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + p-try@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.0.0.tgz#85080bb87c64688fa47996fe8f7dfbe8211760b1" @@ -6456,14 +6247,7 @@ semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== -semver@^7.3.2: - version "7.3.5" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" - integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== - dependencies: - lru-cache "^6.0.0" - -semver@^7.3.7: +semver@^7.3.2, semver@^7.3.7: version "7.3.7" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f" integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g== @@ -6832,14 +6616,6 @@ string.prototype.matchall@^4.0.7: regexp.prototype.flags "^1.4.1" side-channel "^1.0.4" -string.prototype.trimend@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz#e75ae90c2942c63504686c18b287b4a0b1a45f80" - integrity sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - string.prototype.trimend@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz#914a65baaab25fbdd4ee291ca7dde57e869cb8d0" @@ -6849,14 +6625,6 @@ string.prototype.trimend@^1.0.5: define-properties "^1.1.4" es-abstract "^1.19.5" -string.prototype.trimstart@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz#b36399af4ab2999b4c9c648bd7a3fb2bb26feeed" - integrity sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - string.prototype.trimstart@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz#5466d93ba58cfa2134839f81d7f42437e8c01fef" @@ -7169,16 +6937,6 @@ uglify-es@^3.1.9: commander "~2.13.0" source-map "~0.6.1" -unbox-primitive@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.1.tgz#085e215625ec3162574dc8859abee78a59b14471" - integrity sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw== - dependencies: - function-bind "^1.1.1" - has-bigints "^1.0.1" - has-symbols "^1.0.2" - which-boxed-primitive "^1.0.2" - unbox-primitive@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e" @@ -7526,3 +7284,8 @@ yargs@^15.1.0, yargs@^15.3.1, yargs@^15.4.1: which-module "^2.0.0" y18n "^4.0.0" yargs-parser "^18.1.2" + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== From 04e43544b8d75dc6bb0c94e868b992d47e6e8803 Mon Sep 17 00:00:00 2001 From: Nick Gerleman Date: Tue, 26 Jul 2022 20:06:58 -0700 Subject: [PATCH 0061/1165] Allow VirtualizedListContext to support different component type Summary: This change is in preparation of adding a separate `VirtualizedList_EXPERIMENTAL` component. Both the original, and experimental lists use `VirtualizedListContext`, which itself references back to the VirtualizedList class type. VirtualizedList private methods are currently included in the type system, and are called in other VirtualizedList code (see https://github.com/facebook/react-native/commit/b2f871a6fa9c92dd0712055384b9eca6d828e37d). This prevents Flow from seeing the two classes are compatible if "private" methods change. My first attempt was to parameterize the context, to allow both `VirtualizedList`, and `VirtualizedList_EXPERIMENTAL` to use the same code without sacrificing type safety or adding further duplication. This added more complexity than it is worth, so I am instead loosening the type on VirtualizedListContext to pass around a more generic handle. Changelog: [Internal][Changed] - Allow VirtualizedListContext to support different component type Reviewed By: javache Differential Revision: D38017086 fbshipit-source-id: 91e8f6ab2591d3ae9b7f9263711b4a39b78f68e0 --- Libraries/Lists/VirtualizedList.js | 10 ++++++---- Libraries/Lists/VirtualizedListContext.js | 5 ++--- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Libraries/Lists/VirtualizedList.js b/Libraries/Lists/VirtualizedList.js index 69e63090ea32..ebd06871906c 100644 --- a/Libraries/Lists/VirtualizedList.js +++ b/Libraries/Lists/VirtualizedList.js @@ -634,10 +634,11 @@ class VirtualizedList extends React.PureComponent { _registerAsNestedChild = (childList: { cellKey: string, key: string, - ref: VirtualizedList, + ref: React.ElementRef, parentDebugInfo: ListDebugInfo, ... }): ?ChildListState => { + const specificRef = ((childList.ref: any): VirtualizedList); // Register the mapping between this child key and the cellKey for its cell const childListsInCell = this._cellKeysToChildListKeys.get(childList.cellKey) || new Set(); @@ -651,19 +652,20 @@ class VirtualizedList extends React.PureComponent { 'list. You must pass a unique listKey prop to each sibling list.\n\n' + describeNestedLists({ ...childList, + ref: specificRef, // We're called from the child's componentDidMount, so it's safe to // read the child's props here (albeit weird). - horizontal: !!childList.ref.props.horizontal, + horizontal: !!specificRef.props.horizontal, }), ); } this._nestedChildLists.set(childList.key, { - ref: childList.ref, + ref: specificRef, state: null, }); if (this._hasInteracted) { - childList.ref.recordInteraction(); + specificRef.recordInteraction(); } }; diff --git a/Libraries/Lists/VirtualizedListContext.js b/Libraries/Lists/VirtualizedListContext.js index 308f6a20d19a..a17c4b19160a 100644 --- a/Libraries/Lists/VirtualizedListContext.js +++ b/Libraries/Lists/VirtualizedListContext.js @@ -8,7 +8,6 @@ * @format */ -import type VirtualizedList from './VirtualizedList.js'; import * as React from 'react'; import {useMemo, useContext} from 'react'; @@ -50,12 +49,12 @@ type Context = $ReadOnly<{ zoomScale: number, }, horizontal: ?boolean, - getOutermostParentListRef: () => VirtualizedList, + getOutermostParentListRef: () => React.ElementRef, getNestedChildState: string => ?ChildListState, registerAsNestedChild: ({ cellKey: string, key: string, - ref: VirtualizedList, + ref: React.ElementRef, parentDebugInfo: ListDebugInfo, }) => ?ChildListState, unregisterAsNestedChild: ({ From 479053cb3ce2be145993cbeb17e43108313de913 Mon Sep 17 00:00:00 2001 From: Nick Gerleman Date: Tue, 26 Jul 2022 20:06:58 -0700 Subject: [PATCH 0062/1165] Add VirtualizedList_EXPERIMENTAL (CellRenderMask Usage) Summary: # This Change https://github.com/react-native-community/discussions-and-proposals/pull/335 discussed a set of problems with VirtualizedList and focus. These were seen as severe externally for a11y on desktop. The issues center on users of keyboard and accessibility tools, where users expect to be able to move focus in an uninterrupted loop. The design and implementation evolved to be a bit more general, and without any API-surface behavior changes. It was implemented and rolled out externally as a series of changes. The remaining changes that were not upstreamed into RN are rolled into https://github.com/facebook/react-native/pull/32646 This diff brings this change into the repo, as a separate copy of VirtualizedList, to measure its impact to guardrail metrics, without yet making it the default implementation. The intention is for this to be temporary, until there is confidence the implementation is correct. ## List Implementation (more on GitHub) This change makes it possible to synchronously move native focus to arbitrary items in a VirtualizedList. This is implemented by switching component state to a sparse bitset. This was previously implemented and upstreamed as `CellRenderMask`. A usage of this is added, to keep the last focused item rendered. This allows the focus loop to remain unbroken, when scrolling away, or tab loops which leave/re-enter the list. VirtualizedList tracks the last focused cell through the capture phase of `onFocus`. It will keep the cell, and a viewport above and below the last focused cell rendered, to allow movement to it without blanking (without using too much memory). ## Experimentation Implementation A mechanism is added to gate the change via VirtualizedListInjection, mirroring the approach taken for Switch with D27381306 (https://github.com/facebook/react-native/commit/683b825b327e7fa71e87e3d613cb9acd37c24288). It allows VirtualizedList to delegate to a global override. It has a slight penalty to needing to import both modules, but means code which imports VirtualizedList directly is affected the changes. Changelog: [Internal][Added] - Add VirtualizedList_EXPERIMENTAL (CellRenderMask Usage) Reviewed By: lunaleaps Differential Revision: D38020408 fbshipit-source-id: ad0aaa6791f3f4455e3068502a2841f3ffb40b41 --- Libraries/Lists/CellRenderMask.js | 4 + Libraries/Lists/VirtualizeUtils.js | 2 - Libraries/Lists/VirtualizedList.js | 3 +- Libraries/Lists/VirtualizedListInjection.js | 16 + .../Lists/VirtualizedList_EXPERIMENTAL.js | 2410 ++++++++ .../Lists/__tests__/VirtualizedList-test.js | 196 +- .../VirtualizedList_EXPERIMENTAL-test.js | 14 + .../VirtualizedList_EXPERIMENTAL-test.js.snap | 5368 +++++++++++++++++ 8 files changed, 8008 insertions(+), 5 deletions(-) create mode 100644 Libraries/Lists/VirtualizedListInjection.js create mode 100644 Libraries/Lists/VirtualizedList_EXPERIMENTAL.js create mode 100644 Libraries/Lists/__tests__/VirtualizedList_EXPERIMENTAL-test.js create mode 100644 Libraries/Lists/__tests__/__snapshots__/VirtualizedList_EXPERIMENTAL-test.js.snap diff --git a/Libraries/Lists/CellRenderMask.js b/Libraries/Lists/CellRenderMask.js index ddcb96d21c46..66c667f4e31a 100644 --- a/Libraries/Lists/CellRenderMask.js +++ b/Libraries/Lists/CellRenderMask.js @@ -110,6 +110,10 @@ export class CellRenderMask { ); } + numCells(): number { + return this._numCells; + } + equals(other: CellRenderMask): boolean { return ( this._numCells === other._numCells && diff --git a/Libraries/Lists/VirtualizeUtils.js b/Libraries/Lists/VirtualizeUtils.js index 70e48ff1a207..c8ccb07cb30a 100644 --- a/Libraries/Lists/VirtualizeUtils.js +++ b/Libraries/Lists/VirtualizeUtils.js @@ -102,7 +102,6 @@ export function computeWindowedRenderLimits( prev: { first: number, last: number, - ... }, getFrameMetricsApprox: (index: number) => { length: number, @@ -120,7 +119,6 @@ export function computeWindowedRenderLimits( ): { first: number, last: number, - ... } { const itemCount = getItemCount(data); if (itemCount === 0) { diff --git a/Libraries/Lists/VirtualizedList.js b/Libraries/Lists/VirtualizedList.js index ebd06871906c..6387e767be87 100644 --- a/Libraries/Lists/VirtualizedList.js +++ b/Libraries/Lists/VirtualizedList.js @@ -2217,4 +2217,5 @@ const styles = StyleSheet.create({ }, }); -module.exports = VirtualizedList; +module.exports = (require('./VirtualizedListInjection').default + .unstable_VirtualizedList ?? VirtualizedList: typeof VirtualizedList); diff --git a/Libraries/Lists/VirtualizedListInjection.js b/Libraries/Lists/VirtualizedListInjection.js new file mode 100644 index 000000000000..cc872a7ecfb7 --- /dev/null +++ b/Libraries/Lists/VirtualizedListInjection.js @@ -0,0 +1,16 @@ +/** + * 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 + * @format + */ + +'use strict'; +import typeof VirtualizedList from './VirtualizedList'; + +export default { + unstable_VirtualizedList: (null: ?VirtualizedList), +}; diff --git a/Libraries/Lists/VirtualizedList_EXPERIMENTAL.js b/Libraries/Lists/VirtualizedList_EXPERIMENTAL.js new file mode 100644 index 000000000000..d69b3d01a2a8 --- /dev/null +++ b/Libraries/Lists/VirtualizedList_EXPERIMENTAL.js @@ -0,0 +1,2410 @@ +/** + * 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 + * @format + */ + +import type {ScrollResponderType} from '../Components/ScrollView/ScrollView'; +import type {ViewStyleProp} from '../StyleSheet/StyleSheet'; +import type {LayoutEvent, ScrollEvent} from '../Types/CoreEventTypes'; +import type { + ViewabilityConfig, + ViewabilityConfigCallbackPair, + ViewToken, +} from './ViewabilityHelper'; + +import { + type ChildListState, + type ListDebugInfo, + VirtualizedListCellContextProvider, + VirtualizedListContext, + VirtualizedListContextProvider, +} from './VirtualizedListContext.js'; +import { + computeWindowedRenderLimits, + keyExtractor as defaultKeyExtractor, +} from './VirtualizeUtils'; +import * as React from 'react'; + +import type {FocusEvent} from '../Types/CoreEventTypes'; + +import {CellRenderMask} from './CellRenderMask'; +import clamp from '../Utilities/clamp'; + +const RefreshControl = require('../Components/RefreshControl/RefreshControl'); +const ScrollView = require('../Components/ScrollView/ScrollView'); +const View = require('../Components/View/View'); +const Batchinator = require('../Interaction/Batchinator'); +const ReactNative = require('../Renderer/shims/ReactNative'); +const flattenStyle = require('../StyleSheet/flattenStyle'); +const StyleSheet = require('../StyleSheet/StyleSheet'); +const infoLog = require('../Utilities/infoLog'); +const FillRateHelper = require('./FillRateHelper'); +const ViewabilityHelper = require('./ViewabilityHelper'); +const invariant = require('invariant'); + +const ON_END_REACHED_EPSILON = 0.001; + +type Item = any; + +export type Separators = { + highlight: () => void, + unhighlight: () => void, + updateProps: (select: 'leading' | 'trailing', newProps: Object) => void, + ... +}; + +export type RenderItemProps = { + item: ItemT, + index: number, + separators: Separators, + ... +}; + +export type RenderItemType = ( + info: RenderItemProps, +) => React.Node; + +type ViewabilityHelperCallbackTuple = { + viewabilityHelper: ViewabilityHelper, + onViewableItemsChanged: (info: { + viewableItems: Array, + changed: Array, + ... + }) => void, + ... +}; + +type RequiredProps = {| + /** + * The default accessor functions assume this is an Array<{key: string} | {id: string}> but you can override + * getItem, getItemCount, and keyExtractor to handle any type of index-based data. + */ + data?: any, + /** + * A generic accessor for extracting an item from any sort of data blob. + */ + getItem: (data: any, index: number) => ?Item, + /** + * Determines how many items are in the data blob. + */ + getItemCount: (data: any) => number, +|}; +type OptionalProps = {| + renderItem?: ?RenderItemType, + /** + * `debug` will turn on extra logging and visual overlays to aid with debugging both usage and + * implementation, but with a significant perf hit. + */ + debug?: ?boolean, + /** + * DEPRECATED: Virtualization provides significant performance and memory optimizations, but fully + * unmounts react instances that are outside of the render window. You should only need to disable + * this for debugging purposes. Defaults to false. + */ + disableVirtualization?: ?boolean, + /** + * A marker property for telling the list to re-render (since it implements `PureComponent`). If + * any of your `renderItem`, Header, Footer, etc. functions depend on anything outside of the + * `data` prop, stick it here and treat it immutably. + */ + extraData?: any, + // e.g. height, y + getItemLayout?: ( + data: any, + index: number, + ) => { + length: number, + offset: number, + index: number, + ... + }, + horizontal?: ?boolean, + /** + * How many items to render in the initial batch. This should be enough to fill the screen but not + * much more. Note these items will never be unmounted as part of the windowed rendering in order + * to improve perceived performance of scroll-to-top actions. + */ + initialNumToRender?: ?number, + /** + * Instead of starting at the top with the first item, start at `initialScrollIndex`. This + * disables the "scroll to top" optimization that keeps the first `initialNumToRender` items + * always rendered and immediately renders the items starting at this initial index. Requires + * `getItemLayout` to be implemented. + */ + initialScrollIndex?: ?number, + /** + * Reverses the direction of scroll. Uses scale transforms of -1. + */ + inverted?: ?boolean, + keyExtractor?: ?(item: Item, index: number) => string, + /** + * Each cell is rendered using this element. Can be a React Component Class, + * or a render function. Defaults to using View. + */ + CellRendererComponent?: ?React.ComponentType, + /** + * Rendered in between each item, but not at the top or bottom. By default, `highlighted` and + * `leadingItem` props are provided. `renderItem` provides `separators.highlight`/`unhighlight` + * which will update the `highlighted` prop, but you can also add custom props with + * `separators.updateProps`. + */ + ItemSeparatorComponent?: ?React.ComponentType, + /** + * Takes an item from `data` and renders it into the list. Example usage: + * + * ( + * + * )} + * data={[{title: 'Title Text', key: 'item1'}]} + * ListItemComponent={({item, separators}) => ( + * this._onPress(item)} + * onShowUnderlay={separators.highlight} + * onHideUnderlay={separators.unhighlight}> + * + * {item.title} + * + * + * )} + * /> + * + * Provides additional metadata like `index` if you need it, as well as a more generic + * `separators.updateProps` function which let's you set whatever props you want to change the + * rendering of either the leading separator or trailing separator in case the more common + * `highlight` and `unhighlight` (which set the `highlighted: boolean` prop) are insufficient for + * your use-case. + */ + ListItemComponent?: ?(React.ComponentType | React.Element), + /** + * Rendered when the list is empty. Can be a React Component Class, a render function, or + * a rendered element. + */ + ListEmptyComponent?: ?(React.ComponentType | React.Element), + /** + * Rendered at the bottom of all the items. Can be a React Component Class, a render function, or + * a rendered element. + */ + ListFooterComponent?: ?(React.ComponentType | React.Element), + /** + * Styling for internal View for ListFooterComponent + */ + ListFooterComponentStyle?: ViewStyleProp, + /** + * Rendered at the top of all the items. Can be a React Component Class, a render function, or + * a rendered element. + */ + ListHeaderComponent?: ?(React.ComponentType | React.Element), + /** + * Styling for internal View for ListHeaderComponent + */ + ListHeaderComponentStyle?: ViewStyleProp, + /** + * A unique identifier for this list. If there are multiple VirtualizedLists at the same level of + * nesting within another VirtualizedList, this key is necessary for virtualization to + * work properly. + */ + listKey?: string, + /** + * The maximum number of items to render in each incremental render batch. The more rendered at + * once, the better the fill rate, but responsiveness may suffer because rendering content may + * interfere with responding to button taps or other interactions. + */ + maxToRenderPerBatch?: ?number, + /** + * Called once when the scroll position gets within `onEndReachedThreshold` of the rendered + * content. + */ + onEndReached?: ?(info: {distanceFromEnd: number, ...}) => void, + /** + * How far from the end (in units of visible length of the list) the bottom edge of the + * list must be from the end of the content to trigger the `onEndReached` callback. + * Thus a value of 0.5 will trigger `onEndReached` when the end of the content is + * within half the visible length of the list. A value of 0 will not trigger until scrolling + * to the very end of the list. + */ + onEndReachedThreshold?: ?number, + /** + * If provided, a standard RefreshControl will be added for "Pull to Refresh" functionality. Make + * sure to also set the `refreshing` prop correctly. + */ + onRefresh?: ?() => void, + /** + * Used to handle failures when scrolling to an index that has not been measured yet. Recommended + * action is to either compute your own offset and `scrollTo` it, or scroll as far as possible and + * then try again after more items have been rendered. + */ + onScrollToIndexFailed?: ?(info: { + index: number, + highestMeasuredFrameIndex: number, + averageItemLength: number, + ... + }) => void, + /** + * Called when the viewability of rows changes, as defined by the + * `viewabilityConfig` prop. + */ + onViewableItemsChanged?: ?(info: { + viewableItems: Array, + changed: Array, + ... + }) => void, + persistentScrollbar?: ?boolean, + /** + * Set this when offset is needed for the loading indicator to show correctly. + */ + progressViewOffset?: number, + /** + * A custom refresh control element. When set, it overrides the default + * component built internally. The onRefresh and refreshing + * props are also ignored. Only works for vertical VirtualizedList. + */ + refreshControl?: ?React.Element, + /** + * Set this true while waiting for new data from a refresh. + */ + refreshing?: ?boolean, + /** + * Note: may have bugs (missing content) in some circumstances - use at your own risk. + * + * This may improve scroll performance for large lists. + */ + removeClippedSubviews?: boolean, + /** + * Render a custom scroll component, e.g. with a differently styled `RefreshControl`. + */ + renderScrollComponent?: (props: Object) => React.Element, + /** + * Amount of time between low-pri item render batches, e.g. for rendering items quite a ways off + * screen. Similar fill rate/responsiveness tradeoff as `maxToRenderPerBatch`. + */ + updateCellsBatchingPeriod?: ?number, + /** + * See `ViewabilityHelper` for flow type and further documentation. + */ + viewabilityConfig?: ViewabilityConfig, + /** + * List of ViewabilityConfig/onViewableItemsChanged pairs. A specific onViewableItemsChanged + * will be called when its corresponding ViewabilityConfig's conditions are met. + */ + viewabilityConfigCallbackPairs?: Array, + /** + * Determines the maximum number of items rendered outside of the visible area, in units of + * visible lengths. So if your list fills the screen, then `windowSize={21}` (the default) will + * render the visible screen area plus up to 10 screens above and 10 below the viewport. Reducing + * this number will reduce memory consumption and may improve performance, but will increase the + * chance that fast scrolling may reveal momentary blank areas of unrendered content. + */ + windowSize?: ?number, + /** + * The legacy implementation is no longer supported. + */ + legacyImplementation?: empty, +|}; + +type Props = {| + ...React.ElementConfig, + ...RequiredProps, + ...OptionalProps, +|}; + +let _usedIndexForKey = false; +let _keylessItemComponentName: string = ''; + +type State = { + renderMask: CellRenderMask, + cellsAroundViewport: {first: number, last: number}, +}; + +/** + * Default Props Helper Functions + * Use the following helper functions for default values + */ + +// horizontalOrDefault(this.props.horizontal) +function horizontalOrDefault(horizontal: ?boolean) { + return horizontal ?? false; +} + +// initialNumToRenderOrDefault(this.props.initialNumToRenderOrDefault) +function initialNumToRenderOrDefault(initialNumToRender: ?number) { + return initialNumToRender ?? 10; +} + +// maxToRenderPerBatchOrDefault(this.props.maxToRenderPerBatch) +function maxToRenderPerBatchOrDefault(maxToRenderPerBatch: ?number) { + return maxToRenderPerBatch ?? 10; +} + +// onEndReachedThresholdOrDefault(this.props.onEndReachedThreshold) +function onEndReachedThresholdOrDefault(onEndReachedThreshold: ?number) { + return onEndReachedThreshold ?? 2; +} + +// scrollEventThrottleOrDefault(this.props.scrollEventThrottle) +function scrollEventThrottleOrDefault(scrollEventThrottle: ?number) { + return scrollEventThrottle ?? 50; +} + +// windowSizeOrDefault(this.props.windowSize) +function windowSizeOrDefault(windowSize: ?number) { + return windowSize ?? 21; +} + +function findLastWhere( + arr: $ReadOnlyArray, + predicate: (element: T) => boolean, +): T | null { + for (let i = arr.length - 1; i >= 0; i--) { + if (predicate(arr[i])) { + return arr[i]; + } + } + + return null; +} + +/** + * Base implementation for the more convenient [``](https://reactnative.dev/docs/flatlist) + * and [``](https://reactnative.dev/docs/sectionlist) components, which are also better + * documented. In general, this should only really be used if you need more flexibility than + * `FlatList` provides, e.g. for use with immutable data instead of plain arrays. + * + * Virtualization massively improves memory consumption and performance of large lists by + * maintaining a finite render window of active items and replacing all items outside of the render + * window with appropriately sized blank space. The window adapts to scrolling behavior, and items + * are rendered incrementally with low-pri (after any running interactions) if they are far from the + * visible area, or with hi-pri otherwise to minimize the potential of seeing blank space. + * + * Some caveats: + * + * - Internal state is not preserved when content scrolls out of the render window. Make sure all + * your data is captured in the item data or external stores like Flux, Redux, or Relay. + * - This is a `PureComponent` which means that it will not re-render if `props` remain shallow- + * equal. Make sure that everything your `renderItem` function depends on is passed as a prop + * (e.g. `extraData`) that is not `===` after updates, otherwise your UI may not update on + * changes. This includes the `data` prop and parent component state. + * - In order to constrain memory and enable smooth scrolling, content is rendered asynchronously + * offscreen. This means it's possible to scroll faster than the fill rate ands momentarily see + * blank content. This is a tradeoff that can be adjusted to suit the needs of each application, + * and we are working on improving it behind the scenes. + * - By default, the list looks for a `key` or `id` prop on each item and uses that for the React key. + * Alternatively, you can provide a custom `keyExtractor` prop. + * - As an effort to remove defaultProps, use helper functions when referencing certain props + * + */ +class VirtualizedList extends React.PureComponent { + static contextType: typeof VirtualizedListContext = VirtualizedListContext; + + // scrollToEnd may be janky without getItemLayout prop + scrollToEnd(params?: ?{animated?: ?boolean, ...}) { + const animated = params ? params.animated : true; + const veryLast = this.props.getItemCount(this.props.data) - 1; + const frame = this.__getFrameMetricsApprox(veryLast); + const offset = Math.max( + 0, + frame.offset + + frame.length + + this._footerLength - + this._scrollMetrics.visibleLength, + ); + + if (this._scrollRef == null) { + return; + } + + if (this._scrollRef.scrollTo == null) { + console.warn( + 'No scrollTo method provided. This may be because you have two nested ' + + 'VirtualizedLists with the same orientation, or because you are ' + + 'using a custom component that does not implement scrollTo.', + ); + return; + } + + this._scrollRef.scrollTo( + horizontalOrDefault(this.props.horizontal) + ? {x: offset, animated} + : {y: offset, animated}, + ); + } + + // scrollToIndex may be janky without getItemLayout prop + scrollToIndex(params: { + animated?: ?boolean, + index: number, + viewOffset?: number, + viewPosition?: number, + ... + }) { + const { + data, + horizontal, + getItemCount, + getItemLayout, + onScrollToIndexFailed, + } = this.props; + const {animated, index, viewOffset, viewPosition} = params; + invariant( + index >= 0, + `scrollToIndex out of range: requested index ${index} but minimum is 0`, + ); + invariant( + getItemCount(data) >= 1, + `scrollToIndex out of range: item length ${getItemCount( + data, + )} but minimum is 1`, + ); + invariant( + index < getItemCount(data), + `scrollToIndex out of range: requested index ${index} is out of 0 to ${ + getItemCount(data) - 1 + }`, + ); + if (!getItemLayout && index > this._highestMeasuredFrameIndex) { + invariant( + !!onScrollToIndexFailed, + 'scrollToIndex should be used in conjunction with getItemLayout or onScrollToIndexFailed, ' + + 'otherwise there is no way to know the location of offscreen indices or handle failures.', + ); + onScrollToIndexFailed({ + averageItemLength: this._averageCellLength, + highestMeasuredFrameIndex: this._highestMeasuredFrameIndex, + index, + }); + return; + } + const frame = this.__getFrameMetricsApprox(index); + const offset = + Math.max( + 0, + frame.offset - + (viewPosition || 0) * + (this._scrollMetrics.visibleLength - frame.length), + ) - (viewOffset || 0); + + if (this._scrollRef == null) { + return; + } + + if (this._scrollRef.scrollTo == null) { + console.warn( + 'No scrollTo method provided. This may be because you have two nested ' + + 'VirtualizedLists with the same orientation, or because you are ' + + 'using a custom component that does not implement scrollTo.', + ); + return; + } + + this._scrollRef.scrollTo( + horizontal ? {x: offset, animated} : {y: offset, animated}, + ); + } + + // scrollToItem may be janky without getItemLayout prop. Required linear scan through items - + // use scrollToIndex instead if possible. + scrollToItem(params: { + animated?: ?boolean, + item: Item, + viewPosition?: number, + ... + }) { + const {item} = params; + const {data, getItem, getItemCount} = this.props; + const itemCount = getItemCount(data); + for (let index = 0; index < itemCount; index++) { + if (getItem(data, index) === item) { + this.scrollToIndex({...params, index}); + break; + } + } + } + + /** + * Scroll to a specific content pixel offset in the list. + * + * Param `offset` expects the offset to scroll to. + * In case of `horizontal` is true, the offset is the x-value, + * in any other case the offset is the y-value. + * + * Param `animated` (`true` by default) defines whether the list + * should do an animation while scrolling. + */ + scrollToOffset(params: {animated?: ?boolean, offset: number, ...}) { + const {animated, offset} = params; + + if (this._scrollRef == null) { + return; + } + + if (this._scrollRef.scrollTo == null) { + console.warn( + 'No scrollTo method provided. This may be because you have two nested ' + + 'VirtualizedLists with the same orientation, or because you are ' + + 'using a custom component that does not implement scrollTo.', + ); + return; + } + + this._scrollRef.scrollTo( + horizontalOrDefault(this.props.horizontal) + ? {x: offset, animated} + : {y: offset, animated}, + ); + } + + recordInteraction() { + this._nestedChildLists.forEach(childList => { + childList.ref && childList.ref.recordInteraction(); + }); + this._viewabilityTuples.forEach(t => { + t.viewabilityHelper.recordInteraction(); + }); + this._updateViewableItems(this.props.data); + } + + flashScrollIndicators() { + if (this._scrollRef == null) { + return; + } + + this._scrollRef.flashScrollIndicators(); + } + + /** + * Provides a handle to the underlying scroll responder. + * Note that `this._scrollRef` might not be a `ScrollView`, so we + * need to check that it responds to `getScrollResponder` before calling it. + */ + getScrollResponder(): ?ScrollResponderType { + if (this._scrollRef && this._scrollRef.getScrollResponder) { + return this._scrollRef.getScrollResponder(); + } + } + + getScrollableNode(): ?number { + if (this._scrollRef && this._scrollRef.getScrollableNode) { + return this._scrollRef.getScrollableNode(); + } else { + return ReactNative.findNodeHandle(this._scrollRef); + } + } + + getScrollRef(): + | ?React.ElementRef + | ?React.ElementRef { + if (this._scrollRef && this._scrollRef.getScrollRef) { + return this._scrollRef.getScrollRef(); + } else { + return this._scrollRef; + } + } + + setNativeProps(props: Object) { + if (this._scrollRef) { + this._scrollRef.setNativeProps(props); + } + } + + _getCellKey(): string { + return this.context?.cellKey || 'rootList'; + } + + _getListKey(): string { + return this.props.listKey || this._getCellKey(); + } + + _getDebugInfo(): ListDebugInfo { + return { + listKey: this._getListKey(), + cellKey: this._getCellKey(), + horizontal: horizontalOrDefault(this.props.horizontal), + parent: this.context?.debugInfo, + }; + } + + _getScrollMetrics = () => { + return this._scrollMetrics; + }; + + hasMore(): boolean { + return this._hasMore; + } + + _getOutermostParentListRef = () => { + if (this._isNestedWithSameOrientation()) { + return this.context.getOutermostParentListRef(); + } else { + return this; + } + }; + + _getNestedChildState = (key: string): ?ChildListState => { + const existingChildData = this._nestedChildLists.get(key); + return existingChildData && existingChildData.state; + }; + + _registerAsNestedChild = (childList: { + cellKey: string, + key: string, + ref: React.ElementRef, + parentDebugInfo: ListDebugInfo, + ... + }): ?ChildListState => { + const specificRef = ((childList.ref: any): VirtualizedList); + // Register the mapping between this child key and the cellKey for its cell + const childListsInCell = + this._cellKeysToChildListKeys.get(childList.cellKey) || new Set(); + childListsInCell.add(childList.key); + this._cellKeysToChildListKeys.set(childList.cellKey, childListsInCell); + const existingChildData = this._nestedChildLists.get(childList.key); + if (existingChildData && existingChildData.ref !== null) { + console.error( + 'A VirtualizedList contains a cell which itself contains ' + + 'more than one VirtualizedList of the same orientation as the parent ' + + 'list. You must pass a unique listKey prop to each sibling list.\n\n' + + describeNestedLists({ + ...childList, + ref: specificRef, + // We're called from the child's componentDidMount, so it's safe to + // read the child's props here (albeit weird). + horizontal: !!specificRef.props.horizontal, + }), + ); + } + this._nestedChildLists.set(childList.key, { + ref: specificRef, + state: null, + }); + + if (this._hasInteracted) { + specificRef.recordInteraction(); + } + }; + + _unregisterAsNestedChild = (childList: { + key: string, + state: ChildListState, + ... + }): void => { + this._nestedChildLists.set(childList.key, { + ref: null, + state: childList.state, + }); + }; + + state: State; + + constructor(props: Props) { + super(props); + invariant( + // $FlowFixMe[prop-missing] + !props.onScroll || !props.onScroll.__isNative, + 'Components based on VirtualizedList must be wrapped with Animated.createAnimatedComponent ' + + 'to support native onScroll events with useNativeDriver', + ); + invariant( + windowSizeOrDefault(props.windowSize) > 0, + 'VirtualizedList: The windowSize prop must be present and set to a value greater than 0.', + ); + + invariant( + props.getItemCount, + 'VirtualizedList: The "getItemCount" prop must be provided', + ); + + this._fillRateHelper = new FillRateHelper(this._getFrameMetrics); + this._updateCellsToRenderBatcher = new Batchinator( + this._updateCellsToRender, + this.props.updateCellsBatchingPeriod ?? 50, + ); + + if (this.props.viewabilityConfigCallbackPairs) { + this._viewabilityTuples = this.props.viewabilityConfigCallbackPairs.map( + pair => ({ + viewabilityHelper: new ViewabilityHelper(pair.viewabilityConfig), + onViewableItemsChanged: pair.onViewableItemsChanged, + }), + ); + } else { + const {onViewableItemsChanged, viewabilityConfig} = this.props; + if (onViewableItemsChanged) { + this._viewabilityTuples.push({ + viewabilityHelper: new ViewabilityHelper(viewabilityConfig), + onViewableItemsChanged: onViewableItemsChanged, + }); + } + } + + const initialRenderRegion = VirtualizedList._initialRenderRegion(props); + + let initialState: State = { + cellsAroundViewport: initialRenderRegion, + renderMask: VirtualizedList._createRenderMask(props, initialRenderRegion), + }; + + if (this._isNestedWithSameOrientation()) { + const storedState = this.context.getNestedChildState(this._getListKey()); + if (storedState) { + initialState = storedState; + this.state = storedState; + this._frames = storedState.frames; + } + } + + this.state = initialState; + } + + static _createRenderMask( + props: Props, + cellsAroundViewport: {first: number, last: number}, + additionalRegions?: ?$ReadOnlyArray<{first: number, last: number}>, + ): CellRenderMask { + const itemCount = props.getItemCount(props.data); + + invariant( + cellsAroundViewport.first >= 0 && + cellsAroundViewport.last >= cellsAroundViewport.first - 1 && + cellsAroundViewport.last < itemCount, + `Invalid cells around viewport "[${cellsAroundViewport.first}, ${cellsAroundViewport.last}]" was passed to VirtualizedList._createRenderMask`, + ); + + const renderMask = new CellRenderMask(itemCount); + + if (itemCount > 0) { + const allRegions = [cellsAroundViewport, ...(additionalRegions ?? [])]; + for (const region of allRegions) { + if (region.last >= region.first) { + renderMask.addCells(region); + } + } + + // The initially rendered cells are retained as part of the + // "scroll-to-top" optimization + if (props.initialScrollIndex == null || props.initialScrollIndex === 0) { + const initialRegion = VirtualizedList._initialRenderRegion(props); + renderMask.addCells(initialRegion); + } + + // The layout coordinates of sticker headers may be off-screen while the + // actual header is on-screen. Keep the most recent before the viewport + // rendered, even if its layout coordinates are not in viewport. + const stickyIndicesSet = new Set(props.stickyHeaderIndices); + VirtualizedList._ensureClosestStickyHeader( + props, + stickyIndicesSet, + renderMask, + cellsAroundViewport.first, + ); + } + + return renderMask; + } + + static _initialRenderRegion(props: Props): {first: number, last: number} { + const itemCount = props.getItemCount(props.data); + const scrollIndex = props.initialScrollIndex || 0; + + return { + first: scrollIndex, + last: + Math.min( + itemCount, + scrollIndex + initialNumToRenderOrDefault(props.initialNumToRender), + ) - 1, + }; + } + + static _ensureClosestStickyHeader( + props: Props, + stickyIndicesSet: Set, + renderMask: CellRenderMask, + cellIdx: number, + ) { + const stickyOffset = props.ListHeaderComponent ? 1 : 0; + + for (let itemIdx = cellIdx - 1; itemIdx >= 0; itemIdx--) { + if (stickyIndicesSet.has(itemIdx + stickyOffset)) { + renderMask.addCells({first: itemIdx, last: itemIdx}); + break; + } + } + } + + _adjustCellsAroundViewport( + props: Props, + cellsAroundViewport: {first: number, last: number}, + ): {first: number, last: number} { + const {data, getItemCount} = props; + const onEndReachedThreshold = onEndReachedThresholdOrDefault( + props.onEndReachedThreshold, + ); + this._updateViewableItems(data); + + const {contentLength, offset, visibleLength} = this._scrollMetrics; + const distanceFromEnd = contentLength - visibleLength - offset; + + // Wait until the scroll view metrics have been set up. And until then, + // we will trust the initialNumToRender suggestion + if (visibleLength <= 0 || contentLength <= 0) { + return cellsAroundViewport; + } + + let newCellsAroundViewport: {first: number, last: number}; + if (this._isVirtualizationDisabled()) { + const renderAhead = + distanceFromEnd < onEndReachedThreshold * visibleLength + ? maxToRenderPerBatchOrDefault(props.maxToRenderPerBatch) + : 0; + + newCellsAroundViewport = { + first: 0, + last: Math.min( + this.state.cellsAroundViewport.last + renderAhead, + getItemCount(data) - 1, + ), + }; + } else { + // If we have a non-zero initialScrollIndex and run this before we've scrolled, + // we'll wipe out the initialNumToRender rendered elements starting at initialScrollIndex. + // So let's wait until we've scrolled the view to the right place. And until then, + // we will trust the initialScrollIndex suggestion. + + // Thus, we want to recalculate the windowed render limits if any of the following hold: + // - initialScrollIndex is undefined or is 0 + // - initialScrollIndex > 0 AND scrolling is complete + // - initialScrollIndex > 0 AND the end of the list is visible (this handles the case + // where the list is shorter than the visible area) + if ( + this.props.initialScrollIndex && + !this._scrollMetrics.offset && + Math.abs(distanceFromEnd) >= Number.EPSILON + ) { + return cellsAroundViewport; + } + + newCellsAroundViewport = computeWindowedRenderLimits( + props.data, + props.getItemCount, + maxToRenderPerBatchOrDefault(props.maxToRenderPerBatch), + windowSizeOrDefault(props.windowSize), + cellsAroundViewport, + this.__getFrameMetricsApprox, + this._scrollMetrics, + ); + } + + if (this._nestedChildLists.size > 0) { + // If some cell in the new state has a child list in it, we should only render + // up through that item, so that we give that list a chance to render. + // Otherwise there's churn from multiple child lists mounting and un-mounting + // their items. + + // Will this prevent rendering if the nested list doesn't realize the end? + const childIdx = this._findFirstChildWithMore( + newCellsAroundViewport.first, + newCellsAroundViewport.last, + ); + + newCellsAroundViewport.last = childIdx ?? newCellsAroundViewport.last; + } + + return newCellsAroundViewport; + } + + _findFirstChildWithMore(first: number, last: number): number | null { + for (let ii = first; ii <= last; ii++) { + const cellKeyForIndex = this._indicesToKeys.get(ii); + const childListKeys = + cellKeyForIndex && this._cellKeysToChildListKeys.get(cellKeyForIndex); + if (!childListKeys) { + continue; + } + // For each cell, need to check whether any child list in it has more elements to render + for (let childKey of childListKeys) { + const childList = this._nestedChildLists.get(childKey); + if (childList && childList.ref && childList.ref.hasMore()) { + return ii; + } + } + } + + return null; + } + + componentDidMount() { + if (this._isNestedWithSameOrientation()) { + this.context.registerAsNestedChild({ + cellKey: this._getCellKey(), + key: this._getListKey(), + ref: this, + // NOTE: When the child mounts (here) it's not necessarily safe to read + // the parent's props. This is why we explicitly propagate debugInfo + // "down" via context and "up" again via this method call on the + // parent. + parentDebugInfo: this.context.debugInfo, + }); + } + } + + componentWillUnmount() { + if (this._isNestedWithSameOrientation()) { + this.context.unregisterAsNestedChild({ + key: this._getListKey(), + state: { + ...this.state, + frames: this._frames, + }, + }); + } + this._updateViewableItems(null); + this._updateCellsToRenderBatcher.dispose({abort: true}); + this._viewabilityTuples.forEach(tuple => { + tuple.viewabilityHelper.dispose(); + }); + this._fillRateHelper.deactivateAndFlush(); + } + + static getDerivedStateFromProps(newProps: Props, prevState: State): State { + // first and last could be stale (e.g. if a new, shorter items props is passed in), so we make + // sure we're rendering a reasonable range here. + const itemCount = newProps.getItemCount(newProps.data); + if (itemCount === prevState.renderMask.numCells()) { + return prevState; + } + + const constrainedCells = VirtualizedList._constrainToItemCount( + prevState.cellsAroundViewport, + newProps, + ); + + return { + cellsAroundViewport: constrainedCells, + renderMask: VirtualizedList._createRenderMask(newProps, constrainedCells), + }; + } + + _pushCells( + cells: Array, + stickyHeaderIndices: Array, + stickyIndicesFromProps: Set, + first: number, + last: number, + inversionStyle: ViewStyleProp, + ) { + const { + CellRendererComponent, + ItemSeparatorComponent, + ListHeaderComponent, + ListItemComponent, + data, + debug, + getItem, + getItemCount, + getItemLayout, + horizontal, + renderItem, + } = this.props; + const stickyOffset = ListHeaderComponent ? 1 : 0; + const end = getItemCount(data) - 1; + let prevCellKey; + last = Math.min(end, last); + for (let ii = first; ii <= last; ii++) { + const item = getItem(data, ii); + const key = this._keyExtractor(item, ii); + this._indicesToKeys.set(ii, key); + if (stickyIndicesFromProps.has(ii + stickyOffset)) { + stickyHeaderIndices.push(cells.length); + } + cells.push( + this._onCellFocusCapture(key)} + onUnmount={this._onCellUnmount} + ref={ref => { + this._cellRefs[key] = ref; + }} + renderItem={renderItem} + />, + ); + prevCellKey = key; + } + } + + static _constrainToItemCount( + cells: {first: number, last: number}, + props: Props, + ): {first: number, last: number} { + const itemCount = props.getItemCount(props.data); + const last = Math.min(itemCount - 1, cells.last); + + const maxToRenderPerBatch = maxToRenderPerBatchOrDefault( + props.maxToRenderPerBatch, + ); + + return { + first: clamp(0, itemCount - 1 - maxToRenderPerBatch, cells.first), + last, + }; + } + + _onUpdateSeparators = (keys: Array, newProps: Object) => { + keys.forEach(key => { + const ref = key != null && this._cellRefs[key]; + ref && ref.updateSeparatorProps(newProps); + }); + }; + + _isVirtualizationDisabled(): boolean { + return this.props.disableVirtualization || false; + } + + _isNestedWithSameOrientation(): boolean { + const nestedContext = this.context; + return !!( + nestedContext && + !!nestedContext.horizontal === horizontalOrDefault(this.props.horizontal) + ); + } + + _getSpacerKey = (isVertical: boolean): string => + isVertical ? 'height' : 'width'; + + _keyExtractor(item: Item, index: number) { + if (this.props.keyExtractor != null) { + return this.props.keyExtractor(item, index); + } + + const key = defaultKeyExtractor(item, index); + if (key === String(index)) { + _usedIndexForKey = true; + if (item.type && item.type.displayName) { + _keylessItemComponentName = item.type.displayName; + } + } + return key; + } + + render(): React.Node { + if (__DEV__) { + const flatStyles = flattenStyle(this.props.contentContainerStyle); + if (flatStyles != null && flatStyles.flexWrap === 'wrap') { + console.warn( + '`flexWrap: `wrap`` is not supported with the `VirtualizedList` components.' + + 'Consider using `numColumns` with `FlatList` instead.', + ); + } + } + const {ListEmptyComponent, ListFooterComponent, ListHeaderComponent} = + this.props; + const {data, horizontal} = this.props; + const inversionStyle = this.props.inverted + ? horizontalOrDefault(this.props.horizontal) + ? styles.horizontallyInverted + : styles.verticallyInverted + : null; + const cells = []; + const stickyIndicesFromProps = new Set(this.props.stickyHeaderIndices); + const stickyHeaderIndices = []; + + // 1. Add cell for ListHeaderComponent + if (ListHeaderComponent) { + if (stickyIndicesFromProps.has(0)) { + stickyHeaderIndices.push(0); + } + const element = React.isValidElement(ListHeaderComponent) ? ( + ListHeaderComponent + ) : ( + // $FlowFixMe[not-a-component] + // $FlowFixMe[incompatible-type-arg] + + ); + cells.push( + + + { + // $FlowFixMe[incompatible-type] - Typing ReactNativeComponent revealed errors + element + } + + , + ); + } + + // 2a. Add a cell for ListEmptyComponent if applicable + const itemCount = this.props.getItemCount(data); + if (itemCount === 0 && ListEmptyComponent) { + const element: React.Element = ((React.isValidElement( + ListEmptyComponent, + ) ? ( + ListEmptyComponent + ) : ( + // $FlowFixMe[not-a-component] + // $FlowFixMe[incompatible-type-arg] + + )): any); + cells.push( + React.cloneElement(element, { + key: '$empty', + onLayout: event => { + this._onLayoutEmpty(event); + if (element.props.onLayout) { + element.props.onLayout(event); + } + }, + style: StyleSheet.compose(inversionStyle, element.props.style), + }), + ); + } + + // 2b. Add cells and spacers for each item + if (itemCount > 0) { + _usedIndexForKey = false; + _keylessItemComponentName = ''; + const spacerKey = this._getSpacerKey(!horizontal); + + const renderRegions = this.state.renderMask.enumerateRegions(); + const lastSpacer = findLastWhere(renderRegions, r => r.isSpacer); + + for (const section of renderRegions) { + if (section.isSpacer) { + // Legacy behavior is to avoid spacers when virtualization is + // disabled (including head spacers on initial render). + if (this._isVirtualizationDisabled()) { + continue; + } + + // Without getItemLayout, we limit our tail spacer to the _highestMeasuredFrameIndex to + // prevent the user for hyperscrolling into un-measured area because otherwise content will + // likely jump around as it renders in above the viewport. + const isLastSpacer = section === lastSpacer; + const constrainToMeasured = isLastSpacer && !this.props.getItemLayout; + const last = constrainToMeasured + ? clamp( + section.first - 1, + section.last, + this._highestMeasuredFrameIndex, + ) + : section.last; + + const firstMetrics = this.__getFrameMetricsApprox(section.first); + const lastMetrics = this.__getFrameMetricsApprox(last); + const spacerSize = + lastMetrics.offset + lastMetrics.length - firstMetrics.offset; + cells.push( + , + ); + } else { + this._pushCells( + cells, + stickyHeaderIndices, + stickyIndicesFromProps, + section.first, + section.last, + inversionStyle, + ); + } + } + + if (!this._hasWarned.keys && _usedIndexForKey) { + console.warn( + 'VirtualizedList: missing keys for items, make sure to specify a key or id property on each ' + + 'item or provide a custom keyExtractor.', + _keylessItemComponentName, + ); + this._hasWarned.keys = true; + } + } + + // 3. Add cell for ListFooterComponent + if (ListFooterComponent) { + const element = React.isValidElement(ListFooterComponent) ? ( + ListFooterComponent + ) : ( + // $FlowFixMe[not-a-component] + // $FlowFixMe[incompatible-type-arg] + + ); + cells.push( + + + { + // $FlowFixMe[incompatible-type] - Typing ReactNativeComponent revealed errors + element + } + + , + ); + } + + // 4. Render the ScrollView + const scrollProps = { + ...this.props, + onContentSizeChange: this._onContentSizeChange, + onLayout: this._onLayout, + onScroll: this._onScroll, + onScrollBeginDrag: this._onScrollBeginDrag, + onScrollEndDrag: this._onScrollEndDrag, + onMomentumScrollBegin: this._onMomentumScrollBegin, + onMomentumScrollEnd: this._onMomentumScrollEnd, + scrollEventThrottle: scrollEventThrottleOrDefault( + this.props.scrollEventThrottle, + ), // TODO: Android support + invertStickyHeaders: + this.props.invertStickyHeaders !== undefined + ? this.props.invertStickyHeaders + : this.props.inverted, + stickyHeaderIndices, + style: inversionStyle + ? [inversionStyle, this.props.style] + : this.props.style, + }; + + this._hasMore = this.state.cellsAroundViewport.last < itemCount - 1; + + const innerRet = ( + + {React.cloneElement( + ( + this.props.renderScrollComponent || + this._defaultRenderScrollComponent + )(scrollProps), + { + ref: this._captureScrollRef, + }, + cells, + )} + + ); + let ret: React.Node = innerRet; + if (__DEV__) { + ret = ( + + {scrollContext => { + if ( + scrollContext != null && + !scrollContext.horizontal === + !horizontalOrDefault(this.props.horizontal) && + !this._hasWarned.nesting && + this.context == null + ) { + // TODO (T46547044): use React.warn once 16.9 is sync'd: https://github.com/facebook/react/pull/15170 + console.error( + 'VirtualizedLists should never be nested inside plain ScrollViews with the same ' + + 'orientation because it can break windowing and other functionality - use another ' + + 'VirtualizedList-backed container instead.', + ); + this._hasWarned.nesting = true; + } + return innerRet; + }} + + ); + } + if (this.props.debug) { + return ( + + {ret} + {this._renderDebugOverlay()} + + ); + } else { + return ret; + } + } + + componentDidUpdate(prevProps: Props) { + const {data, extraData} = this.props; + if (data !== prevProps.data || extraData !== prevProps.extraData) { + // clear the viewableIndices cache to also trigger + // the onViewableItemsChanged callback with the new data + this._viewabilityTuples.forEach(tuple => { + tuple.viewabilityHelper.resetViewableIndices(); + }); + } + // The `this._hiPriInProgress` is guaranteeing a hiPri cell update will only happen + // once per fiber update. The `_scheduleCellsToRenderUpdate` will set it to true + // if a hiPri update needs to perform. If `componentDidUpdate` is triggered with + // `this._hiPriInProgress=true`, means it's triggered by the hiPri update. The + // `_scheduleCellsToRenderUpdate` will check this condition and not perform + // another hiPri update. + const hiPriInProgress = this._hiPriInProgress; + this._scheduleCellsToRenderUpdate(); + // Make sure setting `this._hiPriInProgress` back to false after `componentDidUpdate` + // is triggered with `this._hiPriInProgress = true` + if (hiPriInProgress) { + this._hiPriInProgress = false; + } + } + + _averageCellLength = 0; + // Maps a cell key to the set of keys for all outermost child lists within that cell + _cellKeysToChildListKeys: Map> = new Map(); + _cellRefs: {[string]: null | CellRenderer} = {}; + _fillRateHelper: FillRateHelper; + _frames: { + [string]: { + inLayout?: boolean, + index: number, + length: number, + offset: number, + }, + } = {}; + _footerLength = 0; + // Used for preventing scrollToIndex from being called multiple times for initialScrollIndex + _hasTriggeredInitialScrollToIndex = false; + _hasInteracted = false; + _hasMore = false; + _hasWarned: {[string]: boolean} = {}; + _headerLength = 0; + _hiPriInProgress: boolean = false; // flag to prevent infinite hiPri cell limit update + _highestMeasuredFrameIndex = 0; + _indicesToKeys: Map = new Map(); + _lastFocusedCellKey: ?string = null; + _nestedChildLists: Map< + string, + { + ref: ?VirtualizedList, + state: ?ChildListState, + ... + }, + > = new Map(); + _offsetFromParentVirtualizedList: number = 0; + _prevParentOffset: number = 0; + _scrollMetrics = { + contentLength: 0, + dOffset: 0, + dt: 10, + offset: 0, + timestamp: 0, + velocity: 0, + visibleLength: 0, + zoomScale: 1, + }; + _scrollRef: ?React.ElementRef = null; + _sentEndForContentLength = 0; + _totalCellLength = 0; + _totalCellsMeasured = 0; + _updateCellsToRenderBatcher: Batchinator; + _viewabilityTuples: Array = []; + + /* $FlowFixMe[missing-local-annot] The type annotation(s) required by Flow's + * LTI update could not be added via codemod */ + _captureScrollRef = ref => { + this._scrollRef = ref; + }; + + _computeBlankness() { + this._fillRateHelper.computeBlankness( + this.props, + this.state.cellsAroundViewport, + this._scrollMetrics, + ); + } + + /* $FlowFixMe[missing-local-annot] The type annotation(s) required by Flow's + * LTI update could not be added via codemod */ + _defaultRenderScrollComponent = props => { + const onRefresh = props.onRefresh; + if (this._isNestedWithSameOrientation()) { + // $FlowFixMe[prop-missing] - Typing ReactNativeComponent revealed errors + return ; + } else if (onRefresh) { + invariant( + typeof props.refreshing === 'boolean', + '`refreshing` prop must be set as a boolean in order to use `onRefresh`, but got `' + + JSON.stringify(props.refreshing ?? 'undefined') + + '`', + ); + return ( + // $FlowFixMe[prop-missing] Invalid prop usage + + ) : ( + props.refreshControl + ) + } + /> + ); + } else { + // $FlowFixMe[prop-missing] Invalid prop usage + return ; + } + }; + + _onCellLayout = (e: LayoutEvent, cellKey: string, index: number): void => { + const layout = e.nativeEvent.layout; + const next = { + offset: this._selectOffset(layout), + length: this._selectLength(layout), + index, + inLayout: true, + }; + const curr = this._frames[cellKey]; + if ( + !curr || + next.offset !== curr.offset || + next.length !== curr.length || + index !== curr.index + ) { + this._totalCellLength += next.length - (curr ? curr.length : 0); + this._totalCellsMeasured += curr ? 0 : 1; + this._averageCellLength = + this._totalCellLength / this._totalCellsMeasured; + this._frames[cellKey] = next; + this._highestMeasuredFrameIndex = Math.max( + this._highestMeasuredFrameIndex, + index, + ); + this._scheduleCellsToRenderUpdate(); + } else { + this._frames[cellKey].inLayout = true; + } + + this._triggerRemeasureForChildListsInCell(cellKey); + + this._computeBlankness(); + this._updateViewableItems(this.props.data); + }; + + _onCellFocusCapture(cellKey: string) { + this._lastFocusedCellKey = cellKey; + const renderMask = VirtualizedList._createRenderMask( + this.props, + this.state.cellsAroundViewport, + this._getNonViewportRenderRegions(), + ); + + if (!renderMask.equals(this.state.renderMask)) { + this.setState({...this.state, renderMask}); + } + } + + _onCellUnmount = (cellKey: string) => { + const curr = this._frames[cellKey]; + if (curr) { + this._frames[cellKey] = {...curr, inLayout: false}; + } + }; + + _triggerRemeasureForChildListsInCell(cellKey: string): void { + const childListKeys = this._cellKeysToChildListKeys.get(cellKey); + if (childListKeys) { + for (let childKey of childListKeys) { + const childList = this._nestedChildLists.get(childKey); + childList && + childList.ref && + childList.ref.measureLayoutRelativeToContainingList(); + } + } + } + + measureLayoutRelativeToContainingList(): void { + // TODO (T35574538): findNodeHandle sometimes crashes with "Unable to find + // node on an unmounted component" during scrolling + try { + if (!this._scrollRef) { + return; + } + // We are assuming that getOutermostParentListRef().getScrollRef() + // is a non-null reference to a ScrollView + this._scrollRef.measureLayout( + this.context.getOutermostParentListRef().getScrollRef(), + (x, y, width, height) => { + this._offsetFromParentVirtualizedList = this._selectOffset({x, y}); + this._scrollMetrics.contentLength = this._selectLength({ + width, + height, + }); + const scrollMetrics = this._convertParentScrollMetrics( + this.context.getScrollMetrics(), + ); + + const metricsChanged = + this._scrollMetrics.visibleLength !== scrollMetrics.visibleLength || + this._scrollMetrics.offset !== scrollMetrics.offset; + + if (metricsChanged) { + this._scrollMetrics.visibleLength = scrollMetrics.visibleLength; + this._scrollMetrics.offset = scrollMetrics.offset; + + // If metrics of the scrollView changed, then we triggered remeasure for child list + // to ensure VirtualizedList has the right information. + this._cellKeysToChildListKeys.forEach(childListKeys => { + if (childListKeys) { + for (let childKey of childListKeys) { + const childList = this._nestedChildLists.get(childKey); + childList && + childList.ref && + childList.ref.measureLayoutRelativeToContainingList(); + } + } + }); + } + }, + error => { + console.warn( + "VirtualizedList: Encountered an error while measuring a list's" + + ' offset from its containing VirtualizedList.', + ); + }, + ); + } catch (error) { + console.warn( + 'measureLayoutRelativeToContainingList threw an error', + error.stack, + ); + } + } + + _onLayout = (e: LayoutEvent) => { + if (this._isNestedWithSameOrientation()) { + // Need to adjust our scroll metrics to be relative to our containing + // VirtualizedList before we can make claims about list item viewability + this.measureLayoutRelativeToContainingList(); + } else { + this._scrollMetrics.visibleLength = this._selectLength( + e.nativeEvent.layout, + ); + } + this.props.onLayout && this.props.onLayout(e); + this._scheduleCellsToRenderUpdate(); + this._maybeCallOnEndReached(); + }; + + _onLayoutEmpty = (e: LayoutEvent) => { + this.props.onLayout && this.props.onLayout(e); + }; + + _getFooterCellKey(): string { + return this._getCellKey() + '-footer'; + } + + _onLayoutFooter = (e: LayoutEvent) => { + this._triggerRemeasureForChildListsInCell(this._getFooterCellKey()); + this._footerLength = this._selectLength(e.nativeEvent.layout); + }; + + _onLayoutHeader = (e: LayoutEvent) => { + this._headerLength = this._selectLength(e.nativeEvent.layout); + }; + + _renderDebugOverlay() { + const normalize = + this._scrollMetrics.visibleLength / + (this._scrollMetrics.contentLength || 1); + const framesInLayout = []; + const itemCount = this.props.getItemCount(this.props.data); + for (let ii = 0; ii < itemCount; ii++) { + const frame = this.__getFrameMetricsApprox(ii); + /* $FlowFixMe[prop-missing] (>=0.68.0 site=react_native_fb) This comment + * suppresses an error found when Flow v0.68 was deployed. To see the + * error delete this comment and run Flow. */ + if (frame.inLayout) { + framesInLayout.push(frame); + } + } + const windowTop = this.__getFrameMetricsApprox( + this.state.cellsAroundViewport.first, + ).offset; + const frameLast = this.__getFrameMetricsApprox( + this.state.cellsAroundViewport.last, + ); + const windowLen = frameLast.offset + frameLast.length - windowTop; + const visTop = this._scrollMetrics.offset; + const visLen = this._scrollMetrics.visibleLength; + + return ( + + {framesInLayout.map((f, ii) => ( + + ))} + + + + ); + } + + _selectLength( + metrics: $ReadOnly<{ + height: number, + width: number, + ... + }>, + ): number { + return !horizontalOrDefault(this.props.horizontal) + ? metrics.height + : metrics.width; + } + + _selectOffset( + metrics: $ReadOnly<{ + x: number, + y: number, + ... + }>, + ): number { + return !horizontalOrDefault(this.props.horizontal) ? metrics.y : metrics.x; + } + + _maybeCallOnEndReached() { + const {data, getItemCount, onEndReached, onEndReachedThreshold} = + this.props; + const {contentLength, visibleLength, offset} = this._scrollMetrics; + let distanceFromEnd = contentLength - visibleLength - offset; + + // Especially when oERT is zero it's necessary to 'floor' very small distanceFromEnd values to be 0 + // since debouncing causes us to not fire this event for every single "pixel" we scroll and can thus + // be at the "end" of the list with a distanceFromEnd approximating 0 but not quite there. + if (distanceFromEnd < ON_END_REACHED_EPSILON) { + distanceFromEnd = 0; + } + + // TODO: T121172172 Look into why we're "defaulting" to a threshold of 2 when oERT is not present + const threshold = + onEndReachedThreshold != null ? onEndReachedThreshold * visibleLength : 2; + if ( + onEndReached && + this.state.cellsAroundViewport.last === getItemCount(data) - 1 && + distanceFromEnd <= threshold && + this._scrollMetrics.contentLength !== this._sentEndForContentLength + ) { + // Only call onEndReached once for a given content length + this._sentEndForContentLength = this._scrollMetrics.contentLength; + onEndReached({distanceFromEnd}); + } else if (distanceFromEnd > threshold) { + // If the user scrolls away from the end and back again cause + // an onEndReached to be triggered again + this._sentEndForContentLength = 0; + } + } + + _onContentSizeChange = (width: number, height: number) => { + if ( + width > 0 && + height > 0 && + this.props.initialScrollIndex != null && + this.props.initialScrollIndex > 0 && + !this._hasTriggeredInitialScrollToIndex + ) { + if (this.props.contentOffset == null) { + this.scrollToIndex({ + animated: false, + index: this.props.initialScrollIndex, + }); + } + this._hasTriggeredInitialScrollToIndex = true; + } + if (this.props.onContentSizeChange) { + this.props.onContentSizeChange(width, height); + } + this._scrollMetrics.contentLength = this._selectLength({height, width}); + this._scheduleCellsToRenderUpdate(); + this._maybeCallOnEndReached(); + }; + + /* Translates metrics from a scroll event in a parent VirtualizedList into + * coordinates relative to the child list. + */ + _convertParentScrollMetrics = (metrics: { + visibleLength: number, + offset: number, + ... + }) => { + // Offset of the top of the nested list relative to the top of its parent's viewport + const offset = metrics.offset - this._offsetFromParentVirtualizedList; + // Child's visible length is the same as its parent's + const visibleLength = metrics.visibleLength; + const dOffset = offset - this._scrollMetrics.offset; + const contentLength = this._scrollMetrics.contentLength; + + return { + visibleLength, + contentLength, + offset, + dOffset, + }; + }; + + _onScroll = (e: Object) => { + this._nestedChildLists.forEach(childList => { + childList.ref && childList.ref._onScroll(e); + }); + if (this.props.onScroll) { + this.props.onScroll(e); + } + const timestamp = e.timeStamp; + let visibleLength = this._selectLength(e.nativeEvent.layoutMeasurement); + let contentLength = this._selectLength(e.nativeEvent.contentSize); + let offset = this._selectOffset(e.nativeEvent.contentOffset); + let dOffset = offset - this._scrollMetrics.offset; + + if (this._isNestedWithSameOrientation()) { + if (this._scrollMetrics.contentLength === 0) { + // Ignore scroll events until onLayout has been called and we + // know our offset from our offset from our parent + return; + } + ({visibleLength, contentLength, offset, dOffset} = + this._convertParentScrollMetrics({ + visibleLength, + offset, + })); + } + + const dt = this._scrollMetrics.timestamp + ? Math.max(1, timestamp - this._scrollMetrics.timestamp) + : 1; + const velocity = dOffset / dt; + + if ( + dt > 500 && + this._scrollMetrics.dt > 500 && + contentLength > 5 * visibleLength && + !this._hasWarned.perf + ) { + infoLog( + 'VirtualizedList: You have a large list that is slow to update - make sure your ' + + 'renderItem function renders components that follow React performance best practices ' + + 'like PureComponent, shouldComponentUpdate, etc.', + {dt, prevDt: this._scrollMetrics.dt, contentLength}, + ); + this._hasWarned.perf = true; + } + + // For invalid negative values (w/ RTL), set this to 1. + const zoomScale = e.nativeEvent.zoomScale < 0 ? 1 : e.nativeEvent.zoomScale; + this._scrollMetrics = { + contentLength, + dt, + dOffset, + offset, + timestamp, + velocity, + visibleLength, + zoomScale, + }; + this._updateViewableItems(this.props.data); + if (!this.props) { + return; + } + this._maybeCallOnEndReached(); + if (velocity !== 0) { + this._fillRateHelper.activate(); + } + this._computeBlankness(); + this._scheduleCellsToRenderUpdate(); + }; + + _scheduleCellsToRenderUpdate() { + const {first, last} = this.state.cellsAroundViewport; + const {offset, visibleLength, velocity} = this._scrollMetrics; + const itemCount = this.props.getItemCount(this.props.data); + let hiPri = false; + const onEndReachedThreshold = onEndReachedThresholdOrDefault( + this.props.onEndReachedThreshold, + ); + const scrollingThreshold = (onEndReachedThreshold * visibleLength) / 2; + // Mark as high priority if we're close to the start of the first item + // But only if there are items before the first rendered item + if (first > 0) { + const distTop = offset - this.__getFrameMetricsApprox(first).offset; + hiPri = + hiPri || distTop < 0 || (velocity < -2 && distTop < scrollingThreshold); + } + // Mark as high priority if we're close to the end of the last item + // But only if there are items after the last rendered item + if (last >= 0 && last < itemCount - 1) { + const distBottom = + this.__getFrameMetricsApprox(last).offset - (offset + visibleLength); + hiPri = + hiPri || + distBottom < 0 || + (velocity > 2 && distBottom < scrollingThreshold); + } + // Only trigger high-priority updates if we've actually rendered cells, + // and with that size estimate, accurately compute how many cells we should render. + // Otherwise, it would just render as many cells as it can (of zero dimension), + // each time through attempting to render more (limited by maxToRenderPerBatch), + // starving the renderer from actually laying out the objects and computing _averageCellLength. + // If this is triggered in an `componentDidUpdate` followed by a hiPri cellToRenderUpdate + // We shouldn't do another hipri cellToRenderUpdate + if ( + hiPri && + (this._averageCellLength || this.props.getItemLayout) && + !this._hiPriInProgress + ) { + this._hiPriInProgress = true; + // Don't worry about interactions when scrolling quickly; focus on filling content as fast + // as possible. + this._updateCellsToRenderBatcher.dispose({abort: true}); + this._updateCellsToRender(); + return; + } else { + this._updateCellsToRenderBatcher.schedule(); + } + } + + _onScrollBeginDrag = (e: ScrollEvent): void => { + this._nestedChildLists.forEach(childList => { + childList.ref && childList.ref._onScrollBeginDrag(e); + }); + this._viewabilityTuples.forEach(tuple => { + tuple.viewabilityHelper.recordInteraction(); + }); + this._hasInteracted = true; + this.props.onScrollBeginDrag && this.props.onScrollBeginDrag(e); + }; + + _onScrollEndDrag = (e: ScrollEvent): void => { + this._nestedChildLists.forEach(childList => { + childList.ref && childList.ref._onScrollEndDrag(e); + }); + const {velocity} = e.nativeEvent; + if (velocity) { + this._scrollMetrics.velocity = this._selectOffset(velocity); + } + this._computeBlankness(); + this.props.onScrollEndDrag && this.props.onScrollEndDrag(e); + }; + + _onMomentumScrollBegin = (e: ScrollEvent): void => { + this._nestedChildLists.forEach(childList => { + childList.ref && childList.ref._onMomentumScrollBegin(e); + }); + this.props.onMomentumScrollBegin && this.props.onMomentumScrollBegin(e); + }; + + _onMomentumScrollEnd = (e: ScrollEvent): void => { + this._nestedChildLists.forEach(childList => { + childList.ref && childList.ref._onMomentumScrollEnd(e); + }); + this._scrollMetrics.velocity = 0; + this._computeBlankness(); + this.props.onMomentumScrollEnd && this.props.onMomentumScrollEnd(e); + }; + + _updateCellsToRender = () => { + this.setState((state, props) => { + const cellsAroundViewport = this._adjustCellsAroundViewport( + props, + state.cellsAroundViewport, + ); + const renderMask = VirtualizedList._createRenderMask( + props, + cellsAroundViewport, + this._getNonViewportRenderRegions(), + ); + + if ( + cellsAroundViewport.first === state.cellsAroundViewport.first && + cellsAroundViewport.last === state.cellsAroundViewport.last && + renderMask.equals(state.renderMask) + ) { + return null; + } + + return {cellsAroundViewport, renderMask}; + }); + }; + + _createViewToken = (index: number, isViewable: boolean) => { + const {data, getItem} = this.props; + const item = getItem(data, index); + return {index, item, key: this._keyExtractor(item, index), isViewable}; + }; + + __getFrameMetricsApprox: (index: number) => { + length: number, + offset: number, + ... + } = index => { + const frame = this._getFrameMetrics(index); + if (frame && frame.index === index) { + // check for invalid frames due to row re-ordering + return frame; + } else { + const {data, getItemCount, getItemLayout} = this.props; + invariant( + index >= 0 && index < getItemCount(data), + 'Tried to get frame for out of range index ' + index, + ); + invariant( + !getItemLayout, + 'Should not have to estimate frames when a measurement metrics function is provided', + ); + return { + length: this._averageCellLength, + offset: this._averageCellLength * index, + }; + } + }; + + _getFrameMetrics = ( + index: number, + ): ?{ + length: number, + offset: number, + index: number, + inLayout?: boolean, + ... + } => { + const {data, getItem, getItemCount, getItemLayout} = this.props; + invariant( + index >= 0 && index < getItemCount(data), + 'Tried to get frame for out of range index ' + index, + ); + const item = getItem(data, index); + const frame = item && this._frames[this._keyExtractor(item, index)]; + if (!frame || frame.index !== index) { + if (getItemLayout) { + /* $FlowFixMe[prop-missing] (>=0.63.0 site=react_native_fb) This comment + * suppresses an error found when Flow v0.63 was deployed. To see the error + * delete this comment and run Flow. */ + return getItemLayout(data, index); + } + } + return frame; + }; + + _getNonViewportRenderRegions = (): $ReadOnlyArray<{ + first: number, + last: number, + }> => { + // Keep a viewport's worth of content around the last focused cell to allow + // random navigation around it without any blanking. E.g. tabbing from one + // focused item out of viewport to another. + if ( + !(this._lastFocusedCellKey && this._cellRefs[this._lastFocusedCellKey]) + ) { + return []; + } + + const lastFocusedCellRenderer = this._cellRefs[this._lastFocusedCellKey]; + const focusedCellIndex = lastFocusedCellRenderer.props.index; + const itemCount = this.props.getItemCount(this.props.data); + + // The cell may have been unmounted and have a stale index + if ( + focusedCellIndex >= itemCount || + this._indicesToKeys.get(focusedCellIndex) !== this._lastFocusedCellKey + ) { + return []; + } + + let first = focusedCellIndex; + let heightOfCellsBeforeFocused = 0; + for ( + let i = first - 1; + i >= 0 && heightOfCellsBeforeFocused < this._scrollMetrics.visibleLength; + i-- + ) { + first--; + heightOfCellsBeforeFocused += this.__getFrameMetricsApprox(i).length; + } + + let last = focusedCellIndex; + let heightOfCellsAfterFocused = 0; + for ( + let i = last + 1; + i < itemCount && + heightOfCellsAfterFocused < this._scrollMetrics.visibleLength; + i++ + ) { + last++; + heightOfCellsAfterFocused += this.__getFrameMetricsApprox(i).length; + } + + return [{first, last}]; + }; + + _updateViewableItems(data: any) { + const {getItemCount} = this.props; + + this._viewabilityTuples.forEach(tuple => { + tuple.viewabilityHelper.onUpdate( + getItemCount(data), + this._scrollMetrics.offset, + this._scrollMetrics.visibleLength, + this._getFrameMetrics, + this._createViewToken, + tuple.onViewableItemsChanged, + this.state.cellsAroundViewport, + ); + }); + } +} + +type CellRendererProps = { + CellRendererComponent?: ?React.ComponentType, + ItemSeparatorComponent: ?React.ComponentType< + any | {highlighted: boolean, leadingItem: ?Item}, + >, + ListItemComponent?: ?(React.ComponentType | React.Element), + cellKey: string, + debug?: ?boolean, + fillRateHelper: FillRateHelper, + getItemLayout?: ( + data: any, + index: number, + ) => { + length: number, + offset: number, + index: number, + ... + }, + horizontal: ?boolean, + index: number, + inversionStyle: ViewStyleProp, + item: Item, + // This is extracted by ScrollViewStickyHeader + onCellLayout: (event: Object, cellKey: string, index: number) => void, + onUnmount: (cellKey: string) => void, + onUpdateSeparators: (cellKeys: Array, props: Object) => void, + prevCellKey: ?string, + onFocusCapture: (event: FocusEvent) => void, + renderItem?: ?RenderItemType, + ... +}; + +type CellRendererState = { + separatorProps: $ReadOnly<{| + highlighted: boolean, + leadingItem: ?Item, + |}>, + ... +}; + +class CellRenderer extends React.Component< + CellRendererProps, + CellRendererState, +> { + state = { + separatorProps: { + highlighted: false, + leadingItem: this.props.item, + }, + }; + + static getDerivedStateFromProps( + props: CellRendererProps, + prevState: CellRendererState, + ): ?CellRendererState { + return { + separatorProps: { + ...prevState.separatorProps, + leadingItem: props.item, + }, + }; + } + + // TODO: consider factoring separator stuff out of VirtualizedList into FlatList since it's not + // reused by SectionList and we can keep VirtualizedList simpler. + _separators = { + highlight: () => { + const {cellKey, prevCellKey} = this.props; + this.props.onUpdateSeparators([cellKey, prevCellKey], { + highlighted: true, + }); + }, + unhighlight: () => { + const {cellKey, prevCellKey} = this.props; + this.props.onUpdateSeparators([cellKey, prevCellKey], { + highlighted: false, + }); + }, + updateProps: (select: 'leading' | 'trailing', newProps: Object) => { + const {cellKey, prevCellKey} = this.props; + this.props.onUpdateSeparators( + [select === 'leading' ? prevCellKey : cellKey], + newProps, + ); + }, + }; + + updateSeparatorProps(newProps: Object) { + this.setState(state => ({ + separatorProps: {...state.separatorProps, ...newProps}, + })); + } + + componentWillUnmount() { + this.props.onUnmount(this.props.cellKey); + } + + _onLayout = (nativeEvent: LayoutEvent): void => { + this.props.onCellLayout && + this.props.onCellLayout( + nativeEvent, + this.props.cellKey, + this.props.index, + ); + }; + + _renderElement( + renderItem: any, + ListItemComponent: any, + item: any, + index: any, + ) { + if (renderItem && ListItemComponent) { + console.warn( + 'VirtualizedList: Both ListItemComponent and renderItem props are present. ListItemComponent will take' + + ' precedence over renderItem.', + ); + } + + if (ListItemComponent) { + /* $FlowFixMe[not-a-component] (>=0.108.0 site=react_native_fb) This + * comment suppresses an error found when Flow v0.108 was deployed. To + * see the error, delete this comment and run Flow. */ + /* $FlowFixMe[incompatible-type-arg] (>=0.108.0 site=react_native_fb) + * This comment suppresses an error found when Flow v0.108 was deployed. + * To see the error, delete this comment and run Flow. */ + return React.createElement(ListItemComponent, { + item, + index, + separators: this._separators, + }); + } + + if (renderItem) { + return renderItem({ + item, + index, + separators: this._separators, + }); + } + + invariant( + false, + 'VirtualizedList: Either ListItemComponent or renderItem props are required but none were found.', + ); + } + + render() { + const { + CellRendererComponent, + ItemSeparatorComponent, + ListItemComponent, + debug, + fillRateHelper, + getItemLayout, + horizontal, + item, + index, + inversionStyle, + onFocusCapture, + renderItem, + } = this.props; + const element = this._renderElement( + renderItem, + ListItemComponent, + item, + index, + ); + + const onLayout = + (getItemLayout && !debug && !fillRateHelper.enabled()) || + !this.props.onCellLayout + ? undefined + : this._onLayout; + // NOTE: that when this is a sticky header, `onLayout` will get automatically extracted and + // called explicitly by `ScrollViewStickyHeader`. + const itemSeparator = React.isValidElement(ItemSeparatorComponent) + ? ItemSeparatorComponent + : ItemSeparatorComponent && ( + + ); + const cellStyle = inversionStyle + ? horizontal + ? [styles.rowReverse, inversionStyle] + : [styles.columnReverse, inversionStyle] + : horizontal + ? [styles.row, inversionStyle] + : inversionStyle; + const result = !CellRendererComponent ? ( + =0.89.0 site=react_native_fb) * + This comment suppresses an error found when Flow v0.89 was deployed. * + To see the error, delete this comment and run Flow. */ + > + {element} + {itemSeparator} + + ) : ( + + {element} + {itemSeparator} + + ); + + return ( + + {result} + + ); + } +} + +function describeNestedLists(childList: { + +cellKey: string, + +key: string, + +ref: VirtualizedList, + +parentDebugInfo: ListDebugInfo, + +horizontal: boolean, + ... +}) { + let trace = + 'VirtualizedList trace:\n' + + ` Child (${childList.horizontal ? 'horizontal' : 'vertical'}):\n` + + ` listKey: ${childList.key}\n` + + ` cellKey: ${childList.cellKey}`; + + let debugInfo: ?ListDebugInfo = childList.parentDebugInfo; + while (debugInfo) { + trace += + `\n Parent (${debugInfo.horizontal ? 'horizontal' : 'vertical'}):\n` + + ` listKey: ${debugInfo.listKey}\n` + + ` cellKey: ${debugInfo.cellKey}`; + debugInfo = debugInfo.parent; + } + return trace; +} + +const styles = StyleSheet.create({ + verticallyInverted: { + transform: [{scaleY: -1}], + }, + horizontallyInverted: { + transform: [{scaleX: -1}], + }, + row: { + flexDirection: 'row', + }, + rowReverse: { + flexDirection: 'row-reverse', + }, + columnReverse: { + flexDirection: 'column-reverse', + }, + debug: { + flex: 1, + }, + debugOverlayBase: { + position: 'absolute', + top: 0, + right: 0, + }, + debugOverlay: { + bottom: 0, + width: 20, + borderColor: 'blue', + borderWidth: 1, + }, + debugOverlayFrame: { + left: 0, + backgroundColor: 'orange', + }, + debugOverlayFrameLast: { + left: 0, + borderColor: 'green', + borderWidth: 2, + }, + debugOverlayFrameVis: { + left: 0, + borderColor: 'red', + borderWidth: 2, + }, +}); + +module.exports = VirtualizedList; diff --git a/Libraries/Lists/__tests__/VirtualizedList-test.js b/Libraries/Lists/__tests__/VirtualizedList-test.js index d4a56e5636fc..904d2f155133 100644 --- a/Libraries/Lists/__tests__/VirtualizedList-test.js +++ b/Libraries/Lists/__tests__/VirtualizedList-test.js @@ -10,8 +10,18 @@ 'use strict'; -const React = require('react'); -const ReactTestRenderer = require('react-test-renderer'); +import React from 'react'; +import ReactTestRenderer from 'react-test-renderer'; +import VirtualizedListInjection from '../VirtualizedListInjection'; +import VirtualizedList_EXPERIMENTAL from '../VirtualizedList_EXPERIMENTAL'; + +const useExperimentalList = + process.env.USE_EXPERIMENTAL_VIRTUALIZEDLIST === 'true'; + +if (useExperimentalList) { + VirtualizedListInjection.unstable_VirtualizedList = + VirtualizedList_EXPERIMENTAL; +} const VirtualizedList = require('../VirtualizedList'); @@ -1498,6 +1508,188 @@ it('calls _onCellLayout properly', () => { expect(mock).not.toHaveBeenCalledWith(event, 'i3', 2); }); +if (useExperimentalList) { + describe('VirtualizedList (Experimental functionality)', () => { + it('keeps viewport below last focused rendered', () => { + const items = generateItems(20); + const ITEM_HEIGHT = 10; + + let component; + ReactTestRenderer.act(() => { + component = ReactTestRenderer.create( + , + ); + }); + + ReactTestRenderer.act(() => { + simulateLayout(component, { + viewport: {width: 10, height: 50}, + content: {width: 10, height: 200}, + }); + + performAllBatches(); + }); + + ReactTestRenderer.act(() => { + component.getInstance()._onCellFocusCapture(3); + }); + + ReactTestRenderer.act(() => { + simulateScroll(component, {x: 0, y: 150}); + performAllBatches(); + }); + + // Cells 1-8 should remain rendered after scrolling to the bottom of the list + expect(component).toMatchSnapshot(); + }); + + it('virtualizes away last focused item if focus changes to a new cell', () => { + const items = generateItems(20); + const ITEM_HEIGHT = 10; + + let component; + ReactTestRenderer.act(() => { + component = ReactTestRenderer.create( + , + ); + }); + + ReactTestRenderer.act(() => { + simulateLayout(component, { + viewport: {width: 10, height: 50}, + content: {width: 10, height: 200}, + }); + + performAllBatches(); + }); + + ReactTestRenderer.act(() => { + component.getInstance()._onCellFocusCapture(3); + }); + + ReactTestRenderer.act(() => { + simulateScroll(component, {x: 0, y: 150}); + performAllBatches(); + }); + + ReactTestRenderer.act(() => { + component.getInstance()._onCellFocusCapture(17); + }); + + // Cells 1-8 should no longer be rendered after focus is moved to the end of + // the list + expect(component).toMatchSnapshot(); + }); + + it('keeps viewport above last focused rendered', () => { + const items = generateItems(20); + const ITEM_HEIGHT = 10; + + let component; + ReactTestRenderer.act(() => { + component = ReactTestRenderer.create( + , + ); + }); + + ReactTestRenderer.act(() => { + simulateLayout(component, { + viewport: {width: 10, height: 50}, + content: {width: 10, height: 200}, + }); + + performAllBatches(); + }); + + ReactTestRenderer.act(() => { + component.getInstance()._onCellFocusCapture(3); + }); + + ReactTestRenderer.act(() => { + simulateScroll(component, {x: 0, y: 150}); + performAllBatches(); + }); + + ReactTestRenderer.act(() => { + component.getInstance()._onCellFocusCapture(17); + }); + + ReactTestRenderer.act(() => { + simulateScroll(component, {x: 0, y: 0}); + performAllBatches(); + }); + + // Cells 12-19 should remain rendered after scrolling to the top of the list + expect(component).toMatchSnapshot(); + }); + + it('virtualizes away last focused index if item removed', () => { + const items = generateItems(20); + const ITEM_HEIGHT = 10; + + let component; + ReactTestRenderer.act(() => { + component = ReactTestRenderer.create( + , + ); + }); + + ReactTestRenderer.act(() => { + simulateLayout(component, { + viewport: {width: 10, height: 50}, + content: {width: 10, height: 200}, + }); + + performAllBatches(); + }); + + ReactTestRenderer.act(() => { + component.getInstance()._onCellFocusCapture(3); + }); + + ReactTestRenderer.act(() => { + simulateScroll(component, {x: 0, y: 150}); + performAllBatches(); + }); + + const itemsWithoutFocused = [...items.slice(0, 3), ...items.slice(4)]; + ReactTestRenderer.act(() => { + component.update( + , + ); + }); + + // Cells 1-8 should no longer be rendered + expect(component).toMatchSnapshot(); + }); + }); +} + function generateItems(count) { return Array(count) .fill() diff --git a/Libraries/Lists/__tests__/VirtualizedList_EXPERIMENTAL-test.js b/Libraries/Lists/__tests__/VirtualizedList_EXPERIMENTAL-test.js new file mode 100644 index 000000000000..27b8fd900cdd --- /dev/null +++ b/Libraries/Lists/__tests__/VirtualizedList_EXPERIMENTAL-test.js @@ -0,0 +1,14 @@ +/** + * 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 + * @emails oncall+react_native + */ + +'use strict'; + +process.env.USE_EXPERIMENTAL_VIRTUALIZEDLIST = 'true'; +require('./VirtualizedList-test'); diff --git a/Libraries/Lists/__tests__/__snapshots__/VirtualizedList_EXPERIMENTAL-test.js.snap b/Libraries/Lists/__tests__/__snapshots__/VirtualizedList_EXPERIMENTAL-test.js.snap new file mode 100644 index 000000000000..3cc1c3c52ba3 --- /dev/null +++ b/Libraries/Lists/__tests__/__snapshots__/VirtualizedList_EXPERIMENTAL-test.js.snap @@ -0,0 +1,5368 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`VirtualizedList (Experimental functionality) keeps viewport above last focused rendered 1`] = ` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +`; + +exports[`VirtualizedList (Experimental functionality) keeps viewport below last focused rendered 1`] = ` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +`; + +exports[`VirtualizedList (Experimental functionality) virtualizes away last focused index if item removed 1`] = ` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +`; + +exports[`VirtualizedList (Experimental functionality) virtualizes away last focused item if focus changes to a new cell 1`] = ` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +`; + +exports[`VirtualizedList forwards correct stickyHeaderIndices when ListHeaderComponent present 1`] = ` + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +`; + +exports[`VirtualizedList forwards correct stickyHeaderIndices when all in initial render window 1`] = ` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +`; + +exports[`VirtualizedList forwards correct stickyHeaderIndices when partially in initial render window 1`] = ` + + + + + + + + + + + + + + + + + + + + +`; + +exports[`VirtualizedList handles nested lists 1`] = ` + + + + + + + + + + + + + + + + + + + + + + + + + + +`; + +exports[`VirtualizedList handles separators correctly 1`] = ` + + + + + + + + + + + + + + + +`; + +exports[`VirtualizedList handles separators correctly 2`] = ` + + + + + + + + + + + + + + + +`; + +exports[`VirtualizedList handles separators correctly 3`] = ` + + + + + + + + + + + + + + + +`; + +exports[`VirtualizedList keeps sticky headers above viewport visualized 1`] = ` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +`; + +exports[`VirtualizedList renders all the bells and whistles 1`] = ` + + } + refreshing={false} + renderItem={[Function]} + scrollEventThrottle={50} + stickyHeaderIndices={Array []} + style={ + Array [ + Object { + "transform": Array [ + Object { + "scaleY": -1, + }, + ], + }, + undefined, + ] + } +> + + + +
+ + + + + + + + + + + + + + + + + + + + + +