diff --git a/.circleci/Dockerfiles/Dockerfile.android b/.circleci/Dockerfiles/Dockerfile.android index 6b54b14815ca70..4038101a28bf4f 100644 --- a/.circleci/Dockerfiles/Dockerfile.android +++ b/.circleci/Dockerfiles/Dockerfile.android @@ -14,7 +14,7 @@ # and build a Android application that can be used to run the # tests specified in the scripts/ directory. # -FROM reactnativecommunity/react-native-android:6.2 +FROM reactnativecommunity/react-native-android:7.0 LABEL Description="React Native Android Test Image" LABEL maintainer="Héctor Ramos " diff --git a/.circleci/config.yml b/.circleci/config.yml index 464cef6c10bfdd..768337f5995bd5 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -111,7 +111,7 @@ executors: reactnativeandroid: <<: *defaults docker: - - image: reactnativecommunity/react-native-android:6.2 + - image: reactnativecommunity/react-native-android:7.0 resource_class: "xlarge" environment: - TERM: "dumb" @@ -448,24 +448,9 @@ jobs: steps: - checkout - run_yarn - - - # Note: The yarn gpg key needs to be refreshed to work around https://github.com/yarnpkg/yarn/issues/7866 - - run: - name: Install additional GitHub bot dependencies - # TEMP: Added workaround from https://github.com/nodesource/distributions/issues/1266#issuecomment-932583579 - command: | - curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - - apt update && apt install -y shellcheck jq - apt-get -y install openssl ca-certificates - update-ca-certificates - curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - - apt update && apt install -y shellcheck jq - - run: name: Run linters against modified files (analysis-bot) command: GITHUB_TOKEN="$PUBLIC_ANALYSISBOT_GITHUB_TOKEN_A""$PUBLIC_ANALYSISBOT_GITHUB_TOKEN_B" yarn lint-ci - when: always # ------------------------- # JOBS: Analyze Code @@ -853,7 +838,7 @@ jobs: default: "StaticLibraries" description: Which kind of option we want to use for `use_frameworks!` type: enum - enum: ["StaticLibraries", "StaticFrameworks"] #TODO: Add "DynamicFrameworks" + enum: ["StaticLibraries", "StaticFrameworks", "DynamicFrameworks"] environment: - PROJECT_NAME: "iOSTemplateProject" - HERMES_WS_DIR: *hermes_workspace_root @@ -906,6 +891,8 @@ jobs: if [[ << parameters.use_frameworks >> == "StaticFrameworks" ]]; then export USE_FRAMEWORKS=static + elif [[ << parameters.use_frameworks >> == "DynamicFrameworks" ]]; then + export USE_FRAMEWORKS=dynamic fi bundle exec pod install @@ -1452,9 +1439,7 @@ jobs: - download_gradle_dependencies # START: Stables and nightlies - # This conditional step sets up the necessary credentials for publishing react-native to npm, - # and for interacting with GitHub as the react-native-bot account. Important: these steps - # should not be allowed to run on commits from pull requests. + # This conditional step sets up the necessary credentials for publishing react-native to npm. - when: condition: or: @@ -1636,7 +1621,7 @@ workflows: flavor: ["Debug", "Release"] jsengine: ["Hermes", "JSC"] flipper: ["WithFlipper", "WithoutFlipper"] - use_frameworks: [ "StaticLibraries", "StaticFrameworks" ] #TODO: make it works with DynamicFrameworks + use_frameworks: ["StaticLibraries", "StaticFrameworks", "DynamicFrameworks"] exclude: - architecture: "NewArch" flavor: "Release" @@ -1648,11 +1633,21 @@ workflows: jsengine: "Hermes" flipper: "WithFlipper" use_frameworks: "StaticFrameworks" + - architecture: "NewArch" + flavor: "Release" + jsengine: "Hermes" + flipper: "WithFlipper" + use_frameworks: "DynamicFrameworks" - architecture: "NewArch" flavor: "Release" jsengine: "Hermes" flipper: "WithoutFlipper" use_frameworks: "StaticFrameworks" + - architecture: "NewArch" + flavor: "Release" + jsengine: "Hermes" + flipper: "WithoutFlipper" + use_frameworks: "DynamicFrameworks" - architecture: "NewArch" flavor: "Release" jsengine: "JSC" @@ -1663,11 +1658,21 @@ workflows: jsengine: "JSC" flipper: "WithFlipper" use_frameworks: "StaticFrameworks" + - architecture: "NewArch" + flavor: "Release" + jsengine: "JSC" + flipper: "WithFlipper" + use_frameworks: "DynamicFrameworks" - architecture: "NewArch" flavor: "Release" jsengine: "JSC" flipper: "WithoutFlipper" use_frameworks: "StaticFrameworks" + - architecture: "NewArch" + flavor: "Release" + jsengine: "JSC" + flipper: "WithoutFlipper" + use_frameworks: "DynamicFrameworks" - architecture: "OldArch" flavor: "Release" jsengine: "Hermes" @@ -1678,6 +1683,11 @@ workflows: jsengine: "Hermes" flipper: "WithFlipper" use_frameworks: "StaticFrameworks" + - architecture: "OldArch" + flavor: "Release" + jsengine: "Hermes" + flipper: "WithFlipper" + use_frameworks: "DynamicFrameworks" - architecture: "OldArch" flavor: "Release" jsengine: "JSC" @@ -1688,6 +1698,11 @@ workflows: jsengine: "JSC" flipper: "WithFlipper" use_frameworks: "StaticFrameworks" + - architecture: "OldArch" + flavor: "Release" + jsengine: "JSC" + flipper: "WithFlipper" + use_frameworks: "DynamicFrameworks" - architecture: "NewArch" flavor: "Debug" jsengine: "Hermes" @@ -1718,6 +1733,36 @@ workflows: jsengine: "JSC" flipper: "WithFlipper" use_frameworks: "StaticFrameworks" + - architecture: "NewArch" + flavor: "Debug" + jsengine: "Hermes" + flipper: "WithFlipper" + use_frameworks: "DynamicFrameworks" + - architecture: "NewArch" + flavor: "Debug" + jsengine: "Hermes" + flipper: "WithoutFlipper" + use_frameworks: "DynamicFrameworks" + - architecture: "NewArch" + flavor: "Debug" + jsengine: "JSC" + flipper: "WithFlipper" + use_frameworks: "DynamicFrameworks" + - architecture: "NewArch" + flavor: "Debug" + jsengine: "JSC" + flipper: "WithoutFlipper" + use_frameworks: "DynamicFrameworks" + - architecture: "OldArch" + flavor: "Debug" + jsengine: "Hermes" + flipper: "WithFlipper" + use_frameworks: "DynamicFrameworks" + - architecture: "OldArch" + flavor: "Debug" + jsengine: "JSC" + flipper: "WithFlipper" + use_frameworks: "DynamicFrameworks" - test_ios_rntester: requires: - build_hermes_macos @@ -1778,7 +1823,6 @@ workflows: # This job will trigger when a version tag is pushed (by package_release) - build_npm_package: name: build_and_publish_npm_package - context: react-native-bot release_type: "release" filters: *only_release_tags requires: @@ -1814,7 +1858,6 @@ workflows: - prepare_hermes_workspace - build_npm_package: name: build_and_publish_npm_package - context: react-native-bot release_type: "dry-run" requires: - build_hermesc_linux diff --git a/.flowconfig b/.flowconfig index b332bb2b0c0b9a..132a3aeeda51d6 100644 --- a/.flowconfig +++ b/.flowconfig @@ -29,6 +29,8 @@ interface.js flow/ [options] +enums=true + emoji=true exact_by_default=true @@ -74,4 +76,4 @@ untyped-import untyped-type-import [version] -^0.198.2 +^0.199.1 diff --git a/.flowconfig.android b/.flowconfig.android index 2c8f824a6548b3..406d98a2231d5a 100644 --- a/.flowconfig.android +++ b/.flowconfig.android @@ -29,6 +29,8 @@ interface.js flow/ [options] +enums=true + emoji=true exact_by_default=true @@ -74,4 +76,4 @@ untyped-import untyped-type-import [version] -^0.198.2 +^0.199.1 diff --git a/.github/workflows/on-issue-labeled.yml b/.github/workflows/on-issue-labeled.yml index 8207432ec8cd30..ae55455cfd1316 100644 --- a/.github/workflows/on-issue-labeled.yml +++ b/.github/workflows/on-issue-labeled.yml @@ -182,3 +182,22 @@ jobs: repo: context.repo.repo, labels: ['Needs: Author Feedback'] }) + type-expo: + runs-on: ubuntu-latest + if: "${{ contains(github.event.label.name, 'Type: Expo') }}" + steps: + - uses: actions/github-script@v6 + with: + script: | + await github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: `It looks like your issue is related to Expo and not React Native core. Please open your issue on an [Expo's repository](https://github.com/expo/expo/issues/new). If you are able to create a repro that showcases that this issue is also happening in React Native vanilla, we will be happy to re-open.`, + }) + await github.rest.issues.update({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + state: "closed", + }) diff --git a/BUCK b/BUCK index c33ea5e8e6264f..37f5bb531bae4f 100644 --- a/BUCK +++ b/BUCK @@ -724,6 +724,8 @@ rn_library( "Libraries/**/*.js", "Libraries/NewAppScreen/**/*.png", "Libraries/LogBox/**/*.png", + "packages/virtualized-lists/**/*.js", + "packages/virtualized-lists/**/*.json", ], exclude = [ "**/__*__/**", diff --git a/CHANGELOG.md b/CHANGELOG.md index 14b140c5945c56..61e7b129eaa2c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,35 @@ # Changelog +## v0.71.2 + +### Added + +- Added AlertOptions argument to the type definition for Alert.prompt to bring it into parity with the js code. ([305ca337c0](https://github.com/facebook/react-native/commit/305ca337c0471c61cb74216bd93ae3f1a232a89f) by [@paulmand3l](https://github.com/paulmand3l)) +- Added missing `accessibilityLabelledBy` TypeScript type ([e162b07982](https://github.com/facebook/react-native/commit/e162b07982cf9481038de71f5dd7bd9b45387f0a) by [@DimitarNestorov](https://github.com/DimitarNestorov)) +- Added missing `accessibilityLanguage` TypeScript type ([71c4f57baf](https://github.com/facebook/react-native/commit/71c4f57baf6683ea4304e15c040d6b6c3b3d2b73) by [@DimitarNestorov](https://github.com/DimitarNestorov)) + +### Changed + +- Bump `react-native-gradle-plugin` to `^0.71.14` in core, `@react-native-community/eslint-config` to `^3.2.0` in starting template ([785bc8d97b](https://github.com/facebook/react-native/commit/785bc8d97b824a2af86ffe46f321471f4952764c) by [@kelset](https://github.com/kelset)) + +### Fixed + +- Add `TextInput`'s `inputMode` TypeScript types ([fac7859863](https://github.com/facebook/react-native/commit/fac7859863c7130740aacc95d0e62417bd8f789e) by [@eps1lon](https://github.com/eps1lon)) +- Fix crash by conditional value of aspectRatio style value ([a8166bd75b](https://github.com/facebook/react-native/commit/a8166bd75b221f967a859d5cc25b3394c4d35301) by [@mym0404](https://github.com/mym0404)) +- Fix TurboModuleRegistry TS type ([c289442848](https://github.com/facebook/react-native/commit/c28944284894a3188b97e3d8bb5b489755852160) by [@janicduplessis](https://github.com/janicduplessis)) +- Fix invariant violation when nesting VirtualizedList inside ListEmptyComponent ([1fef376812](https://github.com/facebook/react-native/commit/1fef37681298c828a07febcd0d975a32f6bc4403) by [@NickGerleman](https://github.com/NickGerleman)) + +#### Android specific + +- [RNGP] Properly set the `jsRootDir` default value ([c0004092f9](https://github.com/facebook/react-native/commit/c0004092f935ad892d4a1acf38fb184f1140bfd2) by [@cortinico](https://github.com/cortinico)) +- Do not use WindowInsetsCompat for Keyboard Events ([32f54877ff](https://github.com/facebook/react-native/commit/32f54877ff788240d24528d208c704ee78e4e761) by [@NickGerleman](https://github.com/NickGerleman)) +- Mitigation for Samsung TextInput Hangs ([4650ef3](https://github.com/facebook/react-native/commit/4650ef36e3d63df6e6a31f00fcf323c53daff2d6) by [@NickGerleman](https://github.com/NickGerleman)) + +#### iOS specific + +- Add Back dynamic framework support for the Old Architecture with Hermes ([b3040ec624](https://github.com/facebook/react-native/commit/b3040ec6244da6ea274654abfd84516de4f5bf52) by [@cipolleschi](https://github.com/cipolleschi)) +- Add Back dynamic framework support for the old architecture ([da270d038c](https://github.com/facebook/react-native/commit/da270d038c271d6b82de568621b49e38739372c6) by [@cipolleschi](https://github.com/cipolleschi)) + ## v0.71.1 ### Added @@ -456,6 +486,24 @@ Read the [announcement blogpost here](https://reactnative.dev/blog/2023/01/12/ve - Bump terser minor version to mitigate CVE-2022-25858 ([743f9ff63b](https://github.com/facebook/react-native/commit/743f9ff63bf1e3825a1788978a9f6bad8ebddc0d) by [@GijsWeterings](https://github.com/GijsWeterings)) +## v0.70.7 + +### Fixed + +#### Android specific + +- Mitigation for Samsung TextInput Hangs ([be69c8b5a7](https://github.com/facebook/react-native/commit/be69c8b5a77ae60cced1b2af64e48b90d9955be5) by [@NickGerleman](https://github.com/NickGerleman)) + +#### iOS Specific + +- Fix the potential race condition when dismissing and presenting modal ([279fb52e03](https://github.com/facebook/react-native/commit/279fb52e033daba60393e400e1ee585e7d067090) by [@wood1986](https://github.com/wood1986)) + +### Added + +#### Android Specific + +- Add `POST_NOTIFICATIONS` and deprecate `POST_NOTIFICATION` ([b5280bbc93](https://github.com/facebook/react-native/commit/b5280bbc93218bd15e2166b8689c1689200bb92c) by [@dcangulo](https://github.com/dcangulo)) + ## v0.70.6 ### Fixed @@ -744,6 +792,22 @@ Read the [announcement blogpost here](https://reactnative.dev/blog/2023/01/12/ve - Add GitHub token permissions for workflows ([3da3d82320](https://github.com/facebook/react-native/commit/3da3d82320bd035c6bd361a82ea12a70dba4e851) by [@varunsh-coder](https://github.com/varunsh-coder)) - Bump RCT-Folly to 2021-07-22 ([68f3a42fc7](https://github.com/facebook/react-native/commit/68f3a42fc7380051714253f43b42175de361f8bd) by [@luissantana](https://github.com/luissantana)) +## v0.69.8 + +### Fixed + +#### Android specific + +- Mitigation for Samsung TextInput Hangs ([be69c8b5a7](https://github.com/facebook/react-native/commit/be69c8b5a77ae60cced1b2af64e48b90d9955be5) by [@NickGerleman](https://github.com/NickGerleman)) + +## v0.69.8 + +### Fixed + +#### Android specific + +- Mitigation for Samsung TextInput Hangs ([be69c8b5a7](https://github.com/facebook/react-native/commit/be69c8b5a77ae60cced1b2af64e48b90d9955be5) by [@NickGerleman](https://github.com/NickGerleman)) + ## v0.69.7 ### Fixed @@ -1044,6 +1108,22 @@ Read the [announcement blogpost here](https://reactnative.dev/blog/2023/01/12/ve - Encode URL params in URLSearchParams.toString() ([1042a8012f](https://github.com/facebook/react-native/commit/1042a8012fb472bd5c882b469fe507dd6279d562) by [@sshic](https://github.com/sshic)) +## v0.68.6 + +### Fixed + +#### Android specific + +- Mitigation for Samsung TextInput Hangs ([be69c8b5a7](https://github.com/facebook/react-native/commit/be69c8b5a77ae60cced1b2af64e48b90d9955be5) by [@NickGerleman](https://github.com/NickGerleman)) + +## v0.68.6 + +### Fixed + +#### Android specific + +- Mitigation for Samsung TextInput Hangs ([be69c8b5a7](https://github.com/facebook/react-native/commit/be69c8b5a77ae60cced1b2af64e48b90d9955be5) by [@NickGerleman](https://github.com/NickGerleman)) + ## v0.68.5 ### Fixed diff --git a/Libraries/Blob/React-RCTBlob.podspec b/Libraries/Blob/React-RCTBlob.podspec index 3d69eeced3ac9b..b3a557dbaeac81 100644 --- a/Libraries/Blob/React-RCTBlob.podspec +++ b/Libraries/Blob/React-RCTBlob.podspec @@ -45,4 +45,8 @@ Pod::Spec.new do |s| s.dependency "React-Core/RCTBlobHeaders", version s.dependency "React-Core/RCTWebSocket", version s.dependency "React-RCTNetwork", version + + if ENV["USE_HERMES"] == nil || ENV["USE_HERMES"] == "1" + s.dependency "hermes-engine" + end end diff --git a/Libraries/Components/View/ReactNativeStyleAttributes.js b/Libraries/Components/View/ReactNativeStyleAttributes.js index 7408b96a461432..13d8db56a5fe67 100644 --- a/Libraries/Components/View/ReactNativeStyleAttributes.js +++ b/Libraries/Components/View/ReactNativeStyleAttributes.js @@ -117,6 +117,9 @@ const ReactNativeStyleAttributes: {[string]: AnyAttributeType, ...} = { */ backfaceVisibility: true, backgroundColor: colorAttributes, + borderBlockColor: colorAttributes, + borderBlockEndColor: colorAttributes, + borderBlockStartColor: colorAttributes, borderBottomColor: colorAttributes, borderBottomEndRadius: true, borderBottomLeftRadius: true, diff --git a/Libraries/Components/View/ViewNativeComponent.js b/Libraries/Components/View/ViewNativeComponent.js index b60bc0a8d1efec..d8052fb9889b02 100644 --- a/Libraries/Components/View/ViewNativeComponent.js +++ b/Libraries/Components/View/ViewNativeComponent.js @@ -85,6 +85,15 @@ export const __INTERNAL_VIEW_CONFIG: PartialViewConfig = borderEndColor: { process: require('../../StyleSheet/processColor').default, }, + borderBlockColor: { + process: require('../../StyleSheet/processColor').default, + }, + borderBlockEndColor: { + process: require('../../StyleSheet/processColor').default, + }, + borderBlockStartColor: { + process: require('../../StyleSheet/processColor').default, + }, focusable: true, overflow: true, diff --git a/Libraries/Inspector/NetworkOverlay.js b/Libraries/Inspector/NetworkOverlay.js index 169318cea27f28..c6d1ec33907e36 100644 --- a/Libraries/Inspector/NetworkOverlay.js +++ b/Libraries/Inspector/NetworkOverlay.js @@ -10,7 +10,7 @@ 'use strict'; -import type {RenderItemProps} from '../Lists/VirtualizedList'; +import type {RenderItemProps} from '@react-native/virtualized-lists'; const ScrollView = require('../Components/ScrollView/ScrollView'); const TouchableHighlight = require('../Components/Touchable/TouchableHighlight'); diff --git a/Libraries/Lists/FillRateHelper.js b/Libraries/Lists/FillRateHelper.js index 87482e73f6be3e..141fe98eb067bb 100644 --- a/Libraries/Lists/FillRateHelper.js +++ b/Libraries/Lists/FillRateHelper.js @@ -10,244 +10,10 @@ 'use strict'; -import type {FrameMetricProps} from './VirtualizedListProps'; +import {typeof FillRateHelper as FillRateHelperType} from '@react-native/virtualized-lists'; -export type FillRateInfo = Info; - -class Info { - any_blank_count: number = 0; - any_blank_ms: number = 0; - any_blank_speed_sum: number = 0; - mostly_blank_count: number = 0; - mostly_blank_ms: number = 0; - pixels_blank: number = 0; - pixels_sampled: number = 0; - pixels_scrolled: number = 0; - total_time_spent: number = 0; - sample_count: number = 0; -} - -type FrameMetrics = { - inLayout?: boolean, - length: number, - offset: number, - ... -}; - -const DEBUG = false; - -let _listeners: Array<(Info) => void> = []; -let _minSampleCount = 10; -let _sampleRate = DEBUG ? 1 : null; - -/** - * A helper class for detecting when the maximem fill rate of `VirtualizedList` is exceeded. - * By default the sampling rate is set to zero and this will do nothing. If you want to collect - * samples (e.g. to log them), make sure to call `FillRateHelper.setSampleRate(0.0-1.0)`. - * - * Listeners and sample rate are global for all `VirtualizedList`s - typical usage will combine with - * `SceneTracker.getActiveScene` to determine the context of the events. - */ -class FillRateHelper { - _anyBlankStartTime: ?number = null; - _enabled = false; - _getFrameMetrics: (index: number, props: FrameMetricProps) => ?FrameMetrics; - _info: Info = new Info(); - _mostlyBlankStartTime: ?number = null; - _samplesStartTime: ?number = null; - - static addListener(callback: FillRateInfo => void): { - remove: () => void, - ... - } { - if (_sampleRate === null) { - console.warn('Call `FillRateHelper.setSampleRate` before `addListener`.'); - } - _listeners.push(callback); - return { - remove: () => { - _listeners = _listeners.filter(listener => callback !== listener); - }, - }; - } - - static setSampleRate(sampleRate: number) { - _sampleRate = sampleRate; - } - - static setMinSampleCount(minSampleCount: number) { - _minSampleCount = minSampleCount; - } - - constructor( - getFrameMetrics: (index: number, props: FrameMetricProps) => ?FrameMetrics, - ) { - this._getFrameMetrics = getFrameMetrics; - this._enabled = (_sampleRate || 0) > Math.random(); - this._resetData(); - } - - activate() { - if (this._enabled && this._samplesStartTime == null) { - DEBUG && console.debug('FillRateHelper: activate'); - this._samplesStartTime = global.performance.now(); - } - } - - deactivateAndFlush() { - if (!this._enabled) { - return; - } - const start = this._samplesStartTime; // const for flow - if (start == null) { - DEBUG && - console.debug('FillRateHelper: bail on deactivate with no start time'); - return; - } - if (this._info.sample_count < _minSampleCount) { - // Don't bother with under-sampled events. - this._resetData(); - return; - } - const total_time_spent = global.performance.now() - start; - const info: any = { - ...this._info, - total_time_spent, - }; - if (DEBUG) { - const derived = { - avg_blankness: this._info.pixels_blank / this._info.pixels_sampled, - avg_speed: this._info.pixels_scrolled / (total_time_spent / 1000), - avg_speed_when_any_blank: - this._info.any_blank_speed_sum / this._info.any_blank_count, - any_blank_per_min: - this._info.any_blank_count / (total_time_spent / 1000 / 60), - any_blank_time_frac: this._info.any_blank_ms / total_time_spent, - mostly_blank_per_min: - this._info.mostly_blank_count / (total_time_spent / 1000 / 60), - mostly_blank_time_frac: this._info.mostly_blank_ms / total_time_spent, - }; - for (const key in derived) { - // $FlowFixMe[prop-missing] - derived[key] = Math.round(1000 * derived[key]) / 1000; - } - console.debug('FillRateHelper deactivateAndFlush: ', {derived, info}); - } - _listeners.forEach(listener => listener(info)); - this._resetData(); - } - - computeBlankness( - props: { - ...FrameMetricProps, - initialNumToRender?: ?number, - ... - }, - cellsAroundViewport: { - first: number, - last: number, - ... - }, - scrollMetrics: { - dOffset: number, - offset: number, - velocity: number, - visibleLength: number, - ... - }, - ): number { - if ( - !this._enabled || - props.getItemCount(props.data) === 0 || - cellsAroundViewport.last < cellsAroundViewport.first || - this._samplesStartTime == null - ) { - return 0; - } - const {dOffset, offset, velocity, visibleLength} = scrollMetrics; - - // Denominator metrics that we track for all events - most of the time there is no blankness and - // we want to capture that. - this._info.sample_count++; - this._info.pixels_sampled += Math.round(visibleLength); - this._info.pixels_scrolled += Math.round(Math.abs(dOffset)); - const scrollSpeed = Math.round(Math.abs(velocity) * 1000); // px / sec - - // Whether blank now or not, record the elapsed time blank if we were blank last time. - const now = global.performance.now(); - if (this._anyBlankStartTime != null) { - this._info.any_blank_ms += now - this._anyBlankStartTime; - } - this._anyBlankStartTime = null; - if (this._mostlyBlankStartTime != null) { - this._info.mostly_blank_ms += now - this._mostlyBlankStartTime; - } - this._mostlyBlankStartTime = null; - - let blankTop = 0; - let first = cellsAroundViewport.first; - let firstFrame = this._getFrameMetrics(first, props); - while ( - first <= cellsAroundViewport.last && - (!firstFrame || !firstFrame.inLayout) - ) { - firstFrame = this._getFrameMetrics(first, props); - first++; - } - // Only count blankTop if we aren't rendering the first item, otherwise we will count the header - // as blank. - if (firstFrame && first > 0) { - blankTop = Math.min( - visibleLength, - Math.max(0, firstFrame.offset - offset), - ); - } - let blankBottom = 0; - let last = cellsAroundViewport.last; - let lastFrame = this._getFrameMetrics(last, props); - while ( - last >= cellsAroundViewport.first && - (!lastFrame || !lastFrame.inLayout) - ) { - lastFrame = this._getFrameMetrics(last, props); - last--; - } - // Only count blankBottom if we aren't rendering the last item, otherwise we will count the - // footer as blank. - if (lastFrame && last < props.getItemCount(props.data) - 1) { - const bottomEdge = lastFrame.offset + lastFrame.length; - blankBottom = Math.min( - visibleLength, - Math.max(0, offset + visibleLength - bottomEdge), - ); - } - const pixels_blank = Math.round(blankTop + blankBottom); - const blankness = pixels_blank / visibleLength; - if (blankness > 0) { - this._anyBlankStartTime = now; - this._info.any_blank_speed_sum += scrollSpeed; - this._info.any_blank_count++; - this._info.pixels_blank += pixels_blank; - if (blankness > 0.5) { - this._mostlyBlankStartTime = now; - this._info.mostly_blank_count++; - } - } else if (scrollSpeed < 0.01 || Math.abs(dOffset) < 1) { - this.deactivateAndFlush(); - } - return blankness; - } - - enabled(): boolean { - return this._enabled; - } - - _resetData() { - this._anyBlankStartTime = null; - this._info = new Info(); - this._mostlyBlankStartTime = null; - this._samplesStartTime = null; - } -} +const FillRateHelper: FillRateHelperType = + require('@react-native/virtualized-lists').FillRateHelper; +export type {FillRateInfo} from '@react-native/virtualized-lists'; module.exports = FillRateHelper; diff --git a/Libraries/Lists/FlatList.d.ts b/Libraries/Lists/FlatList.d.ts index 344d5671359c45..6ac7f57fdcd843 100644 --- a/Libraries/Lists/FlatList.d.ts +++ b/Libraries/Lists/FlatList.d.ts @@ -12,7 +12,7 @@ import type { ListRenderItem, ViewToken, VirtualizedListProps, -} from './VirtualizedList'; +} from '@react-native/virtualized-lists'; import type {ScrollViewComponent} from '../Components/ScrollView/ScrollView'; import {StyleProp} from '../StyleSheet/StyleSheet'; import {ViewStyle} from '../StyleSheet/StyleSheetTypes'; diff --git a/Libraries/Lists/FlatList.js b/Libraries/Lists/FlatList.js index 56748eaf75240d..40372bc70dd311 100644 --- a/Libraries/Lists/FlatList.js +++ b/Libraries/Lists/FlatList.js @@ -11,14 +11,17 @@ import typeof ScrollViewNativeComponent from '../Components/ScrollView/ScrollViewNativeComponent'; import type {ViewStyleProp} from '../StyleSheet/StyleSheet'; import type { + RenderItemProps, + RenderItemType, ViewabilityConfigCallbackPair, ViewToken, -} from './ViewabilityHelper'; -import type {RenderItemProps, RenderItemType} from './VirtualizedList'; +} from '@react-native/virtualized-lists'; import {type ScrollResponderType} from '../Components/ScrollView/ScrollView'; -import VirtualizedList from './VirtualizedList'; -import {keyExtractor as defaultKeyExtractor} from './VirtualizeUtils'; +import { + VirtualizedList, + keyExtractor as defaultKeyExtractor, +} from '@react-native/virtualized-lists'; import memoizeOne from 'memoize-one'; const View = require('../Components/View/View'); diff --git a/Libraries/Lists/FlatList.js.flow b/Libraries/Lists/FlatList.js.flow index 10a7c9073257bd..304a1006182186 100644 --- a/Libraries/Lists/FlatList.js.flow +++ b/Libraries/Lists/FlatList.js.flow @@ -14,8 +14,13 @@ const View = require('../Components/View/View'); import typeof ScrollViewNativeComponent from '../Components/ScrollView/ScrollViewNativeComponent'; import {type ScrollResponderType} from '../Components/ScrollView/ScrollView'; import type {ViewStyleProp} from '../StyleSheet/StyleSheet'; -import type {RenderItemType} from './VirtualizedList'; -import typeof VirtualizedList from './VirtualizedList'; +import type { + RenderItemType, + RenderItemProps, + ViewToken, + ViewabilityConfigCallbackPair, +} from '@react-native/virtualized-lists'; +import {typeof VirtualizedList} from '@react-native/virtualized-lists'; type RequiredProps = {| /** diff --git a/Libraries/Lists/SectionList.d.ts b/Libraries/Lists/SectionList.d.ts index ae1b10df46a10d..7ff5bbb0a3cbe1 100644 --- a/Libraries/Lists/SectionList.d.ts +++ b/Libraries/Lists/SectionList.d.ts @@ -11,7 +11,7 @@ import type * as React from 'react'; import type { ListRenderItemInfo, VirtualizedListWithoutRenderItemProps, -} from './VirtualizedList'; +} from '@react-native/virtualized-lists'; import type { ScrollView, ScrollViewProps, diff --git a/Libraries/Lists/SectionList.js b/Libraries/Lists/SectionList.js index d452ee2b7f6419..0f199487b92a23 100644 --- a/Libraries/Lists/SectionList.js +++ b/Libraries/Lists/SectionList.js @@ -12,13 +12,13 @@ import type {ScrollResponderType} from '../Components/ScrollView/ScrollView'; import type { - Props as VirtualizedSectionListProps, ScrollToLocationParamsType, SectionBase as _SectionBase, -} from './VirtualizedSectionList'; + VirtualizedSectionListProps, +} from '@react-native/virtualized-lists'; import Platform from '../Utilities/Platform'; -import VirtualizedSectionList from './VirtualizedSectionList'; +import {VirtualizedSectionList} from '@react-native/virtualized-lists'; import * as React from 'react'; type Item = any; diff --git a/Libraries/Lists/SectionListModern.js b/Libraries/Lists/SectionListModern.js index c7856e13d9a666..d9676f106f8cfc 100644 --- a/Libraries/Lists/SectionListModern.js +++ b/Libraries/Lists/SectionListModern.js @@ -12,14 +12,14 @@ import type {ScrollResponderType} from '../Components/ScrollView/ScrollView'; import type { - Props as VirtualizedSectionListProps, ScrollToLocationParamsType, SectionBase as _SectionBase, -} from './VirtualizedSectionList'; + VirtualizedSectionListProps, +} from '@react-native/virtualized-lists'; import type {AbstractComponent, Element, ElementRef} from 'react'; import Platform from '../Utilities/Platform'; -import VirtualizedSectionList from './VirtualizedSectionList'; +import {VirtualizedSectionList} from '@react-native/virtualized-lists'; import React, {forwardRef, useImperativeHandle, useRef} from 'react'; type Item = any; diff --git a/Libraries/Lists/ViewabilityHelper.js b/Libraries/Lists/ViewabilityHelper.js index 33a9811825affd..c7dedfdf496b93 100644 --- a/Libraries/Lists/ViewabilityHelper.js +++ b/Libraries/Lists/ViewabilityHelper.js @@ -10,351 +10,15 @@ 'use strict'; -import type {FrameMetricProps} from './VirtualizedListProps'; +export type { + ViewToken, + ViewabilityConfig, + ViewabilityConfigCallbackPair, +} from '@react-native/virtualized-lists'; -const invariant = require('invariant'); +import {typeof ViewabilityHelper as ViewabilityHelperType} from '@react-native/virtualized-lists'; -export type ViewToken = { - item: any, - key: string, - index: ?number, - isViewable: boolean, - section?: any, - ... -}; - -export type ViewabilityConfigCallbackPair = { - viewabilityConfig: ViewabilityConfig, - onViewableItemsChanged: (info: { - viewableItems: Array, - changed: Array, - ... - }) => void, - ... -}; - -export type ViewabilityConfig = {| - /** - * Minimum amount of time (in milliseconds) that an item must be physically viewable before the - * viewability callback will be fired. A high number means that scrolling through content without - * stopping will not mark the content as viewable. - */ - minimumViewTime?: number, - - /** - * Percent of viewport that must be covered for a partially occluded item to count as - * "viewable", 0-100. Fully visible items are always considered viewable. A value of 0 means - * that a single pixel in the viewport makes the item viewable, and a value of 100 means that - * an item must be either entirely visible or cover the entire viewport to count as viewable. - */ - viewAreaCoveragePercentThreshold?: number, - - /** - * Similar to `viewAreaPercentThreshold`, but considers the percent of the item that is visible, - * rather than the fraction of the viewable area it covers. - */ - itemVisiblePercentThreshold?: number, - - /** - * Nothing is considered viewable until the user scrolls or `recordInteraction` is called after - * render. - */ - waitForInteraction?: boolean, -|}; - -/** - * A Utility class for calculating viewable items based on current metrics like scroll position and - * layout. - * - * An item is said to be in a "viewable" state when any of the following - * is true for longer than `minimumViewTime` milliseconds (after an interaction if `waitForInteraction` - * is true): - * - * - Occupying >= `viewAreaCoveragePercentThreshold` of the view area XOR fraction of the item - * visible in the view area >= `itemVisiblePercentThreshold`. - * - Entirely visible on screen - */ -class ViewabilityHelper { - _config: ViewabilityConfig; - _hasInteracted: boolean = false; - _timers: Set = new Set(); - _viewableIndices: Array = []; - _viewableItems: Map = new Map(); - - constructor( - config: ViewabilityConfig = {viewAreaCoveragePercentThreshold: 0}, - ) { - this._config = config; - } - - /** - * Cleanup, e.g. on unmount. Clears any pending timers. - */ - dispose() { - /* $FlowFixMe[incompatible-call] (>=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. */ - this._timers.forEach(clearTimeout); - } - - /** - * Determines which items are viewable based on the current metrics and config. - */ - computeViewableItems( - props: FrameMetricProps, - scrollOffset: number, - viewportHeight: number, - getFrameMetrics: ( - index: number, - props: FrameMetricProps, - ) => ?{ - length: number, - offset: number, - ... - }, - // Optional optimization to reduce the scan size - renderRange?: { - first: number, - last: number, - ... - }, - ): Array { - const itemCount = props.getItemCount(props.data); - const {itemVisiblePercentThreshold, viewAreaCoveragePercentThreshold} = - this._config; - const viewAreaMode = viewAreaCoveragePercentThreshold != null; - const viewablePercentThreshold = viewAreaMode - ? viewAreaCoveragePercentThreshold - : itemVisiblePercentThreshold; - invariant( - viewablePercentThreshold != null && - (itemVisiblePercentThreshold != null) !== - (viewAreaCoveragePercentThreshold != null), - 'Must set exactly one of itemVisiblePercentThreshold or viewAreaCoveragePercentThreshold', - ); - const viewableIndices = []; - if (itemCount === 0) { - return viewableIndices; - } - let firstVisible = -1; - const {first, last} = renderRange || {first: 0, last: itemCount - 1}; - if (last >= itemCount) { - console.warn( - 'Invalid render range computing viewability ' + - JSON.stringify({renderRange, itemCount}), - ); - return []; - } - for (let idx = first; idx <= last; idx++) { - const metrics = getFrameMetrics(idx, props); - if (!metrics) { - continue; - } - const top = metrics.offset - scrollOffset; - const bottom = top + metrics.length; - if (top < viewportHeight && bottom > 0) { - firstVisible = idx; - if ( - _isViewable( - viewAreaMode, - viewablePercentThreshold, - top, - bottom, - viewportHeight, - metrics.length, - ) - ) { - viewableIndices.push(idx); - } - } else if (firstVisible >= 0) { - break; - } - } - return viewableIndices; - } - - /** - * Figures out which items are viewable and how that has changed from before and calls - * `onViewableItemsChanged` as appropriate. - */ - onUpdate( - props: FrameMetricProps, - scrollOffset: number, - viewportHeight: number, - getFrameMetrics: ( - index: number, - props: FrameMetricProps, - ) => ?{ - length: number, - offset: number, - ... - }, - createViewToken: ( - index: number, - isViewable: boolean, - props: FrameMetricProps, - ) => ViewToken, - onViewableItemsChanged: ({ - viewableItems: Array, - changed: Array, - ... - }) => void, - // Optional optimization to reduce the scan size - renderRange?: { - first: number, - last: number, - ... - }, - ): void { - const itemCount = props.getItemCount(props.data); - if ( - (this._config.waitForInteraction && !this._hasInteracted) || - itemCount === 0 || - !getFrameMetrics(0, props) - ) { - return; - } - let viewableIndices: Array = []; - if (itemCount) { - viewableIndices = this.computeViewableItems( - props, - scrollOffset, - viewportHeight, - getFrameMetrics, - renderRange, - ); - } - if ( - this._viewableIndices.length === viewableIndices.length && - this._viewableIndices.every((v, ii) => v === viewableIndices[ii]) - ) { - // We might get a lot of scroll events where visibility doesn't change and we don't want to do - // extra work in those cases. - return; - } - this._viewableIndices = viewableIndices; - if (this._config.minimumViewTime) { - const handle: TimeoutID = setTimeout(() => { - /* $FlowFixMe[incompatible-call] (>=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. */ - this._timers.delete(handle); - this._onUpdateSync( - props, - viewableIndices, - onViewableItemsChanged, - createViewToken, - ); - }, this._config.minimumViewTime); - /* $FlowFixMe[incompatible-call] (>=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. */ - this._timers.add(handle); - } else { - this._onUpdateSync( - props, - viewableIndices, - onViewableItemsChanged, - createViewToken, - ); - } - } - - /** - * clean-up cached _viewableIndices to evaluate changed items on next update - */ - resetViewableIndices() { - this._viewableIndices = []; - } - - /** - * Records that an interaction has happened even if there has been no scroll. - */ - recordInteraction() { - this._hasInteracted = true; - } - - _onUpdateSync( - props: FrameMetricProps, - viewableIndicesToCheck: Array, - onViewableItemsChanged: ({ - changed: Array, - viewableItems: Array, - ... - }) => void, - createViewToken: ( - index: number, - isViewable: boolean, - props: FrameMetricProps, - ) => ViewToken, - ) { - // Filter out indices that have gone out of view since this call was scheduled. - viewableIndicesToCheck = viewableIndicesToCheck.filter(ii => - this._viewableIndices.includes(ii), - ); - const prevItems = this._viewableItems; - const nextItems = new Map( - viewableIndicesToCheck.map(ii => { - const viewable = createViewToken(ii, true, props); - return [viewable.key, viewable]; - }), - ); - - const changed = []; - for (const [key, viewable] of nextItems) { - if (!prevItems.has(key)) { - changed.push(viewable); - } - } - for (const [key, viewable] of prevItems) { - if (!nextItems.has(key)) { - changed.push({...viewable, isViewable: false}); - } - } - if (changed.length > 0) { - this._viewableItems = nextItems; - onViewableItemsChanged({ - viewableItems: Array.from(nextItems.values()), - changed, - viewabilityConfig: this._config, - }); - } - } -} - -function _isViewable( - viewAreaMode: boolean, - viewablePercentThreshold: number, - top: number, - bottom: number, - viewportHeight: number, - itemLength: number, -): boolean { - if (_isEntirelyVisible(top, bottom, viewportHeight)) { - return true; - } else { - const pixels = _getPixelsVisible(top, bottom, viewportHeight); - const percent = - 100 * (viewAreaMode ? pixels / viewportHeight : pixels / itemLength); - return percent >= viewablePercentThreshold; - } -} - -function _getPixelsVisible( - top: number, - bottom: number, - viewportHeight: number, -): number { - const visibleHeight = Math.min(bottom, viewportHeight) - Math.max(top, 0); - return Math.max(0, visibleHeight); -} - -function _isEntirelyVisible( - top: number, - bottom: number, - viewportHeight: number, -): boolean { - return top >= 0 && bottom <= viewportHeight && bottom > top; -} +const ViewabilityHelper: ViewabilityHelperType = + require('@react-native/virtualized-lists').ViewabilityHelper; module.exports = ViewabilityHelper; diff --git a/Libraries/Lists/VirtualizeUtils.js b/Libraries/Lists/VirtualizeUtils.js index 3a70d9f683091e..535d25b3abc538 100644 --- a/Libraries/Lists/VirtualizeUtils.js +++ b/Libraries/Lists/VirtualizeUtils.js @@ -10,249 +10,9 @@ 'use strict'; -import type {FrameMetricProps} from './VirtualizedListProps'; +import {typeof keyExtractor as KeyExtractorType} from '@react-native/virtualized-lists'; -/** - * Used to find the indices of the frames that overlap the given offsets. Useful for finding the - * items that bound different windows of content, such as the visible area or the buffered overscan - * area. - */ -export function elementsThatOverlapOffsets( - offsets: Array, - props: FrameMetricProps, - getFrameMetrics: ( - index: number, - props: FrameMetricProps, - ) => { - length: number, - offset: number, - ... - }, - zoomScale: number = 1, -): Array { - const itemCount = props.getItemCount(props.data); - const result = []; - for (let offsetIndex = 0; offsetIndex < offsets.length; offsetIndex++) { - const currentOffset = offsets[offsetIndex]; - let left = 0; - let right = itemCount - 1; - - while (left <= right) { - // eslint-disable-next-line no-bitwise - const mid = left + ((right - left) >>> 1); - const frame = getFrameMetrics(mid, props); - const scaledOffsetStart = frame.offset * zoomScale; - const scaledOffsetEnd = (frame.offset + frame.length) * zoomScale; - - // We want the first frame that contains the offset, with inclusive bounds. Thus, for the - // first frame the scaledOffsetStart is inclusive, while for other frames it is exclusive. - if ( - (mid === 0 && currentOffset < scaledOffsetStart) || - (mid !== 0 && currentOffset <= scaledOffsetStart) - ) { - right = mid - 1; - } else if (currentOffset > scaledOffsetEnd) { - left = mid + 1; - } else { - result[offsetIndex] = mid; - break; - } - } - } - - return result; -} - -/** - * Computes the number of elements in the `next` range that are new compared to the `prev` range. - * Handy for calculating how many new items will be rendered when the render window changes so we - * can restrict the number of new items render at once so that content can appear on the screen - * faster. - */ -export function newRangeCount( - prev: { - first: number, - last: number, - ... - }, - next: { - first: number, - last: number, - ... - }, -): number { - return ( - next.last - - next.first + - 1 - - Math.max( - 0, - 1 + Math.min(next.last, prev.last) - Math.max(next.first, prev.first), - ) - ); -} - -/** - * Custom logic for determining which items should be rendered given the current frame and scroll - * metrics, as well as the previous render state. The algorithm may evolve over time, but generally - * prioritizes the visible area first, then expands that with overscan regions ahead and behind, - * biased in the direction of scroll. - */ -export function computeWindowedRenderLimits( - props: FrameMetricProps, - maxToRenderPerBatch: number, - windowSize: number, - prev: { - first: number, - last: number, - }, - getFrameMetricsApprox: ( - index: number, - props: FrameMetricProps, - ) => { - length: number, - offset: number, - ... - }, - scrollMetrics: { - dt: number, - offset: number, - velocity: number, - visibleLength: number, - zoomScale: number, - ... - }, -): { - first: number, - last: number, -} { - const itemCount = props.getItemCount(props.data); - if (itemCount === 0) { - return {first: 0, last: -1}; - } - const {offset, velocity, visibleLength, zoomScale = 1} = scrollMetrics; - - // Start with visible area, then compute maximum overscan region by expanding from there, biased - // in the direction of scroll. Total overscan area is capped, which should cap memory consumption - // too. - const visibleBegin = Math.max(0, offset); - const visibleEnd = visibleBegin + visibleLength; - const overscanLength = (windowSize - 1) * visibleLength; - - // Considering velocity seems to introduce more churn than it's worth. - const leadFactor = 0.5; // Math.max(0, Math.min(1, velocity / 25 + 0.5)); - - const fillPreference = - velocity > 1 ? 'after' : velocity < -1 ? 'before' : 'none'; - - const overscanBegin = Math.max( - 0, - visibleBegin - (1 - leadFactor) * overscanLength, - ); - const overscanEnd = Math.max(0, visibleEnd + leadFactor * overscanLength); - - const lastItemOffset = - getFrameMetricsApprox(itemCount - 1, props).offset * zoomScale; - if (lastItemOffset < overscanBegin) { - // Entire list is before our overscan window - return { - first: Math.max(0, itemCount - 1 - maxToRenderPerBatch), - last: itemCount - 1, - }; - } - - // Find the indices that correspond to the items at the render boundaries we're targeting. - let [overscanFirst, first, last, overscanLast] = elementsThatOverlapOffsets( - [overscanBegin, visibleBegin, visibleEnd, overscanEnd], - props, - getFrameMetricsApprox, - zoomScale, - ); - overscanFirst = overscanFirst == null ? 0 : overscanFirst; - first = first == null ? Math.max(0, overscanFirst) : first; - overscanLast = overscanLast == null ? itemCount - 1 : overscanLast; - last = - last == null - ? Math.min(overscanLast, first + maxToRenderPerBatch - 1) - : last; - const visible = {first, last}; - - // We want to limit the number of new cells we're rendering per batch so that we can fill the - // content on the screen quickly. If we rendered the entire overscan window at once, the user - // could be staring at white space for a long time waiting for a bunch of offscreen content to - // render. - let newCellCount = newRangeCount(prev, visible); - - while (true) { - if (first <= overscanFirst && last >= overscanLast) { - // If we fill the entire overscan range, we're done. - break; - } - const maxNewCells = newCellCount >= maxToRenderPerBatch; - const firstWillAddMore = first <= prev.first || first > prev.last; - const firstShouldIncrement = - first > overscanFirst && (!maxNewCells || !firstWillAddMore); - const lastWillAddMore = last >= prev.last || last < prev.first; - const lastShouldIncrement = - last < overscanLast && (!maxNewCells || !lastWillAddMore); - if (maxNewCells && !firstShouldIncrement && !lastShouldIncrement) { - // We only want to stop if we've hit maxNewCells AND we cannot increment first or last - // without rendering new items. This let's us preserve as many already rendered items as - // possible, reducing render churn and keeping the rendered overscan range as large as - // possible. - break; - } - if ( - firstShouldIncrement && - !(fillPreference === 'after' && lastShouldIncrement && lastWillAddMore) - ) { - if (firstWillAddMore) { - newCellCount++; - } - first--; - } - if ( - lastShouldIncrement && - !(fillPreference === 'before' && firstShouldIncrement && firstWillAddMore) - ) { - if (lastWillAddMore) { - newCellCount++; - } - last++; - } - } - if ( - !( - last >= first && - first >= 0 && - last < itemCount && - first >= overscanFirst && - last <= overscanLast && - first <= visible.first && - last >= visible.last - ) - ) { - throw new Error( - 'Bad window calculation ' + - JSON.stringify({ - first, - last, - itemCount, - overscanFirst, - overscanLast, - visible, - }), - ); - } - return {first, last}; -} +const keyExtractor: KeyExtractorType = + require('@react-native/virtualized-lists').keyExtractor; -export function keyExtractor(item: any, index: number): string { - if (typeof item === 'object' && item?.key != null) { - return item.key; - } - if (typeof item === 'object' && item?.id != null) { - return item.id; - } - return String(index); -} +module.exports = {keyExtractor}; diff --git a/Libraries/Lists/VirtualizedList.js b/Libraries/Lists/VirtualizedList.js index 9d1d336eccc762..2488b1e5e37f57 100644 --- a/Libraries/Lists/VirtualizedList.js +++ b/Libraries/Lists/VirtualizedList.js @@ -8,1945 +8,16 @@ * @format */ -import type {ScrollResponderType} from '../Components/ScrollView/ScrollView'; -import type {ViewStyleProp} from '../StyleSheet/StyleSheet'; -import type {LayoutEvent, ScrollEvent} from '../Types/CoreEventTypes'; -import type {ViewToken} from './ViewabilityHelper'; -import type { - FrameMetricProps, - Item, - Props, - RenderItemProps, - RenderItemType, - Separators, -} from './VirtualizedListProps'; - -import RefreshControl from '../Components/RefreshControl/RefreshControl'; -import ScrollView from '../Components/ScrollView/ScrollView'; -import View from '../Components/View/View'; -import Batchinator from '../Interaction/Batchinator'; -import {findNodeHandle} from '../ReactNative/RendererProxy'; -import flattenStyle from '../StyleSheet/flattenStyle'; -import StyleSheet from '../StyleSheet/StyleSheet'; -import clamp from '../Utilities/clamp'; -import infoLog from '../Utilities/infoLog'; -import {CellRenderMask} from './CellRenderMask'; -import ChildListCollection from './ChildListCollection'; -import FillRateHelper from './FillRateHelper'; -import StateSafePureComponent from './StateSafePureComponent'; -import ViewabilityHelper from './ViewabilityHelper'; -import CellRenderer from './VirtualizedListCellRenderer'; -import { - VirtualizedListCellContextProvider, - VirtualizedListContext, - VirtualizedListContextProvider, -} from './VirtualizedListContext.js'; -import { - computeWindowedRenderLimits, - keyExtractor as defaultKeyExtractor, -} from './VirtualizeUtils'; -import invariant from 'invariant'; -import * as React from 'react'; - -export type {RenderItemProps, RenderItemType, Separators}; - -const ON_EDGE_REACHED_EPSILON = 0.001; - -let _usedIndexForKey = false; -let _keylessItemComponentName: string = ''; - -type ViewabilityHelperCallbackTuple = { - viewabilityHelper: ViewabilityHelper, - onViewableItemsChanged: (info: { - viewableItems: Array, - changed: Array, - ... - }) => void, - ... -}; - -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; -} - -// onStartReachedThresholdOrDefault(this.props.onStartReachedThreshold) -function onStartReachedThresholdOrDefault(onStartReachedThreshold: ?number) { - return onStartReachedThreshold ?? 2; -} - -// onEndReachedThresholdOrDefault(this.props.onEndReachedThreshold) -function onEndReachedThresholdOrDefault(onEndReachedThreshold: ?number) { - return onEndReachedThreshold ?? 2; -} - -// getScrollingThreshold(visibleLength, onEndReachedThreshold) -function getScrollingThreshold(threshold: number, visibleLength: number) { - return (threshold * visibleLength) / 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 - * - */ -export default class VirtualizedList extends StateSafePureComponent< - Props, - State, -> { - 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, this.props); - 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, - ... - }): $FlowFixMe { - 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(Math.floor(index), this.props); - const offset = - Math.max( - 0, - this._getOffsetApprox(index, this.props) - - (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, - viewOffset?: number, - 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.recordInteraction(); - }); - this._viewabilityTuples.forEach(t => { - t.viewabilityHelper.recordInteraction(); - }); - this._updateViewableItems(this.props, this.state.cellsAroundViewport); - } - - 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 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'; - } - - // $FlowFixMe[missing-local-annot] - _getScrollMetrics = () => { - return this._scrollMetrics; - }; - - hasMore(): boolean { - return this._hasMore; - } - - // $FlowFixMe[missing-local-annot] - _getOutermostParentListRef = () => { - if (this._isNestedWithSameOrientation()) { - return this.context.getOutermostParentListRef(); - } else { - return this; - } - }; - - _registerAsNestedChild = (childList: { - cellKey: string, - ref: React.ElementRef, - }): void => { - this._nestedChildLists.add(childList.ref, childList.cellKey); - if (this._hasInteracted) { - childList.ref.recordInteraction(); - } - }; - - _unregisterAsNestedChild = (childList: { - ref: React.ElementRef, - }): void => { - this._nestedChildLists.remove(childList.ref); - }; - - 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, - }); - } - } - - invariant( - !this.context, - 'Unexpectedly saw VirtualizedListContext available in ctor', - ); - - const initialRenderRegion = VirtualizedList._initialRenderRegion(props); - - this.state = { - cellsAroundViewport: initialRenderRegion, - renderMask: VirtualizedList._createRenderMask(props, initialRenderRegion), - }; - } - - 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) { - 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 = Math.floor(Math.max(0, 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(props, cellsAroundViewport); - - 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.last >= getItemCount(data) - ? VirtualizedList._constrainToItemCount(cellsAroundViewport, props) - : cellsAroundViewport; - } - - let newCellsAroundViewport: {first: number, last: number}; - if (props.disableVirtualization) { - const renderAhead = - distanceFromEnd < onEndReachedThreshold * visibleLength - ? maxToRenderPerBatchOrDefault(props.maxToRenderPerBatch) - : 0; - - newCellsAroundViewport = { - first: 0, - last: Math.min( - 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 ( - props.initialScrollIndex && - !this._scrollMetrics.offset && - Math.abs(distanceFromEnd) >= Number.EPSILON - ) { - return cellsAroundViewport.last >= getItemCount(data) - ? VirtualizedList._constrainToItemCount(cellsAroundViewport, props) - : cellsAroundViewport; - } - - newCellsAroundViewport = computeWindowedRenderLimits( - props, - maxToRenderPerBatchOrDefault(props.maxToRenderPerBatch), - windowSizeOrDefault(props.windowSize), - cellsAroundViewport, - this.__getFrameMetricsApprox, - this._scrollMetrics, - ); - invariant( - newCellsAroundViewport.last < getItemCount(data), - 'computeWindowedRenderLimits() should return range in-bounds', - ); - } - - 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); - if ( - cellKeyForIndex != null && - this._nestedChildLists.anyInCell(cellKeyForIndex, childList => - childList.hasMore(), - ) - ) { - return ii; - } - } - - return null; - } +'use strict'; - componentDidMount() { - if (this._isNestedWithSameOrientation()) { - this.context.registerAsNestedChild({ - ref: this, - cellKey: this.context.cellKey, - }); - } - } +import {typeof VirtualizedList as VirtualizedListType} from '@react-native/virtualized-lists'; - componentWillUnmount() { - if (this._isNestedWithSameOrientation()) { - this.context.unregisterAsNestedChild({ref: this}); - } - this._updateCellsToRenderBatcher.dispose({abort: true}); - this._viewabilityTuples.forEach(tuple => { - tuple.viewabilityHelper.dispose(); - }); - this._fillRateHelper.deactivateAndFlush(); - } +const VirtualizedList: VirtualizedListType = + require('@react-native/virtualized-lists').VirtualizedList; - 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.props); - 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); - }); - }; - - _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, - props: { - keyExtractor?: ?(item: Item, index: number) => string, - ... - }, - // $FlowFixMe[missing-local-annot] - ) { - if (props.keyExtractor != null) { - return 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__) { - // $FlowFixMe[underconstrained-implicit-instantiation] - 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: Array = []; - 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, { - onLayout: (event: LayoutEvent) => { - 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.props.disableVirtualization) { - 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, - this.props, - ); - const lastMetrics = this.__getFrameMetricsApprox(last, this.props); - 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 && - this.props.scrollEnabled !== false - ) { - // 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; - _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: ChildListCollection = - new ChildListCollection(); - _offsetFromParentVirtualizedList: number = 0; - _prevParentOffset: number = 0; - // $FlowFixMe[missing-local-annot] - _scrollMetrics = { - contentLength: 0, - dOffset: 0, - dt: 10, - offset: 0, - timestamp: 0, - velocity: 0, - visibleLength: 0, - zoomScale: 1, - }; - _scrollRef: ?React.ElementRef = null; - _sentStartForContentLength = 0; - _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 - // $FlowFixMe[incompatible-use] - - ) : ( - props.refreshControl - ) - } - /> - ); - } else { - // $FlowFixMe[prop-missing] Invalid prop usage - // $FlowFixMe[incompatible-use] - 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, this.state.cellsAroundViewport); - }; - - _onCellFocusCapture(cellKey: string) { - this._lastFocusedCellKey = cellKey; - const renderMask = VirtualizedList._createRenderMask( - this.props, - this.state.cellsAroundViewport, - this._getNonViewportRenderRegions(this.props), - ); - - this.setState(state => { - if (!renderMask.equals(state.renderMask)) { - return {renderMask}; - } - return null; - }); - } - - _onCellUnmount = (cellKey: string) => { - const curr = this._frames[cellKey]; - if (curr) { - this._frames[cellKey] = {...curr, inLayout: false}; - } - }; - - _triggerRemeasureForChildListsInCell(cellKey: string): void { - this._nestedChildLists.forEachInCell(cellKey, childList => { - childList.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._nestedChildLists.forEach(childList => { - childList.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._maybeCallOnEdgeReached(); - }; - - _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); - }; - - // $FlowFixMe[missing-local-annot] - _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, this.props); - /* $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, - this.props, - ).offset; - const frameLast = this.__getFrameMetricsApprox( - this.state.cellsAroundViewport.last, - this.props, - ); - 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; - } - - _maybeCallOnEdgeReached() { - const { - data, - getItemCount, - onStartReached, - onStartReachedThreshold, - onEndReached, - onEndReachedThreshold, - initialScrollIndex, - } = this.props; - const {contentLength, visibleLength, offset} = this._scrollMetrics; - let distanceFromStart = offset; - let distanceFromEnd = contentLength - visibleLength - offset; - - // Especially when oERT is zero it's necessary to 'floor' very small distance 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 edge of the list with a distance approximating 0 but not quite there. - if (distanceFromStart < ON_EDGE_REACHED_EPSILON) { - distanceFromStart = 0; - } - if (distanceFromEnd < ON_EDGE_REACHED_EPSILON) { - distanceFromEnd = 0; - } - - // TODO: T121172172 Look into why we're "defaulting" to a threshold of 2px - // when oERT is not present (different from 2 viewports used elsewhere) - const DEFAULT_THRESHOLD_PX = 2; - - const startThreshold = - onStartReachedThreshold != null - ? onStartReachedThreshold * visibleLength - : DEFAULT_THRESHOLD_PX; - const endThreshold = - onEndReachedThreshold != null - ? onEndReachedThreshold * visibleLength - : DEFAULT_THRESHOLD_PX; - const isWithinStartThreshold = distanceFromStart <= startThreshold; - const isWithinEndThreshold = distanceFromEnd <= endThreshold; - - // First check if the user just scrolled within the end threshold - // and call onEndReached only once for a given content length, - // and only if onStartReached is not being executed - if ( - onEndReached && - this.state.cellsAroundViewport.last === getItemCount(data) - 1 && - isWithinEndThreshold && - this._scrollMetrics.contentLength !== this._sentEndForContentLength - ) { - this._sentEndForContentLength = this._scrollMetrics.contentLength; - onEndReached({distanceFromEnd}); - } - - // Next check if the user just scrolled within the start threshold - // and call onStartReached only once for a given content length, - // and only if onEndReached is not being executed - else if ( - onStartReached != null && - this.state.cellsAroundViewport.first === 0 && - isWithinStartThreshold && - this._scrollMetrics.contentLength !== this._sentStartForContentLength - ) { - // On initial mount when using initialScrollIndex the offset will be 0 initially - // and will trigger an unexpected onStartReached. To avoid this we can use - // timestamp to differentiate between the initial scroll metrics and when we actually - // received the first scroll event. - if (!initialScrollIndex || this._scrollMetrics.timestamp !== 0) { - this._sentStartForContentLength = this._scrollMetrics.contentLength; - onStartReached({distanceFromStart}); - } - } - - // If the user scrolls away from the start or end and back again, - // cause onStartReached or onEndReached to be triggered again - else { - this._sentStartForContentLength = isWithinStartThreshold - ? this._sentStartForContentLength - : 0; - this._sentEndForContentLength = isWithinEndThreshold - ? 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._maybeCallOnEdgeReached(); - }; - - /* Translates metrics from a scroll event in a parent VirtualizedList into - * coordinates relative to the child list. - */ - _convertParentScrollMetrics = (metrics: { - visibleLength: number, - offset: number, - ... - }): $FlowFixMe => { - // 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._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, this.state.cellsAroundViewport); - if (!this.props) { - return; - } - this._maybeCallOnEdgeReached(); - 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 onStartReachedThreshold = onStartReachedThresholdOrDefault( - this.props.onStartReachedThreshold, - ); - const onEndReachedThreshold = onEndReachedThresholdOrDefault( - this.props.onEndReachedThreshold, - ); - // 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, this.props).offset; - hiPri = - distTop < 0 || - (velocity < -2 && - distTop < - getScrollingThreshold(onStartReachedThreshold, visibleLength)); - } - // 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 (!hiPri && last >= 0 && last < itemCount - 1) { - const distBottom = - this.__getFrameMetricsApprox(last, this.props).offset - - (offset + visibleLength); - hiPri = - distBottom < 0 || - (velocity > 2 && - distBottom < - getScrollingThreshold(onEndReachedThreshold, visibleLength)); - } - // 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._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._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._onMomentumScrollBegin(e); - }); - this.props.onMomentumScrollBegin && this.props.onMomentumScrollBegin(e); - }; - - _onMomentumScrollEnd = (e: ScrollEvent): void => { - this._nestedChildLists.forEach(childList => { - childList._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(props), - ); - - 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, - props: FrameMetricProps, - // $FlowFixMe[missing-local-annot] - ) => { - const {data, getItem} = props; - const item = getItem(data, index); - return { - index, - item, - key: this._keyExtractor(item, index, props), - isViewable, - }; - }; - - /** - * Gets an approximate offset to an item at a given index. Supports - * fractional indices. - */ - _getOffsetApprox = (index: number, props: FrameMetricProps): number => { - if (Number.isInteger(index)) { - return this.__getFrameMetricsApprox(index, props).offset; - } else { - const frameMetrics = this.__getFrameMetricsApprox( - Math.floor(index), - props, - ); - const remainder = index - Math.floor(index); - return frameMetrics.offset + remainder * frameMetrics.length; - } - }; - - __getFrameMetricsApprox: ( - index: number, - props: FrameMetricProps, - ) => { - length: number, - offset: number, - ... - } = (index, props) => { - const frame = this._getFrameMetrics(index, props); - if (frame && frame.index === index) { - // check for invalid frames due to row re-ordering - return frame; - } else { - const {data, getItemCount, getItemLayout} = 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, - props: FrameMetricProps, - ): ?{ - length: number, - offset: number, - index: number, - inLayout?: boolean, - ... - } => { - const {data, getItem, getItemCount, getItemLayout} = 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 != null - ? this._frames[this._keyExtractor(item, index, props)] - : undefined; - 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 = ( - props: FrameMetricProps, - ): $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 = props.getItemCount(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, - props, - ).length; - } - - let last = focusedCellIndex; - let heightOfCellsAfterFocused = 0; - for ( - let i = last + 1; - i < itemCount && - heightOfCellsAfterFocused < this._scrollMetrics.visibleLength; - i++ - ) { - last++; - heightOfCellsAfterFocused += this.__getFrameMetricsApprox( - i, - props, - ).length; - } - - return [{first, last}]; - }; - - _updateViewableItems( - props: FrameMetricProps, - cellsAroundViewport: {first: number, last: number}, - ) { - this._viewabilityTuples.forEach(tuple => { - tuple.viewabilityHelper.onUpdate( - props, - this._scrollMetrics.offset, - this._scrollMetrics.visibleLength, - this._getFrameMetrics, - this._createViewToken, - tuple.onViewableItemsChanged, - cellsAroundViewport, - ); - }); - } -} - -const styles = StyleSheet.create({ - verticallyInverted: { - transform: [{scaleY: -1}], - }, - horizontallyInverted: { - transform: [{scaleX: -1}], - }, - 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, - }, -}); +export type { + RenderItemProps, + RenderItemType, + Separators, +} from '@react-native/virtualized-lists'; +module.exports = VirtualizedList; diff --git a/Libraries/Lists/VirtualizedListContext.js b/Libraries/Lists/VirtualizedListContext.js index bca5724498a356..5686ccf372286c 100644 --- a/Libraries/Lists/VirtualizedListContext.js +++ b/Libraries/Lists/VirtualizedListContext.js @@ -4,113 +4,15 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @flow strict-local + * @flow * @format */ -import typeof VirtualizedList from './VirtualizedList'; +'use strict'; -import * as React from 'react'; -import {useContext, useMemo} from 'react'; +import {typeof VirtualizedListContextResetter as VirtualizedListContextResetterType} from '@react-native/virtualized-lists'; -type Context = $ReadOnly<{ - cellKey: ?string, - getScrollMetrics: () => { - contentLength: number, - dOffset: number, - dt: number, - offset: number, - timestamp: number, - velocity: number, - visibleLength: number, - zoomScale: number, - }, - horizontal: ?boolean, - getOutermostParentListRef: () => React.ElementRef, - registerAsNestedChild: ({ - cellKey: string, - ref: React.ElementRef, - }) => void, - unregisterAsNestedChild: ({ - ref: React.ElementRef, - }) => void, -}>; +const VirtualizedListContextResetter: VirtualizedListContextResetterType = + require('@react-native/virtualized-lists').VirtualizedListContextResetter; -export const VirtualizedListContext: React.Context = - React.createContext(null); -if (__DEV__) { - VirtualizedListContext.displayName = 'VirtualizedListContext'; -} - -/** - * Resets the context. Intended for use by portal-like components (e.g. Modal). - */ -export function VirtualizedListContextResetter({ - children, -}: { - children: React.Node, -}): React.Node { - return ( - - {children} - - ); -} - -/** - * Sets the context with memoization. Intended to be used by `VirtualizedList`. - */ -export function VirtualizedListContextProvider({ - children, - value, -}: { - children: React.Node, - value: Context, -}): React.Node { - // Avoid setting a newly created context object if the values are identical. - const context = useMemo( - () => ({ - cellKey: null, - getScrollMetrics: value.getScrollMetrics, - horizontal: value.horizontal, - getOutermostParentListRef: value.getOutermostParentListRef, - registerAsNestedChild: value.registerAsNestedChild, - unregisterAsNestedChild: value.unregisterAsNestedChild, - }), - [ - value.getScrollMetrics, - value.horizontal, - value.getOutermostParentListRef, - value.registerAsNestedChild, - value.unregisterAsNestedChild, - ], - ); - return ( - - {children} - - ); -} - -/** - * Sets the `cellKey`. Intended to be used by `VirtualizedList` for each cell. - */ -export function VirtualizedListCellContextProvider({ - cellKey, - children, -}: { - cellKey: string, - children: React.Node, -}): React.Node { - // Avoid setting a newly created context object if the values are identical. - const currContext = useContext(VirtualizedListContext); - const context = useMemo( - () => (currContext == null ? null : {...currContext, cellKey}), - [currContext, cellKey], - ); - return ( - - {children} - - ); -} +module.exports = {VirtualizedListContextResetter}; diff --git a/Libraries/Lists/VirtualizedSectionList.js b/Libraries/Lists/VirtualizedSectionList.js index e4bf2fe58a0c44..242dfe34c6b231 100644 --- a/Libraries/Lists/VirtualizedSectionList.js +++ b/Libraries/Lists/VirtualizedSectionList.js @@ -8,610 +8,15 @@ * @format */ -import type {ViewToken} from './ViewabilityHelper'; +'use strict'; -import View from '../Components/View/View'; -import VirtualizedList from './VirtualizedList'; -import {keyExtractor as defaultKeyExtractor} from './VirtualizeUtils'; -import invariant from 'invariant'; -import * as React from 'react'; +import {typeof VirtualizedSectionList as VirtualizedSectionListType} from '@react-native/virtualized-lists'; -type Item = any; +const VirtualizedSectionList: VirtualizedSectionListType = + require('@react-native/virtualized-lists').VirtualizedSectionList; -export type SectionBase = { - /** - * The data for rendering items in this section. - */ - data: $ReadOnlyArray, - /** - * Optional key to keep track of section re-ordering. If you don't plan on re-ordering sections, - * the array index will be used by default. - */ - key?: string, - // Optional props will override list-wide props just for this section. - renderItem?: ?(info: { - item: SectionItemT, - index: number, - section: SectionBase, - separators: { - highlight: () => void, - unhighlight: () => void, - updateProps: (select: 'leading' | 'trailing', newProps: Object) => void, - ... - }, - ... - }) => null | React.Element, - ItemSeparatorComponent?: ?React.ComponentType, - keyExtractor?: (item: SectionItemT, index?: ?number) => string, - ... -}; - -type RequiredProps> = {| - sections: $ReadOnlyArray, -|}; - -type OptionalProps> = {| - /** - * Default renderer for every item in every section. - */ - renderItem?: (info: { - item: Item, - index: number, - section: SectionT, - separators: { - highlight: () => void, - unhighlight: () => void, - updateProps: (select: 'leading' | 'trailing', newProps: Object) => void, - ... - }, - ... - }) => null | React.Element, - /** - * Rendered at the top of each section. These stick to the top of the `ScrollView` by default on - * iOS. See `stickySectionHeadersEnabled`. - */ - renderSectionHeader?: ?(info: { - section: SectionT, - ... - }) => null | React.Element, - /** - * Rendered at the bottom of each section. - */ - renderSectionFooter?: ?(info: { - section: SectionT, - ... - }) => null | React.Element, - /** - * Rendered at the top and bottom of each section (note this is different from - * `ItemSeparatorComponent` which is only rendered between items). These are intended to separate - * sections from the headers above and below and typically have the same highlight response as - * `ItemSeparatorComponent`. Also receives `highlighted`, `[leading/trailing][Item/Separator]`, - * and any custom props from `separators.updateProps`. - */ - SectionSeparatorComponent?: ?React.ComponentType, - /** - * Makes section headers stick to the top of the screen until the next one pushes it off. Only - * enabled by default on iOS because that is the platform standard there. - */ - stickySectionHeadersEnabled?: boolean, - onEndReached?: ?({distanceFromEnd: number, ...}) => void, -|}; - -type VirtualizedListProps = React.ElementConfig; - -export type Props = {| - ...RequiredProps, - ...OptionalProps, - ...$Diff< - VirtualizedListProps, - { - renderItem: $PropertyType, - data: $PropertyType, - ... - }, - >, -|}; -export type ScrollToLocationParamsType = {| - animated?: ?boolean, - itemIndex: number, - sectionIndex: number, - viewOffset?: number, - viewPosition?: number, -|}; - -type State = {childProps: VirtualizedListProps, ...}; - -/** - * Right now this just flattens everything into one list and uses VirtualizedList under the - * hood. The only operation that might not scale well is concatting the data arrays of all the - * sections when new props are received, which should be plenty fast for up to ~10,000 items. - */ -class VirtualizedSectionList< - SectionT: SectionBase, -> extends React.PureComponent, State> { - scrollToLocation(params: ScrollToLocationParamsType) { - let index = params.itemIndex; - for (let i = 0; i < params.sectionIndex; i++) { - index += this.props.getItemCount(this.props.sections[i].data) + 2; - } - let viewOffset = params.viewOffset || 0; - if (this._listRef == null) { - return; - } - if (params.itemIndex > 0 && this.props.stickySectionHeadersEnabled) { - const frame = this._listRef.__getFrameMetricsApprox( - index - params.itemIndex, - this._listRef.props, - ); - viewOffset += frame.length; - } - const toIndexParams = { - ...params, - viewOffset, - index, - }; - // $FlowFixMe[incompatible-use] - this._listRef.scrollToIndex(toIndexParams); - } - - getListRef(): ?React.ElementRef { - return this._listRef; - } - - render(): React.Node { - const { - ItemSeparatorComponent, // don't pass through, rendered with renderItem - SectionSeparatorComponent, - renderItem: _renderItem, - renderSectionFooter, - renderSectionHeader, - sections: _sections, - stickySectionHeadersEnabled, - ...passThroughProps - } = this.props; - - const listHeaderOffset = this.props.ListHeaderComponent ? 1 : 0; - - const stickyHeaderIndices = this.props.stickySectionHeadersEnabled - ? ([]: Array) - : undefined; - - let itemCount = 0; - for (const section of this.props.sections) { - // Track the section header indices - if (stickyHeaderIndices != null) { - stickyHeaderIndices.push(itemCount + listHeaderOffset); - } - - // Add two for the section header and footer. - itemCount += 2; - itemCount += this.props.getItemCount(section.data); - } - const renderItem = this._renderItem(itemCount); - - return ( - - this._getItem(this.props, sections, index) - } - getItemCount={() => itemCount} - onViewableItemsChanged={ - this.props.onViewableItemsChanged - ? this._onViewableItemsChanged - : undefined - } - ref={this._captureRef} - /> - ); - } - - _getItem( - props: Props, - sections: ?$ReadOnlyArray, - index: number, - ): ?Item { - if (!sections) { - return null; - } - let itemIdx = index - 1; - for (let i = 0; i < sections.length; i++) { - const section = sections[i]; - const sectionData = section.data; - const itemCount = props.getItemCount(sectionData); - if (itemIdx === -1 || itemIdx === itemCount) { - // We intend for there to be overflow by one on both ends of the list. - // This will be for headers and footers. When returning a header or footer - // item the section itself is the item. - return section; - } else if (itemIdx < itemCount) { - // If we are in the bounds of the list's data then return the item. - return props.getItem(sectionData, itemIdx); - } else { - itemIdx -= itemCount + 2; // Add two for the header and footer - } - } - return null; - } - - // $FlowFixMe[missing-local-annot] - _keyExtractor = (item: Item, index: number) => { - const info = this._subExtractor(index); - return (info && info.key) || String(index); - }; - - _subExtractor(index: number): ?{ - section: SectionT, - // Key of the section or combined key for section + item - key: string, - // Relative index within the section - index: ?number, - // True if this is the section header - header?: ?boolean, - leadingItem?: ?Item, - leadingSection?: ?SectionT, - trailingItem?: ?Item, - trailingSection?: ?SectionT, - ... - } { - let itemIndex = index; - const {getItem, getItemCount, keyExtractor, sections} = this.props; - for (let i = 0; i < sections.length; i++) { - const section = sections[i]; - const sectionData = section.data; - const key = section.key || String(i); - itemIndex -= 1; // The section adds an item for the header - if (itemIndex >= getItemCount(sectionData) + 1) { - itemIndex -= getItemCount(sectionData) + 1; // The section adds an item for the footer. - } else if (itemIndex === -1) { - return { - section, - key: key + ':header', - index: null, - header: true, - trailingSection: sections[i + 1], - }; - } else if (itemIndex === getItemCount(sectionData)) { - return { - section, - key: key + ':footer', - index: null, - header: false, - trailingSection: sections[i + 1], - }; - } else { - const extractor = - section.keyExtractor || keyExtractor || defaultKeyExtractor; - return { - section, - key: - key + ':' + extractor(getItem(sectionData, itemIndex), itemIndex), - index: itemIndex, - leadingItem: getItem(sectionData, itemIndex - 1), - leadingSection: sections[i - 1], - trailingItem: getItem(sectionData, itemIndex + 1), - trailingSection: sections[i + 1], - }; - } - } - } - - _convertViewable = (viewable: ViewToken): ?ViewToken => { - invariant(viewable.index != null, 'Received a broken ViewToken'); - const info = this._subExtractor(viewable.index); - if (!info) { - return null; - } - const keyExtractorWithNullableIndex = info.section.keyExtractor; - const keyExtractorWithNonNullableIndex = - this.props.keyExtractor || defaultKeyExtractor; - const key = - keyExtractorWithNullableIndex != null - ? keyExtractorWithNullableIndex(viewable.item, info.index) - : keyExtractorWithNonNullableIndex(viewable.item, info.index ?? 0); - - return { - ...viewable, - index: info.index, - key, - section: info.section, - }; - }; - - _onViewableItemsChanged = ({ - viewableItems, - changed, - }: { - viewableItems: Array, - changed: Array, - ... - }) => { - const onViewableItemsChanged = this.props.onViewableItemsChanged; - if (onViewableItemsChanged != null) { - onViewableItemsChanged({ - viewableItems: viewableItems - .map(this._convertViewable, this) - .filter(Boolean), - changed: changed.map(this._convertViewable, this).filter(Boolean), - }); - } - }; - - _renderItem = - (listItemCount: number): $FlowFixMe => - // eslint-disable-next-line react/no-unstable-nested-components - ({item, index}: {item: Item, index: number, ...}) => { - const info = this._subExtractor(index); - if (!info) { - return null; - } - const infoIndex = info.index; - if (infoIndex == null) { - const {section} = info; - if (info.header === true) { - const {renderSectionHeader} = this.props; - return renderSectionHeader ? renderSectionHeader({section}) : null; - } else { - const {renderSectionFooter} = this.props; - return renderSectionFooter ? renderSectionFooter({section}) : null; - } - } else { - const renderItem = info.section.renderItem || this.props.renderItem; - const SeparatorComponent = this._getSeparatorComponent( - index, - info, - listItemCount, - ); - invariant(renderItem, 'no renderItem!'); - return ( - - ); - } - }; - - _updatePropsFor = (cellKey: string, value: any) => { - const updateProps = this._updatePropsMap[cellKey]; - if (updateProps != null) { - updateProps(value); - } - }; - - _updateHighlightFor = (cellKey: string, value: boolean) => { - const updateHighlight = this._updateHighlightMap[cellKey]; - if (updateHighlight != null) { - updateHighlight(value); - } - }; - - _setUpdateHighlightFor = ( - cellKey: string, - updateHighlightFn: ?(boolean) => void, - ) => { - if (updateHighlightFn != null) { - this._updateHighlightMap[cellKey] = updateHighlightFn; - } else { - // $FlowFixMe[prop-missing] - delete this._updateHighlightFor[cellKey]; - } - }; - - _setUpdatePropsFor = (cellKey: string, updatePropsFn: ?(boolean) => void) => { - if (updatePropsFn != null) { - this._updatePropsMap[cellKey] = updatePropsFn; - } else { - delete this._updatePropsMap[cellKey]; - } - }; - - _getSeparatorComponent( - index: number, - info?: ?Object, - listItemCount: number, - ): ?React.ComponentType { - info = info || this._subExtractor(index); - if (!info) { - return null; - } - const ItemSeparatorComponent = - info.section.ItemSeparatorComponent || this.props.ItemSeparatorComponent; - const {SectionSeparatorComponent} = this.props; - const isLastItemInList = index === listItemCount - 1; - const isLastItemInSection = - info.index === this.props.getItemCount(info.section.data) - 1; - if (SectionSeparatorComponent && isLastItemInSection) { - return SectionSeparatorComponent; - } - if (ItemSeparatorComponent && !isLastItemInSection && !isLastItemInList) { - return ItemSeparatorComponent; - } - return null; - } - - _updateHighlightMap: {[string]: (boolean) => void} = {}; - _updatePropsMap: {[string]: void | (boolean => void)} = {}; - _listRef: ?React.ElementRef; - _captureRef = (ref: null | React$ElementRef>) => { - this._listRef = ref; - }; -} - -type ItemWithSeparatorCommonProps = $ReadOnly<{| - leadingItem: ?Item, - leadingSection: ?Object, - section: Object, - trailingItem: ?Item, - trailingSection: ?Object, -|}>; - -type ItemWithSeparatorProps = $ReadOnly<{| - ...ItemWithSeparatorCommonProps, - LeadingSeparatorComponent: ?React.ComponentType, - SeparatorComponent: ?React.ComponentType, - cellKey: string, - index: number, - item: Item, - setSelfHighlightCallback: ( - cellKey: string, - updateFn: ?(boolean) => void, - ) => void, - setSelfUpdatePropsCallback: ( - cellKey: string, - updateFn: ?(boolean) => void, - ) => void, - prevCellKey?: ?string, - updateHighlightFor: (prevCellKey: string, value: boolean) => void, - updatePropsFor: (prevCellKey: string, value: Object) => void, - renderItem: Function, - inverted: boolean, -|}>; - -function ItemWithSeparator(props: ItemWithSeparatorProps): React.Node { - const { - LeadingSeparatorComponent, - // this is the trailing separator and is associated with this item - SeparatorComponent, - cellKey, - prevCellKey, - setSelfHighlightCallback, - updateHighlightFor, - setSelfUpdatePropsCallback, - updatePropsFor, - item, - index, - section, - inverted, - } = props; - - const [leadingSeparatorHiglighted, setLeadingSeparatorHighlighted] = - React.useState(false); - - const [separatorHighlighted, setSeparatorHighlighted] = React.useState(false); - - const [leadingSeparatorProps, setLeadingSeparatorProps] = React.useState({ - leadingItem: props.leadingItem, - leadingSection: props.leadingSection, - section: props.section, - trailingItem: props.item, - trailingSection: props.trailingSection, - }); - const [separatorProps, setSeparatorProps] = React.useState({ - leadingItem: props.item, - leadingSection: props.leadingSection, - section: props.section, - trailingItem: props.trailingItem, - trailingSection: props.trailingSection, - }); - - React.useEffect(() => { - setSelfHighlightCallback(cellKey, setSeparatorHighlighted); - // $FlowFixMe[incompatible-call] - setSelfUpdatePropsCallback(cellKey, setSeparatorProps); - - return () => { - setSelfUpdatePropsCallback(cellKey, null); - setSelfHighlightCallback(cellKey, null); - }; - }, [ - cellKey, - setSelfHighlightCallback, - setSeparatorProps, - setSelfUpdatePropsCallback, - ]); - - const separators = { - highlight: () => { - setLeadingSeparatorHighlighted(true); - setSeparatorHighlighted(true); - if (prevCellKey != null) { - updateHighlightFor(prevCellKey, true); - } - }, - unhighlight: () => { - setLeadingSeparatorHighlighted(false); - setSeparatorHighlighted(false); - if (prevCellKey != null) { - updateHighlightFor(prevCellKey, false); - } - }, - updateProps: ( - select: 'leading' | 'trailing', - newProps: $Shape, - ) => { - if (select === 'leading') { - if (LeadingSeparatorComponent != null) { - setLeadingSeparatorProps({...leadingSeparatorProps, ...newProps}); - } else if (prevCellKey != null) { - // update the previous item's separator - updatePropsFor(prevCellKey, {...leadingSeparatorProps, ...newProps}); - } - } else if (select === 'trailing' && SeparatorComponent != null) { - setSeparatorProps({...separatorProps, ...newProps}); - } - }, - }; - const element = props.renderItem({ - item, - index, - section, - separators, - }); - const leadingSeparator = LeadingSeparatorComponent != null && ( - - ); - const separator = SeparatorComponent != null && ( - - ); - return leadingSeparator || separator ? ( - - {inverted === false ? leadingSeparator : separator} - {element} - {inverted === false ? separator : leadingSeparator} - - ) : ( - element - ); -} - -/* $FlowFixMe[class-object-subtyping] added when improving typing for this - * parameters */ -// $FlowFixMe[method-unbinding] -module.exports = (VirtualizedSectionList: React.AbstractComponent< - React.ElementConfig, - $ReadOnly<{ - getListRef: () => ?React.ElementRef, - scrollToLocation: (params: ScrollToLocationParamsType) => void, - ... - }>, ->); +export type { + SectionBase, + ScrollToLocationParamsType, +} from '@react-native/virtualized-lists'; +module.exports = VirtualizedSectionList; diff --git a/Libraries/Modal/Modal.js b/Libraries/Modal/Modal.js index 46e9e714d29262..9750d2e5be31d3 100644 --- a/Libraries/Modal/Modal.js +++ b/Libraries/Modal/Modal.js @@ -13,11 +13,11 @@ import type {RootTag} from '../ReactNative/RootTag'; import type {DirectEventHandler} from '../Types/CodegenTypes'; import NativeEventEmitter from '../EventEmitter/NativeEventEmitter'; -import {VirtualizedListContextResetter} from '../Lists/VirtualizedListContext.js'; import {type EventSubscription} from '../vendor/emitter/EventEmitter'; import ModalInjection from './ModalInjection'; import NativeModalManager from './NativeModalManager'; import RCTModalHostView from './RCTModalHostViewNativeComponent'; +import {VirtualizedListContextResetter} from '@react-native/virtualized-lists'; const ScrollView = require('../Components/ScrollView/ScrollView'); const View = require('../Components/View/View'); diff --git a/Libraries/Renderer/REVISION b/Libraries/Renderer/REVISION index 86ed1c8121de3c..2ef55796759cfe 100644 --- a/Libraries/Renderer/REVISION +++ b/Libraries/Renderer/REVISION @@ -1 +1 @@ -17f6912a44e2ce7b88a72488931428da58f19c56 \ No newline at end of file +48b687fc95a172cec8f305312a27d105e5719581 \ No newline at end of file diff --git a/Libraries/StyleSheet/StyleSheetTypes.d.ts b/Libraries/StyleSheet/StyleSheetTypes.d.ts index f8ea56ae7989ff..412eaa55afb61d 100644 --- a/Libraries/StyleSheet/StyleSheetTypes.d.ts +++ b/Libraries/StyleSheet/StyleSheetTypes.d.ts @@ -232,6 +232,9 @@ export interface TransformsStyle { export interface ViewStyle extends FlexStyle, ShadowStyleIOS, TransformsStyle { backfaceVisibility?: 'visible' | 'hidden' | undefined; backgroundColor?: ColorValue | undefined; + borderBlockColor?: ColorValue | undefined; + borderBlockEndColor?: ColorValue | undefined; + borderBlockStartColor?: ColorValue | undefined; borderBottomColor?: ColorValue | undefined; borderBottomEndRadius?: number | undefined; borderBottomLeftRadius?: number | undefined; @@ -239,6 +242,11 @@ export interface ViewStyle extends FlexStyle, ShadowStyleIOS, TransformsStyle { borderBottomStartRadius?: number | undefined; borderBottomWidth?: number | undefined; borderColor?: ColorValue | undefined; + /** + * On iOS 13+, it is possible to change the corner curve of borders. + * @platform ios + */ + borderCurve?: 'circular' | 'continuous' | undefined; borderEndColor?: ColorValue | undefined; borderEndEndRadius?: number | undefined; borderEndStartRadius?: number | undefined; @@ -268,6 +276,10 @@ export interface ViewStyle extends FlexStyle, ShadowStyleIOS, TransformsStyle { * @platform android */ elevation?: number | undefined; + /** + * Controls whether the View can be the target of touch events. + */ + pointerEvents?: 'box-none' | 'none' | 'box-only' | 'auto' | undefined; } export type FontVariant = diff --git a/Libraries/StyleSheet/StyleSheetTypes.js b/Libraries/StyleSheet/StyleSheetTypes.js index 44015f2b02b160..4fc70eed012233 100644 --- a/Libraries/StyleSheet/StyleSheetTypes.js +++ b/Libraries/StyleSheet/StyleSheetTypes.js @@ -698,6 +698,9 @@ export type ____ViewStyle_InternalCore = $ReadOnly<{ borderRightColor?: ____ColorValue_Internal, borderStartColor?: ____ColorValue_Internal, borderTopColor?: ____ColorValue_Internal, + borderBlockColor?: ____ColorValue_Internal, + borderBlockEndColor?: ____ColorValue_Internal, + borderBlockStartColor?: ____ColorValue_Internal, borderRadius?: number | AnimatedNode, borderBottomEndRadius?: number | AnimatedNode, borderBottomLeftRadius?: number | AnimatedNode, diff --git a/Libraries/Utilities/Appearance.d.ts b/Libraries/Utilities/Appearance.d.ts index 7d2faf69d8cec4..2b8428e0d7d1de 100644 --- a/Libraries/Utilities/Appearance.d.ts +++ b/Libraries/Utilities/Appearance.d.ts @@ -28,6 +28,16 @@ export namespace Appearance { */ export function getColorScheme(): ColorSchemeName; + /** + * Set the color scheme preference. This is useful for overriding the default + * color scheme preference for the app. Note that this will not change the + * appearance of the system UI, only the appearance of the app. + * Only available on iOS 13+ and Android 10+. + */ + export function setColorScheme( + scheme: ColorSchemeName | null | undefined, + ): void; + /** * Add an event handler that is fired when appearance preferences change. */ diff --git a/Libraries/Utilities/Appearance.js b/Libraries/Utilities/Appearance.js index 54d03dd18200b2..69817442085124 100644 --- a/Libraries/Utilities/Appearance.js +++ b/Libraries/Utilities/Appearance.js @@ -85,6 +85,17 @@ module.exports = { return nativeColorScheme; }, + setColorScheme(colorScheme: ?ColorSchemeName): void { + const nativeColorScheme = colorScheme == null ? 'unspecified' : colorScheme; + + invariant( + colorScheme === 'dark' || colorScheme === 'light' || colorScheme == null, + "Unrecognized color scheme. Did you mean 'dark', 'light' or null?", + ); + + NativeAppearance?.setColorScheme?.(nativeColorScheme); + }, + /** * Add an event handler that is fired when appearance preferences change. */ diff --git a/Libraries/Utilities/NativeAppearance.js b/Libraries/Utilities/NativeAppearance.js index cb8688f14e2967..786790f5987140 100644 --- a/Libraries/Utilities/NativeAppearance.js +++ b/Libraries/Utilities/NativeAppearance.js @@ -26,6 +26,7 @@ export interface Spec extends TurboModule { // types. /* 'light' | 'dark' */ +getColorScheme: () => ?string; + +setColorScheme?: (colorScheme: string) => void; // RCTEventEmitter +addListener: (eventName: string) => void; diff --git a/Libraries/Utilities/ReactNativeTestTools.js b/Libraries/Utilities/ReactNativeTestTools.js index 5dc2221528dcee..8671575054137c 100644 --- a/Libraries/Utilities/ReactNativeTestTools.js +++ b/Libraries/Utilities/ReactNativeTestTools.js @@ -15,8 +15,8 @@ import type {ReactTestRenderer as ReactTestRendererType} from 'react-test-render const Switch = require('../Components/Switch/Switch').default; const TextInput = require('../Components/TextInput/TextInput'); const View = require('../Components/View/View'); -const VirtualizedList = require('../Lists/VirtualizedList').default; const Text = require('../Text/Text'); +const {VirtualizedList} = require('@react-native/virtualized-lists'); const React = require('react'); const ShallowRenderer = require('react-shallow-renderer'); const ReactTestRenderer = require('react-test-renderer'); diff --git a/React-Core.podspec b/React-Core.podspec index b0bc4959222338..31db1b23d9a3ed 100644 --- a/React-Core.podspec +++ b/React-Core.podspec @@ -75,12 +75,20 @@ Pod::Spec.new do |s| s.subspec "Default" do |ss| ss.source_files = "React/**/*.{c,h,m,mm,S,cpp}" - ss.exclude_files = "React/CoreModules/**/*", - "React/DevSupport/**/*", - "React/Fabric/**/*", - "React/FBReactNativeSpec/**/*", - "React/Tests/**/*", - "React/Inspector/**/*" + exclude_files = [ + "React/CoreModules/**/*", + "React/DevSupport/**/*", + "React/Fabric/**/*", + "React/FBReactNativeSpec/**/*", + "React/Tests/**/*", + "React/Inspector/**/*" + ] + # If we are using Hermes (the default is use hermes, so USE_HERMES can be nil), we don't have jsc installed + # So we have to exclude the JSCExecutorFactory + if ENV['USE_HERMES'] == nil || ENV['USE_HERMES'] == "1" + exclude_files = exclude_files.append("React/CxxBridge/JSCExecutorFactory.{h,mm}") + end + ss.exclude_files = exclude_files ss.private_header_files = "React/Cxx*/*.h" end @@ -114,4 +122,11 @@ Pod::Spec.new do |s| s.dependency "React-jsiexecutor", version s.dependency "Yoga" s.dependency "glog" + + if ENV['USE_HERMES'] == "0" + s.dependency 'React-jsc' + else + s.dependency 'React-hermes' + s.dependency 'hermes-engine' + end end diff --git a/React/CoreModules/RCTAppearance.h b/React/CoreModules/RCTAppearance.h index d8bb18b89ac32b..caa842d72f6a1b 100644 --- a/React/CoreModules/RCTAppearance.h +++ b/React/CoreModules/RCTAppearance.h @@ -8,6 +8,7 @@ #import #import +#import #import RCT_EXTERN void RCTEnableAppearancePreference(BOOL enabled); diff --git a/React/CoreModules/RCTAppearance.mm b/React/CoreModules/RCTAppearance.mm index 71259d4a98d119..72257c8fa1bfdc 100644 --- a/React/CoreModules/RCTAppearance.mm +++ b/React/CoreModules/RCTAppearance.mm @@ -10,6 +10,7 @@ #import #import #import +#import #import "CoreModulesPlugins.h" @@ -68,6 +69,20 @@ void RCTOverrideAppearancePreference(NSString *const colorSchemeOverride) return RCTAppearanceColorSchemeLight; } +@implementation RCTConvert (UIUserInterfaceStyle) + +RCT_ENUM_CONVERTER( + UIUserInterfaceStyle, + (@{ + @"light" : @(UIUserInterfaceStyleLight), + @"dark" : @(UIUserInterfaceStyleDark), + @"unspecified" : @(UIUserInterfaceStyleUnspecified) + }), + UIUserInterfaceStyleUnspecified, + integerValue); + +@end + @interface RCTAppearance () @end @@ -92,6 +107,17 @@ - (dispatch_queue_t)methodQueue return std::make_shared(params); } +RCT_EXPORT_METHOD(setColorScheme : (NSString *)style) +{ + UIUserInterfaceStyle userInterfaceStyle = [RCTConvert UIUserInterfaceStyle:style]; + NSArray<__kindof UIWindow *> *windows = RCTSharedApplication().windows; + if (@available(iOS 13.0, *)) { + for (UIWindow *window in windows) { + window.overrideUserInterfaceStyle = userInterfaceStyle; + } + } +} + RCT_EXPORT_SYNCHRONOUS_TYPED_METHOD(NSString *, getColorScheme) { if (_currentColorScheme == nil) { diff --git a/React/CoreModules/React-CoreModules.podspec b/React/CoreModules/React-CoreModules.podspec index 90c8adf1bc27f7..89f79da17b46d1 100644 --- a/React/CoreModules/React-CoreModules.podspec +++ b/React/CoreModules/React-CoreModules.podspec @@ -44,4 +44,5 @@ Pod::Spec.new do |s| s.dependency "React-RCTImage", version s.dependency "ReactCommon/turbomodule/core", version s.dependency "React-jsi", version + s.dependency 'React-RCTBlob' end diff --git a/React/Views/RCTView.h b/React/Views/RCTView.h index adda5c1f016848..abb1966a199f0c 100644 --- a/React/Views/RCTView.h +++ b/React/Views/RCTView.h @@ -86,6 +86,9 @@ extern const UIAccessibilityTraits SwitchAccessibilityTrait; @property (nonatomic, strong) UIColor *borderStartColor; @property (nonatomic, strong) UIColor *borderEndColor; @property (nonatomic, strong) UIColor *borderColor; +@property (nonatomic, strong) UIColor *borderBlockColor; +@property (nonatomic, strong) UIColor *borderBlockEndColor; +@property (nonatomic, strong) UIColor *borderBlockStartColor; /** * Border widths. @@ -97,6 +100,10 @@ extern const UIAccessibilityTraits SwitchAccessibilityTrait; @property (nonatomic, assign) CGFloat borderStartWidth; @property (nonatomic, assign) CGFloat borderEndWidth; @property (nonatomic, assign) CGFloat borderWidth; +// TODO: Implement logical border width logic +@property (nonatomic, assign) CGFloat borderBlockWidth; +@property (nonatomic, assign) CGFloat borderBlockEndWidth; +@property (nonatomic, assign) CGFloat borderBlockStartWidth; /** * Border curve. diff --git a/React/Views/RCTView.m b/React/Views/RCTView.m index f9a38f31040f1b..6d7583395e3415 100644 --- a/React/Views/RCTView.m +++ b/React/Views/RCTView.m @@ -745,6 +745,17 @@ - (RCTBorderColors)borderColorsWithTraitCollection:(UITraitCollection *)traitCol UIColor *borderTopColor = _borderTopColor; UIColor *borderBottomColor = _borderBottomColor; + if (_borderBlockColor) { + borderTopColor = _borderBlockColor; + borderBottomColor = _borderBlockColor; + } + if (_borderBlockEndColor) { + borderBottomColor = _borderBlockEndColor; + } + if (_borderBlockStartColor) { + borderTopColor = _borderBlockStartColor; + } + #if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 if (@available(iOS 13.0, *)) { borderColor = [borderColor resolvedColorWithTraitCollection:self.traitCollection]; @@ -924,7 +935,7 @@ -(void)setBorder##side##Color : (UIColor *)color \ } setBorderColor() setBorderColor(Top) setBorderColor(Right) setBorderColor(Bottom) setBorderColor(Left) - setBorderColor(Start) setBorderColor(End) + setBorderColor(Start) setBorderColor(End) setBorderColor(Block) setBorderColor(BlockEnd) setBorderColor(BlockStart) #pragma mark - Border Width diff --git a/React/Views/RCTViewManager.m b/React/Views/RCTViewManager.m index e50b4c19d91a50..a866b6f748987d 100644 --- a/React/Views/RCTViewManager.m +++ b/React/Views/RCTViewManager.m @@ -358,6 +358,9 @@ - (RCTShadowView *)shadowView RCT_VIEW_BORDER_PROPERTY(Left) RCT_VIEW_BORDER_PROPERTY(Start) RCT_VIEW_BORDER_PROPERTY(End) +RCT_VIEW_BORDER_PROPERTY(Block) +RCT_VIEW_BORDER_PROPERTY(BlockEnd) +RCT_VIEW_BORDER_PROPERTY(BlockStart) #define RCT_VIEW_BORDER_RADIUS_PROPERTY(SIDE) \ RCT_CUSTOM_VIEW_PROPERTY(border##SIDE##Radius, CGFloat, RCTView) \ diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java b/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java index 5ac4cd77d23006..1ac3df2b2c08f5 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java +++ b/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java @@ -179,7 +179,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { mWasMeasured = true; // Check if we were waiting for onMeasure to attach the root view. - if (mReactInstanceManager != null && !mIsAttachedToInstance) { + if (hasActiveReactInstance() && !isViewAttachedToReactInstance()) { attachToReactInstanceManager(); } else if (measureSpecsUpdated || mLastWidth != width || mLastHeight != height) { updateRootLayoutSpecs(true, mWidthMeasureSpec, mHeightMeasureSpec); @@ -203,7 +203,7 @@ public void onChildStartedNativeGesture(View childView, MotionEvent ev) { if (!isDispatcherReady()) { return; } - ReactContext reactContext = mReactInstanceManager.getCurrentReactContext(); + ReactContext reactContext = getCurrentReactContext(); UIManager uiManager = UIManagerHelper.getUIManager(reactContext, getUIManagerType()); if (uiManager != null) { @@ -220,7 +220,7 @@ public void onChildEndedNativeGesture(View childView, MotionEvent ev) { if (!isDispatcherReady()) { return; } - ReactContext reactContext = mReactInstanceManager.getCurrentReactContext(); + ReactContext reactContext = getCurrentReactContext(); UIManager uiManager = UIManagerHelper.getUIManager(reactContext, getUIManagerType()); if (uiManager != null) { @@ -233,9 +233,7 @@ public void onChildEndedNativeGesture(View childView, MotionEvent ev) { } private boolean isDispatcherReady() { - if (mReactInstanceManager == null - || !mIsAttachedToInstance - || mReactInstanceManager.getCurrentReactContext() == null) { + if (!hasActiveReactContext() || !isViewAttachedToReactInstance()) { FLog.w(TAG, "Unable to dispatch touch to JS as the catalyst instance has not been attached"); return false; } @@ -262,31 +260,31 @@ public boolean onInterceptTouchEvent(MotionEvent ev) { if (shouldDispatchJSTouchEvent(ev)) { dispatchJSTouchEvent(ev); } - dispatchJSPointerEvent(ev); + dispatchJSPointerEvent(ev, true); return super.onInterceptTouchEvent(ev); } - @Override - public boolean onInterceptHoverEvent(MotionEvent ev) { - dispatchJSPointerEvent(ev); - return super.onInterceptHoverEvent(ev); - } - @Override public boolean onTouchEvent(MotionEvent ev) { if (shouldDispatchJSTouchEvent(ev)) { dispatchJSTouchEvent(ev); } - dispatchJSPointerEvent(ev); + dispatchJSPointerEvent(ev, false); super.onTouchEvent(ev); // In case when there is no children interested in handling touch event, we return true from // the root view in order to receive subsequent events related to that gesture return true; } + @Override + public boolean onInterceptHoverEvent(MotionEvent ev) { + dispatchJSPointerEvent(ev, true); + return super.onInterceptHoverEvent(ev); + } + @Override public boolean onHoverEvent(MotionEvent ev) { - dispatchJSPointerEvent(ev); + dispatchJSPointerEvent(ev, false); return super.onHoverEvent(ev); } @@ -303,9 +301,7 @@ protected void dispatchDraw(Canvas canvas) { @Override public boolean dispatchKeyEvent(KeyEvent ev) { - if (mReactInstanceManager == null - || !mIsAttachedToInstance - || mReactInstanceManager.getCurrentReactContext() == null) { + if (!hasActiveReactContext() || !isViewAttachedToReactInstance()) { FLog.w(TAG, "Unable to handle key event as the catalyst instance has not been attached"); return super.dispatchKeyEvent(ev); } @@ -315,9 +311,7 @@ public boolean dispatchKeyEvent(KeyEvent ev) { @Override protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) { - if (mReactInstanceManager == null - || !mIsAttachedToInstance - || mReactInstanceManager.getCurrentReactContext() == null) { + if (!hasActiveReactContext() || !isViewAttachedToReactInstance()) { FLog.w( TAG, "Unable to handle focus changed event as the catalyst instance has not been attached"); @@ -330,9 +324,7 @@ protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyF @Override public void requestChildFocus(View child, View focused) { - if (mReactInstanceManager == null - || !mIsAttachedToInstance - || mReactInstanceManager.getCurrentReactContext() == null) { + if (!hasActiveReactContext() || !isViewAttachedToReactInstance()) { FLog.w( TAG, "Unable to handle child focus changed event as the catalyst instance has not been attached"); @@ -343,10 +335,8 @@ public void requestChildFocus(View child, View focused) { super.requestChildFocus(child, focused); } - protected void dispatchJSPointerEvent(MotionEvent event) { - if (mReactInstanceManager == null - || !mIsAttachedToInstance - || mReactInstanceManager.getCurrentReactContext() == null) { + protected void dispatchJSPointerEvent(MotionEvent event, boolean isCapture) { + if (!hasActiveReactContext() || !isViewAttachedToReactInstance()) { FLog.w(TAG, "Unable to dispatch touch to JS as the catalyst instance has not been attached"); return; } @@ -357,19 +347,17 @@ protected void dispatchJSPointerEvent(MotionEvent event) { FLog.w(TAG, "Unable to dispatch pointer events to JS before the dispatcher is available"); return; } - ReactContext reactContext = mReactInstanceManager.getCurrentReactContext(); + ReactContext reactContext = getCurrentReactContext(); UIManager uiManager = UIManagerHelper.getUIManager(reactContext, getUIManagerType()); if (uiManager != null) { EventDispatcher eventDispatcher = uiManager.getEventDispatcher(); - mJSPointerDispatcher.handleMotionEvent(event, eventDispatcher); + mJSPointerDispatcher.handleMotionEvent(event, eventDispatcher, isCapture); } } protected void dispatchJSTouchEvent(MotionEvent event) { - if (mReactInstanceManager == null - || !mIsAttachedToInstance - || mReactInstanceManager.getCurrentReactContext() == null) { + if (!hasActiveReactContext() || !isViewAttachedToReactInstance()) { FLog.w(TAG, "Unable to dispatch touch to JS as the catalyst instance has not been attached"); return; } @@ -377,7 +365,7 @@ protected void dispatchJSTouchEvent(MotionEvent event) { FLog.w(TAG, "Unable to dispatch touch to JS before the dispatcher is available"); return; } - ReactContext reactContext = mReactInstanceManager.getCurrentReactContext(); + ReactContext reactContext = getCurrentReactContext(); UIManager uiManager = UIManagerHelper.getUIManager(reactContext, getUIManagerType()); if (uiManager != null) { @@ -412,7 +400,7 @@ private boolean isFabric() { @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); - if (mIsAttachedToInstance) { + if (isViewAttachedToReactInstance()) { removeOnGlobalLayoutListener(); getViewTreeObserver().addOnGlobalLayoutListener(getCustomGlobalLayoutListener()); } @@ -421,7 +409,7 @@ protected void onAttachedToWindow() { @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); - if (mIsAttachedToInstance) { + if (isViewAttachedToReactInstance()) { removeOnGlobalLayoutListener(); } } @@ -571,7 +559,7 @@ public AtomicInteger getState() { private void updateRootLayoutSpecs( boolean measureSpecsChanged, final int widthMeasureSpec, final int heightMeasureSpec) { ReactMarker.logMarker(ReactMarkerConstants.ROOT_VIEW_UPDATE_LAYOUT_SPECS_START); - if (mReactInstanceManager == null) { + if (!hasActiveReactInstance()) { ReactMarker.logMarker(ReactMarkerConstants.ROOT_VIEW_UPDATE_LAYOUT_SPECS_END); FLog.w(TAG, "Unable to update root layout specs for uninitialized ReactInstanceManager"); return; @@ -585,7 +573,7 @@ private void updateRootLayoutSpecs( return; } - final ReactContext reactApplicationContext = mReactInstanceManager.getCurrentReactContext(); + final ReactContext reactApplicationContext = getCurrentReactContext(); if (reactApplicationContext != null) { @Nullable @@ -629,8 +617,8 @@ public void unmountReactApplication() { // to be committed via the Scheduler, which will cause mounting instructions // to be queued up and synchronously executed to delete and remove // all the views in the hierarchy. - if (mReactInstanceManager != null) { - final ReactContext reactApplicationContext = mReactInstanceManager.getCurrentReactContext(); + if (hasActiveReactInstance()) { + final ReactContext reactApplicationContext = getCurrentReactContext(); if (reactApplicationContext != null && isFabric()) { @Nullable UIManager uiManager = @@ -729,11 +717,11 @@ public void setAppProperties(@Nullable Bundle appProperties) { public void runApplication() { Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "ReactRootView.runApplication"); try { - if (mReactInstanceManager == null || !mIsAttachedToInstance) { + if (!hasActiveReactInstance() || !isViewAttachedToReactInstance()) { return; } - ReactContext reactContext = mReactInstanceManager.getCurrentReactContext(); + ReactContext reactContext = getCurrentReactContext(); if (reactContext == null) { return; } @@ -853,12 +841,12 @@ public void setRootViewTag(int rootViewTag) { @Override public void handleException(final Throwable t) { - if (mReactInstanceManager == null || mReactInstanceManager.getCurrentReactContext() == null) { + if (!hasActiveReactContext()) { throw new RuntimeException(t); } Exception e = new IllegalViewOperationException(t.getMessage(), this, t); - mReactInstanceManager.getCurrentReactContext().handleException(e); + getCurrentReactContext().handleException(e); } public void setIsFabric(boolean isFabric) { @@ -876,14 +864,30 @@ public ReactInstanceManager getReactInstanceManager() { } /* package */ void sendEvent(String eventName, @Nullable WritableMap params) { - if (mReactInstanceManager != null) { - mReactInstanceManager - .getCurrentReactContext() + if (hasActiveReactInstance()) { + getCurrentReactContext() .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) .emit(eventName, params); } } + public boolean hasActiveReactInstance() { + return mReactInstanceManager != null; + } + + public boolean hasActiveReactContext() { + return mReactInstanceManager != null && mReactInstanceManager.getCurrentReactContext() != null; + } + + @Nullable + public ReactContext getCurrentReactContext() { + return mReactInstanceManager.getCurrentReactContext(); + } + + public boolean isViewAttachedToReactInstance() { + return mIsAttachedToInstance; + } + private class CustomGlobalLayoutListener implements ViewTreeObserver.OnGlobalLayoutListener { private final Rect mVisibleViewArea; private final int mMinKeyboardHeightDetected; @@ -900,9 +904,7 @@ private class CustomGlobalLayoutListener implements ViewTreeObserver.OnGlobalLay @Override public void onGlobalLayout() { - if (mReactInstanceManager == null - || !mIsAttachedToInstance - || mReactInstanceManager.getCurrentReactContext() == null) { + if (!hasActiveReactContext() || !isViewAttachedToReactInstance()) { return; } @@ -1061,7 +1063,7 @@ private void emitOrientationChanged(final int newRotation) { private void emitUpdateDimensionsEvent() { DeviceInfoModule deviceInfo = - mReactInstanceManager.getCurrentReactContext().getNativeModule(DeviceInfoModule.class); + getCurrentReactContext().getNativeModule(DeviceInfoModule.class); if (deviceInfo != null) { deviceInfo.emitUpdateDimensionsEvent(); diff --git a/ReactAndroid/src/main/java/com/facebook/react/common/JavascriptException.java b/ReactAndroid/src/main/java/com/facebook/react/common/JavascriptException.java index d1aaca03123ee3..b3945ee2508057 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/common/JavascriptException.java +++ b/ReactAndroid/src/main/java/com/facebook/react/common/JavascriptException.java @@ -7,12 +7,14 @@ package com.facebook.react.common; +import com.facebook.proguard.annotations.DoNotStrip; import javax.annotation.Nullable; /** * A JS exception that was propagated to native. In debug mode, these exceptions are normally shown * to developers in a redbox. */ +@DoNotStrip public class JavascriptException extends RuntimeException implements HasJavascriptExceptionMetadata { 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 843bc6acc2dd07..a4df8b3565d6a9 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/config/ReactFeatureFlags.java +++ b/ReactAndroid/src/main/java/com/facebook/react/config/ReactFeatureFlags.java @@ -67,9 +67,6 @@ public class ReactFeatureFlags { /** Enables or disables calculation of Transformed Frames */ public static boolean calculateTransformedFramesEnabled = false; - /** Feature Flag to use overflowInset values provided by Yoga */ - public static boolean useOverflowInset = false; - public static boolean dispatchPointerEvents = false; /** Feature Flag to enable the pending event queue in fabric before mounting views */ @@ -115,4 +112,10 @@ public class ReactFeatureFlags { * state in Fabric SurfaceMountingManager. */ public static boolean reduceDeleteCreateMutationLayoutAnimation = true; + + /** + * Allow fix to drop delete...create mutations which could cause missing view state in Fabric + * SurfaceMountingManager. + */ + public static boolean reduceDeleteCreateMutation = false; } diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/Binding.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/Binding.java index e6cad3c21595b3..19caa193e40bd7 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/Binding.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/Binding.java @@ -9,7 +9,6 @@ import android.annotation.SuppressLint; import androidx.annotation.NonNull; -import androidx.annotation.Nullable; import com.facebook.jni.HybridData; import com.facebook.proguard.annotations.DoNotStrip; import com.facebook.react.bridge.NativeMap; @@ -86,7 +85,7 @@ public native ReadableNativeMap getInspectorDataForInstance( public void register( @NonNull RuntimeExecutor runtimeExecutor, - @Nullable RuntimeScheduler runtimeScheduler, + @NonNull RuntimeScheduler runtimeScheduler, @NonNull FabricUIManager fabricUIManager, @NonNull EventBeatManager eventBeatManager, @NonNull ComponentFactory componentFactory, diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java index e0947264fd959a..5f3a34038bed36 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java @@ -182,9 +182,6 @@ public void onFabricCommitEnd(DevToolsReactPerfLogger.FabricCommitPoint commitPo */ private volatile boolean mDestroyed = false; - // TODO T83943316: Delete this variable once StaticViewConfigs are enabled by default - private volatile boolean mShouldDeallocateEventDispatcher = false; - private boolean mDriveCxxAnimations = false; private long mDispatchViewUpdatesTime = 0l; @@ -209,28 +206,6 @@ public void executeItems(Queue items) { } }; - // TODO T83943316: Deprecate and delete this constructor once StaticViewConfigs are enabled by - // default - @Deprecated - public FabricUIManager( - ReactApplicationContext reactContext, - ViewManagerRegistry viewManagerRegistry, - EventDispatcher eventDispatcher, - EventBeatManager eventBeatManager) { - mDispatchUIFrameCallback = new DispatchUIFrameCallback(reactContext); - mReactApplicationContext = reactContext; - mMountingManager = new MountingManager(viewManagerRegistry, mMountItemExecutor); - mMountItemDispatcher = - new MountItemDispatcher(mMountingManager, new MountItemDispatchListener()); - mEventDispatcher = eventDispatcher; - mShouldDeallocateEventDispatcher = false; - mEventBeatManager = eventBeatManager; - mReactApplicationContext.addLifecycleEventListener(this); - - mViewManagerRegistry = viewManagerRegistry; - mReactApplicationContext.registerComponentCallbacks(viewManagerRegistry); - } - public FabricUIManager( ReactApplicationContext reactContext, ViewManagerRegistry viewManagerRegistry, @@ -241,7 +216,6 @@ public FabricUIManager( mMountItemDispatcher = new MountItemDispatcher(mMountingManager, new MountItemDispatchListener()); mEventDispatcher = new EventDispatcherImpl(reactContext); - mShouldDeallocateEventDispatcher = true; mEventBeatManager = eventBeatManager; mReactApplicationContext.addLifecycleEventListener(this); @@ -467,10 +441,11 @@ public void onCatalystInstanceDestroy() { ViewManagerPropertyUpdater.clear(); - // When using StaticViewConfigs is enabled, FabriUIManager is - // responsible for initializing and deallocating EventDispatcher. + // When StaticViewConfigs is enabled, FabriUIManager is + // responsible for initializing and deallocating EventDispatcher. StaticViewConfigs is enabled + // only in Bridgeless for now. // TODO T83943316: Remove this IF once StaticViewConfigs are enabled by default - if (mShouldDeallocateEventDispatcher) { + if (!ReactFeatureFlags.enableBridgelessArchitecture) { mEventDispatcher.onCatalystInstanceDestroyed(); } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/appearance/AppearanceModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/appearance/AppearanceModule.java index e64bbe122c6df6..301a8deff1bc05 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/appearance/AppearanceModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/appearance/AppearanceModule.java @@ -11,6 +11,7 @@ import android.content.Context; import android.content.res.Configuration; import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatDelegate; import com.facebook.fbreact.specs.NativeAppearanceSpec; import com.facebook.react.bridge.Arguments; import com.facebook.react.bridge.ReactApplicationContext; @@ -66,6 +67,17 @@ private String colorSchemeForCurrentConfiguration(Context context) { return "light"; } + @Override + public void setColorScheme(String style) { + if (style == "dark") { + AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES); + } else if (style == "light") { + AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO); + } else if (style == "unspecified") { + AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM); + } + } + @Override public String getColorScheme() { // Attempt to use the Activity context first in order to get the most up to date diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/appearance/BUCK b/ReactAndroid/src/main/java/com/facebook/react/modules/appearance/BUCK index 4cb4e081946767..044b4c8d0941a1 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/appearance/BUCK +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/appearance/BUCK @@ -14,6 +14,7 @@ rn_android_library( deps = [ react_native_dep("third-party/java/jsr-305:jsr-305"), react_native_dep("third-party/android/androidx:annotation"), + react_native_dep("third-party/android/androidx:appcompat"), react_native_target("java/com/facebook/react/bridge:bridge"), react_native_target("java/com/facebook/react/common:common"), react_native_target("java/com/facebook/react/module/annotations:annotations"), diff --git a/ReactAndroid/src/main/java/com/facebook/react/shell/BUCK b/ReactAndroid/src/main/java/com/facebook/react/shell/BUCK index b64122b9d3975e..5621dd31762a68 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/shell/BUCK +++ b/ReactAndroid/src/main/java/com/facebook/react/shell/BUCK @@ -15,6 +15,7 @@ rn_android_library( react_native_dep("libraries/fresco/fresco-react-native:imagepipeline"), react_native_dep("libraries/soloader/java/com/facebook/soloader:soloader"), react_native_dep("third-party/android/androidx:annotation"), + react_native_dep("third-party/android/androidx:appcompat"), react_native_dep("third-party/android/androidx:core"), react_native_dep("third-party/android/androidx:fragment"), react_native_dep("third-party/android/androidx:legacy-support-core-utils"), diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/JSPointerDispatcher.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/JSPointerDispatcher.java index e1f75da6dc6f63..2a462123eaa69b 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/JSPointerDispatcher.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/JSPointerDispatcher.java @@ -199,7 +199,8 @@ private PointerEventState createEventState(int activePointerId, MotionEvent moti mHoveringPointerIds); // Creates a copy of hovering pointer ids, as they may be updated } - public void handleMotionEvent(MotionEvent motionEvent, EventDispatcher eventDispatcher) { + public void handleMotionEvent( + MotionEvent motionEvent, EventDispatcher eventDispatcher, boolean isCapture) { // Don't fire any pointer events if child view is handling native gesture if (mChildHandlingNativeGesture != -1) { return; @@ -214,16 +215,44 @@ public void handleMotionEvent(MotionEvent motionEvent, EventDispatcher eventDisp } PointerEventState eventState = createEventState(activePointerId, motionEvent); - List activeHitPath = - eventState.getHitPathByPointerId().get(eventState.getActivePointerId()); - if (activeHitPath == null || activeHitPath.isEmpty()) { - return; + // We've empirically determined that when we get a ACTION_HOVER_EXIT from the root view on the + // `onInterceptHoverEvent`, this means we've exited the root view. + // This logic may be wrong but reasoning about the dispatch sequence for HOVER_ENTER/HOVER_EXIT + // doesn't follow the capture/bubbling sequence like other MotionEvents. See: + // https://developer.android.com/reference/android/view/MotionEvent#ACTION_HOVER_ENTER + // https://suragch.medium.com/how-touch-events-are-delivered-in-android-eee3b607b038 + boolean isExitFromRoot = + isCapture && motionEvent.getActionMasked() == MotionEvent.ACTION_HOVER_EXIT; + + // Calculate the targetTag, with special handling for when we exit the root view. In that case, + // we use the root viewId of the last event + int activeTargetTag; + + List activeHitPath; + if (isExitFromRoot) { + List lastHitPath = + mLastHitPathByPointerId != null + ? mLastHitPathByPointerId.get(eventState.getActivePointerId()) + : null; + if (lastHitPath == null || lastHitPath.isEmpty()) { + return; + } + activeTargetTag = lastHitPath.get(lastHitPath.size() - 1).getViewId(); + + // Explicitly make the hit path for this cursor empty + activeHitPath = new ArrayList<>(); + eventState.getHitPathByPointerId().put(activePointerId, activeHitPath); + } else { + activeHitPath = eventState.getHitPathByPointerId().get(activePointerId); + if (activeHitPath == null || activeHitPath.isEmpty()) { + return; + } + activeTargetTag = activeHitPath.get(0).getViewId(); } - TouchTargetHelper.ViewTarget activeViewTarget = activeHitPath.get(0); - int activeTargetTag = activeViewTarget.getViewId(); - + // Dispatch pointer events from the MotionEvents. When we want to ignore an event, we need to + // exit early so we don't record anything about this MotionEvent. switch (action) { case MotionEvent.ACTION_DOWN: case MotionEvent.ACTION_POINTER_DOWN: @@ -231,7 +260,18 @@ public void handleMotionEvent(MotionEvent motionEvent, EventDispatcher eventDisp break; case MotionEvent.ACTION_HOVER_MOVE: // TODO(luwe) - converge this with ACTION_MOVE - // HOVER_MOVE may occur before DOWN. Add its downTime as a coalescing key + + // If we don't move enough, ignore this event. + float[] eventCoordinates = eventState.getEventCoordinatesByPointerId().get(activePointerId); + float[] lastEventCoordinates = + mLastEventCoordinatesByPointerId != null + && mLastEventCoordinatesByPointerId.containsKey(activePointerId) + ? mLastEventCoordinatesByPointerId.get(activePointerId) + : new float[] {0, 0}; + if (!qualifiedMove(eventCoordinates, lastEventCoordinates)) { + return; + } + onMove(activeTargetTag, eventState, motionEvent, eventDispatcher); break; case MotionEvent.ACTION_MOVE: @@ -257,8 +297,15 @@ public void handleMotionEvent(MotionEvent motionEvent, EventDispatcher eventDisp dispatchCancelEvent(eventState, motionEvent, eventDispatcher); break; case MotionEvent.ACTION_HOVER_ENTER: + // Ignore these events as enters will be calculated from HOVER_MOVE + return; case MotionEvent.ACTION_HOVER_EXIT: - // These are handled by HOVER_MOVE + // For root exits, we need to update our stored eventState to reflect this exit because we + // won't receive future HOVER_MOVE events when cursor is outside root view + if (isExitFromRoot) { + // We've set the hit path for this pointer to be empty to calculate all exits + onMove(activeTargetTag, eventState, motionEvent, eventDispatcher); + } break; default: FLog.w( @@ -267,6 +314,7 @@ public void handleMotionEvent(MotionEvent motionEvent, EventDispatcher eventDisp return; } + // Caching the event state so we have a new "last" mLastHitPathByPointerId = eventState.getHitPathByPointerId(); mLastEventCoordinatesByPointerId = eventState.getEventCoordinatesByPointerId(); mLastButtonState = motionEvent.getButtonState(); @@ -335,7 +383,11 @@ private void dispatchEventForViewTargets( } } - // called on hover_move motion events only + private boolean qualifiedMove(float[] eventCoordinates, float[] lastEventCoordinates) { + return (Math.abs(lastEventCoordinates[0] - eventCoordinates[0]) > ONMOVE_EPSILON + || Math.abs(lastEventCoordinates[1] - eventCoordinates[1]) > ONMOVE_EPSILON); + } + private void onMove( int targetTag, PointerEventState eventState, @@ -343,7 +395,6 @@ private void onMove( EventDispatcher eventDispatcher) { int activePointerId = eventState.getActivePointerId(); - float[] eventCoordinates = eventState.getEventCoordinatesByPointerId().get(activePointerId); List activeHitPath = eventState.getHitPathByPointerId().get(activePointerId); List lastHitPath = @@ -351,21 +402,6 @@ private void onMove( ? mLastHitPathByPointerId.get(activePointerId) : new ArrayList(); - float[] lastEventCoordinates = - mLastEventCoordinatesByPointerId != null - && mLastEventCoordinatesByPointerId.containsKey(activePointerId) - ? mLastEventCoordinatesByPointerId.get(activePointerId) - : new float[] {0, 0}; - - boolean qualifiedMove = - (Math.abs(lastEventCoordinates[0] - eventCoordinates[0]) > ONMOVE_EPSILON - || Math.abs(lastEventCoordinates[1] - eventCoordinates[1]) > ONMOVE_EPSILON); - - // Early exit if active pointer has not moved enough - if (!qualifiedMove) { - return; - } - // hitState is list ordered from inner child -> parent tag // Traverse hitState back-to-front to find the first divergence with lastHitPath // FIXME: this may generate incorrect events when view collapsing changes the hierarchy diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/Spacing.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/Spacing.java index 36aeb9776da067..9ff37664d52b67 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/Spacing.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/Spacing.java @@ -47,10 +47,18 @@ public class Spacing { * Spacing type that represents all directions (left, top, right, bottom). E.g. {@code margin}. */ public static final int ALL = 8; + /** Spacing type that represents block directions (top, bottom). E.g. {@code marginBlock}. */ + public static final int BLOCK = 9; + /** Spacing type that represents the block end direction (bottom). E.g. {@code marginBlockEnd}. */ + public static final int BLOCK_END = 10; + /** + * Spacing type that represents the block start direction (top). E.g. {@code marginBlockStart}. + */ + public static final int BLOCK_START = 11; private static final int[] sFlagsMap = { 1, /*LEFT*/ 2, /*TOP*/ 4, /*RIGHT*/ 8, /*BOTTOM*/ 16, /*START*/ 32, /*END*/ 64, /*HORIZONTAL*/ - 128, /*VERTICAL*/ 256, /*ALL*/ + 128, /*VERTICAL*/ 256, /*ALL*/ 512, /*BLOCK*/ 1024, /*BLOCK_END*/ 2048, /*BLOCK_START*/ }; private final float[] mSpacing; @@ -96,7 +104,8 @@ public boolean set(int spacingType, float value) { mHasAliasesSet = (mValueFlags & sFlagsMap[ALL]) != 0 || (mValueFlags & sFlagsMap[VERTICAL]) != 0 - || (mValueFlags & sFlagsMap[HORIZONTAL]) != 0; + || (mValueFlags & sFlagsMap[HORIZONTAL]) != 0 + || (mValueFlags & sFlagsMap[BLOCK]) != 0; return true; } @@ -111,7 +120,13 @@ public boolean set(int spacingType, float value) { */ public float get(int spacingType) { float defaultValue = - (spacingType == START || spacingType == END ? YogaConstants.UNDEFINED : mDefaultValue); + (spacingType == START + || spacingType == END + || spacingType == BLOCK + || spacingType == BLOCK_END + || spacingType == BLOCK_START + ? YogaConstants.UNDEFINED + : mDefaultValue); if (mValueFlags == 0) { return defaultValue; @@ -174,6 +189,9 @@ private static float[] newFullSpacingArray() { YogaConstants.UNDEFINED, YogaConstants.UNDEFINED, YogaConstants.UNDEFINED, + YogaConstants.UNDEFINED, + YogaConstants.UNDEFINED, + YogaConstants.UNDEFINED, }; } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/TouchTargetHelper.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/TouchTargetHelper.java index 4b1a518f10dd7b..cff46d4dcbd27e 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/TouchTargetHelper.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/TouchTargetHelper.java @@ -19,7 +19,6 @@ import androidx.annotation.Nullable; import com.facebook.react.bridge.JSApplicationIllegalArgumentException; import com.facebook.react.bridge.UiThreadUtil; -import com.facebook.react.config.ReactFeatureFlags; import com.facebook.react.touch.ReactHitSlopView; import com.facebook.react.uimanager.common.ViewUtil; import java.util.ArrayList; @@ -192,7 +191,6 @@ private static View findTouchTargetView( // If the touch point is outside of the overflowinset for the view, we can safely ignore // it. if (ViewUtil.getUIManagerType(view.getId()) == FABRIC - && ReactFeatureFlags.useOverflowInset && !isTouchPointInViewWithOverflowInset(eventCoords[0], eventCoords[1], view)) { return null; } diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.java index 53cc9783421917..3f76fa7dd3d9b1 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.java @@ -135,6 +135,9 @@ public class ViewProps { public static final String BORDER_RIGHT_COLOR = "borderRightColor"; public static final String BORDER_TOP_COLOR = "borderTopColor"; public static final String BORDER_BOTTOM_COLOR = "borderBottomColor"; + public static final String BORDER_BLOCK_COLOR = "borderBlockColor"; + public static final String BORDER_BLOCK_END_COLOR = "borderBlockEndColor"; + public static final String BORDER_BLOCK_START_COLOR = "borderBlockStartColor"; public static final String BORDER_TOP_START_RADIUS = "borderTopStartRadius"; public static final String BORDER_TOP_END_RADIUS = "borderTopEndRadius"; public static final String BORDER_BOTTOM_START_RADIUS = "borderBottomStartRadius"; @@ -299,6 +302,15 @@ public static boolean isLayoutOnly(ReadableMap map, String prop) { case BORDER_BOTTOM_COLOR: return map.getType(BORDER_BOTTOM_COLOR) == ReadableType.Number && map.getInt(BORDER_BOTTOM_COLOR) == Color.TRANSPARENT; + case BORDER_BLOCK_COLOR: + return map.getType(BORDER_BLOCK_COLOR) == ReadableType.Number + && map.getInt(BORDER_BLOCK_COLOR) == Color.TRANSPARENT; + case BORDER_BLOCK_END_COLOR: + return map.getType(BORDER_BLOCK_END_COLOR) == ReadableType.Number + && map.getInt(BORDER_BLOCK_END_COLOR) == Color.TRANSPARENT; + case BORDER_BLOCK_START_COLOR: + return map.getType(BORDER_BLOCK_START_COLOR) == ReadableType.Number + && map.getInt(BORDER_BLOCK_START_COLOR) == Color.TRANSPARENT; case BORDER_WIDTH: return map.isNull(BORDER_WIDTH) || map.getDouble(BORDER_WIDTH) == 0d; case BORDER_LEFT_WIDTH: diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.java b/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.java index 9f408a7668c18f..8c401a3544f1e0 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.java @@ -534,7 +534,7 @@ private ThemedReactContext getReactContext() { public boolean onInterceptTouchEvent(MotionEvent event) { mJSTouchDispatcher.handleTouchEvent(event, mEventDispatcher); if (mJSPointerDispatcher != null) { - mJSPointerDispatcher.handleMotionEvent(event, mEventDispatcher); + mJSPointerDispatcher.handleMotionEvent(event, mEventDispatcher, true); } return super.onInterceptTouchEvent(event); } @@ -543,7 +543,7 @@ public boolean onInterceptTouchEvent(MotionEvent event) { public boolean onTouchEvent(MotionEvent event) { mJSTouchDispatcher.handleTouchEvent(event, mEventDispatcher); if (mJSPointerDispatcher != null) { - mJSPointerDispatcher.handleMotionEvent(event, mEventDispatcher); + mJSPointerDispatcher.handleMotionEvent(event, mEventDispatcher, false); } super.onTouchEvent(event); // In case when there is no children interested in handling touch event, we return true from @@ -554,7 +554,7 @@ public boolean onTouchEvent(MotionEvent event) { @Override public boolean onInterceptHoverEvent(MotionEvent event) { if (mJSPointerDispatcher != null) { - mJSPointerDispatcher.handleMotionEvent(event, mEventDispatcher); + mJSPointerDispatcher.handleMotionEvent(event, mEventDispatcher, true); } return super.onHoverEvent(event); } @@ -562,7 +562,7 @@ public boolean onInterceptHoverEvent(MotionEvent event) { @Override public boolean onHoverEvent(MotionEvent event) { if (mJSPointerDispatcher != null) { - mJSPointerDispatcher.handleMotionEvent(event, mEventDispatcher); + mJSPointerDispatcher.handleMotionEvent(event, mEventDispatcher, false); } return super.onHoverEvent(event); } 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 5f734256571277..c5271853b4d09c 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 @@ -356,14 +356,17 @@ protected void onLayout(boolean changed, int l, int t, int r, int b) { mScrollXAfterMeasure = NO_SCROLL_POSITION; } - // Call with the present values in order to re-layout if necessary - // If a "pending" value has been set, we restore that value. - // That value gets cleared by reactScrollTo. - int scrollToX = - pendingContentOffsetX != UNSET_CONTENT_OFFSET ? pendingContentOffsetX : getScrollX(); - int scrollToY = - pendingContentOffsetY != UNSET_CONTENT_OFFSET ? pendingContentOffsetY : getScrollY(); - scrollTo(scrollToX, scrollToY); + // Apply pending contentOffset in case it was set before the view was laid out. + if (isContentReady()) { + // If a "pending" content offset value has been set, we restore that value. + // Upon call to scrollTo, the "pending" values will be re-set. + int scrollToX = + pendingContentOffsetX != UNSET_CONTENT_OFFSET ? pendingContentOffsetX : getScrollX(); + int scrollToY = + pendingContentOffsetY != UNSET_CONTENT_OFFSET ? pendingContentOffsetY : getScrollY(); + scrollTo(scrollToX, scrollToY); + } + ReactScrollViewHelper.emitLayoutEvent(this); } 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 7a619882dfdd14..2442f7b2013d55 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 @@ -286,14 +286,17 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { - // Call with the present values in order to re-layout if necessary - // If a "pending" content offset value has been set, we restore that value. - // Upon call to scrollTo, the "pending" values will be re-set. - int scrollToX = - pendingContentOffsetX != UNSET_CONTENT_OFFSET ? pendingContentOffsetX : getScrollX(); - int scrollToY = - pendingContentOffsetY != UNSET_CONTENT_OFFSET ? pendingContentOffsetY : getScrollY(); - scrollTo(scrollToX, scrollToY); + // Apply pending contentOffset in case it was set before the view was laid out. + if (isContentReady()) { + // If a "pending" content offset value has been set, we restore that value. + // Upon call to scrollTo, the "pending" values will be re-set. + int scrollToX = + pendingContentOffsetX != UNSET_CONTENT_OFFSET ? pendingContentOffsetX : getScrollX(); + int scrollToY = + pendingContentOffsetY != UNSET_CONTENT_OFFSET ? pendingContentOffsetY : getScrollY(); + scrollTo(scrollToX, scrollToY); + } + ReactScrollViewHelper.emitLayoutEvent(this); } @@ -1124,10 +1127,12 @@ public void onLayoutChange( mMaintainVisibleContentPositionHelper.updateScrollPosition(); } - int currentScrollY = getScrollY(); - int maxScrollY = getMaxScrollY(); - if (currentScrollY > maxScrollY) { - scrollTo(getScrollX(), maxScrollY); + if (isShown() && isContentReady()) { + int currentScrollY = getScrollY(); + int maxScrollY = getMaxScrollY(); + if (currentScrollY > maxScrollY) { + scrollTo(getScrollX(), maxScrollY); + } } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactMapBufferPropSetter.kt b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactMapBufferPropSetter.kt index 100cf1c36d3d0e..a7effcdab1752e 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactMapBufferPropSetter.kt +++ b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactMapBufferPropSetter.kt @@ -87,6 +87,9 @@ object ReactMapBufferPropSetter { private const val EDGE_START = 4 private const val EDGE_END = 5 private const val EDGE_ALL = 6 + private const val EDGE_BLOCK = 7 + private const val EDGE_BLOCK_END = 8 + private const val EDGE_BLOCK_START = 9 private const val CORNER_TOP_LEFT = 0 private const val CORNER_TOP_RIGHT = 1 @@ -349,6 +352,9 @@ object ReactMapBufferPropSetter { EDGE_BOTTOM -> 4 EDGE_START -> 5 EDGE_END -> 6 + EDGE_BLOCK -> 7 + EDGE_BLOCK_END -> 8 + EDGE_BLOCK_START -> 9 else -> throw IllegalArgumentException("Unknown key for border color: $key") } val colorValue = entry.intValue diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewBackgroundDrawable.java b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewBackgroundDrawable.java index 937abcc20bb392..eded03ee94dfb0 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewBackgroundDrawable.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewBackgroundDrawable.java @@ -359,6 +359,21 @@ private void drawRoundedBackgroundWithBorders(Canvas canvas) { int colorRight = getBorderColor(Spacing.RIGHT); int colorBottom = getBorderColor(Spacing.BOTTOM); + int colorBlock = getBorderColor(Spacing.BLOCK); + int colorBlockStart = getBorderColor(Spacing.BLOCK_START); + int colorBlockEnd = getBorderColor(Spacing.BLOCK_END); + + if (isBorderColorDefined(Spacing.BLOCK)) { + colorBottom = colorBlock; + colorTop = colorBlock; + } + if (isBorderColorDefined(Spacing.BLOCK_END)) { + colorBottom = colorBlockEnd; + } + if (isBorderColorDefined(Spacing.BLOCK_START)) { + colorTop = colorBlockStart; + } + if (borderWidth.top > 0 || borderWidth.bottom > 0 || borderWidth.left > 0 @@ -552,13 +567,19 @@ private void updatePath() { int colorRight = getBorderColor(Spacing.RIGHT); int colorBottom = getBorderColor(Spacing.BOTTOM); int borderColor = getBorderColor(Spacing.ALL); + int colorBlock = getBorderColor(Spacing.BLOCK); + int colorBlockStart = getBorderColor(Spacing.BLOCK_START); + int colorBlockEnd = getBorderColor(Spacing.BLOCK_END); // Clip border ONLY if its color is non transparent if (Color.alpha(colorLeft) != 0 && Color.alpha(colorTop) != 0 && Color.alpha(colorRight) != 0 && Color.alpha(colorBottom) != 0 - && Color.alpha(borderColor) != 0) { + && Color.alpha(borderColor) != 0 + && Color.alpha(colorBlock) != 0 + && Color.alpha(colorBlockStart) != 0 + && Color.alpha(colorBlockEnd) != 0) { mInnerClipTempRectForBorderRadius.top += borderWidth.top; mInnerClipTempRectForBorderRadius.bottom -= borderWidth.bottom; @@ -1128,6 +1149,21 @@ private void drawRectangularBackgroundWithBorders(Canvas canvas) { int colorRight = getBorderColor(Spacing.RIGHT); int colorBottom = getBorderColor(Spacing.BOTTOM); + int colorBlock = getBorderColor(Spacing.BLOCK); + int colorBlockStart = getBorderColor(Spacing.BLOCK_START); + int colorBlockEnd = getBorderColor(Spacing.BLOCK_END); + + if (isBorderColorDefined(Spacing.BLOCK)) { + colorBottom = colorBlock; + colorTop = colorBlock; + } + if (isBorderColorDefined(Spacing.BLOCK_END)) { + colorBottom = colorBlockEnd; + } + if (isBorderColorDefined(Spacing.BLOCK_START)) { + colorTop = colorBlockStart; + } + final boolean isRTL = getResolvedLayoutDirection() == View.LAYOUT_DIRECTION_RTL; int colorStart = getBorderColor(Spacing.START); int colorEnd = getBorderColor(Spacing.END); diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManager.java index 91cbdf7c3b741a..4bd81d72153b0b 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManager.java @@ -47,6 +47,9 @@ public class ReactViewManager extends ReactClippingViewManager { Spacing.BOTTOM, Spacing.START, Spacing.END, + Spacing.BLOCK, + Spacing.BLOCK_END, + Spacing.BLOCK_START }; private static final int CMD_HOTSPOT_UPDATE = 1; private static final int CMD_SET_PRESSED = 2; @@ -238,7 +241,10 @@ public void setBorderWidth(ReactViewGroup view, int index, float width) { ViewProps.BORDER_TOP_COLOR, ViewProps.BORDER_BOTTOM_COLOR, ViewProps.BORDER_START_COLOR, - ViewProps.BORDER_END_COLOR + ViewProps.BORDER_END_COLOR, + ViewProps.BORDER_BLOCK_COLOR, + ViewProps.BORDER_BLOCK_END_COLOR, + ViewProps.BORDER_BLOCK_START_COLOR }, customType = "Color") public void setBorderColor(ReactViewGroup view, int index, Integer color) { diff --git a/ReactAndroid/src/main/jni/CMakeLists.txt b/ReactAndroid/src/main/jni/CMakeLists.txt index 7bc36325b689e7..2d1295d2cc5df5 100644 --- a/ReactAndroid/src/main/jni/CMakeLists.txt +++ b/ReactAndroid/src/main/jni/CMakeLists.txt @@ -19,6 +19,9 @@ endif(CCACHE_FOUND) add_link_options(-Wl,--build-id) add_compile_options(-Wall -Werror -std=c++17) +# This exposes the check_for_circular_dependencies macro to all the submodules +include(CircularDepsValidator.cmake) + function(add_react_android_subdir relative_path) add_subdirectory(${REACT_ANDROID_DIR}/${relative_path} ReactAndroid/${relative_path}) endfunction() diff --git a/ReactAndroid/src/main/jni/CircularDepsValidator.cmake b/ReactAndroid/src/main/jni/CircularDepsValidator.cmake new file mode 100644 index 00000000000000..44f8fb93651820 --- /dev/null +++ b/ReactAndroid/src/main/jni/CircularDepsValidator.cmake @@ -0,0 +1,32 @@ +# 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. + +cmake_minimum_required(VERSION 3.13) +set(CMAKE_VERBOSE_MAKEFILE on) + +# Util function that help us verify that you're not including a header file +# which has an invalid import path. Most of the time this is causing a C++ circular dependency. +function(check_for_circular_dependencies allowed_imports_paths) + file(GLOB headers CONFIGURE_DEPENDS *.h) + foreach(file ${headers}) + file(STRINGS ${file} header_file) + while(header_file) + list(POP_FRONT header_file line) + if (line MATCHES "^#include &config, global_ref &javaUIManager) : javaUIManager_(javaUIManager), - useOverflowInset_(getFeatureFlagValue("useOverflowInset")) { + reduceDeleteCreateMutation_( + getFeatureFlagValue("reduceDeleteCreateMutation")) { CoreFeatures::enableMapBuffer = getFeatureFlagValue("useMapBufferProps"); } @@ -314,9 +315,33 @@ void FabricMountingManager::executeMount( bool isVirtual = mutation.mutatedViewIsVirtual(); switch (mutationType) { case ShadowViewMutation::Create: { - bool allocationCheck = + bool shouldCreateView = !allocatedViewTags.contains(newChildShadowView.tag); - bool shouldCreateView = allocationCheck; + if (reduceDeleteCreateMutation_) { + // Detect DELETE...CREATE situation on the same node and do NOT push + // back to the mount items. This is an edge case that may happen + // when for example animation runs while commit happened, and we + // want to filter them out here to capture all possible sources of + // such mutations. The re-ordering logic here assumes no + // DELETE...CREATE in the mutations, as we will re-order mutations + // and batch all DELETE instructions in the end. + auto it = std::remove_if( + cppDeleteMountItems.begin(), + cppDeleteMountItems.end(), + [&](auto &deletedMountItem) -> bool { + return deletedMountItem.oldChildShadowView.tag == + newChildShadowView.tag; + }); + bool hasDeletedViewsWithSameTag = it != cppDeleteMountItems.end(); + cppDeleteMountItems.erase(it, cppDeleteMountItems.end()); + + if (hasDeletedViewsWithSameTag) { + shouldCreateView = false; + LOG(ERROR) + << "XIN: Detect DELETE...CREATE on the same tag from mutations in the same batch. The DELETE and CREATE mutations are removed before sending to the native platforms"; + } + } + if (shouldCreateView) { cppCommonMountItems.push_back( CppMountItem::CreateMountItem(newChildShadowView)); @@ -378,8 +403,7 @@ void FabricMountingManager::executeMount( // children of the current view. The layout of current view may not // change, and we separate this part from layout mount items to not // pack too much data there. - if (useOverflowInset_ && - (oldChildShadowView.layoutMetrics.overflowInset != + if ((oldChildShadowView.layoutMetrics.overflowInset != newChildShadowView.layoutMetrics.overflowInset)) { cppUpdateOverflowInsetMountItems.push_back( CppMountItem::UpdateOverflowInsetMountItem( @@ -435,9 +459,8 @@ void FabricMountingManager::executeMount( // children of the current view. The layout of current view may not // change, and we separate this part from layout mount items to not // pack too much data there. - if (useOverflowInset_ && - newChildShadowView.layoutMetrics.overflowInset != - EdgeInsets::ZERO) { + if (newChildShadowView.layoutMetrics.overflowInset != + EdgeInsets::ZERO) { cppUpdateOverflowInsetMountItems.push_back( CppMountItem::UpdateOverflowInsetMountItem( newChildShadowView)); diff --git a/ReactAndroid/src/main/jni/react/fabric/FabricMountingManager.h b/ReactAndroid/src/main/jni/react/fabric/FabricMountingManager.h index 57e9eff06a6244..c098e661b66632 100644 --- a/ReactAndroid/src/main/jni/react/fabric/FabricMountingManager.h +++ b/ReactAndroid/src/main/jni/react/fabric/FabricMountingManager.h @@ -69,7 +69,7 @@ class FabricMountingManager final { butter::map> allocatedViewRegistry_{}; std::recursive_mutex allocatedViewsMutex_; - bool const useOverflowInset_{false}; + bool const reduceDeleteCreateMutation_{false}; jni::local_ref getProps( ShadowView const &oldShadowView, diff --git a/ReactAndroid/src/main/jni/react/jscexecutor/CMakeLists.txt b/ReactAndroid/src/main/jni/react/jscexecutor/CMakeLists.txt index 464aa19ccef868..67858803b3cff7 100644 --- a/ReactAndroid/src/main/jni/react/jscexecutor/CMakeLists.txt +++ b/ReactAndroid/src/main/jni/react/jscexecutor/CMakeLists.txt @@ -13,9 +13,22 @@ add_library(jscexecutor SHARED ${jscexecutor_SRC}) target_include_directories(jscexecutor PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) +# Patch from Expo: https://github.com/expo/react-native/blob/02714ab44d1e206fa80e81aef618e61017cccdc1/ReactAndroid/src/main/java/com/facebook/react/jscexecutor/CMakeLists.txt#L16-L25 +# Explicitly link libgcc.a to prevent undefined `_Unwind_Resume` symbol and crash from throwing c++ exceptions even someone tries to catch the exceptions. +# according to https://android.googlesource.com/platform/ndk/+/master/docs/BuildSystemMaintainers.md#unwinding, +# we should put the unwinder between static libs and shared libs. +# +# TODO(ncor): we don't need this patch anymore after upgrading to ndk r23 +if(ANDROID_NDK_REVISION VERSION_LESS "23.0.0") + set(LIB_UNWIND gcc) +else() + set(LIB_UNWIND unwind) +endif() + target_link_libraries(jscexecutor jsireact jscruntime + ${LIB_UNWIND} fb fbjni folly_runtime diff --git a/ReactCommon/ReactCommon.podspec b/ReactCommon/ReactCommon.podspec index 39701310f6af11..da424368772a11 100644 --- a/ReactCommon/ReactCommon.podspec +++ b/ReactCommon/ReactCommon.podspec @@ -19,7 +19,7 @@ end folly_compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -Wno-comma -Wno-shorten-64-to-32 -Wno-gnu-zero-variadic-macro-arguments' folly_version = '2021.07.22.00' boost_compiler_flags = '-Wno-documentation' - +using_hermes = ENV['USE_HERMES'] == nil || ENV['USE_HERMES'] == "1" Pod::Spec.new do |s| s.name = "ReactCommon" s.module_name = "ReactCommon" @@ -49,6 +49,9 @@ Pod::Spec.new do |s| s.dependency "React-logger", version ss.dependency "DoubleConversion" ss.dependency "glog" + if using_hermes + ss.dependency "hermes-engine" + end ss.subspec "bridging" do |sss| sss.dependency "React-jsi", version @@ -56,6 +59,9 @@ Pod::Spec.new do |s| sss.exclude_files = "react/bridging/tests" sss.header_dir = "react/bridging" sss.pod_target_xcconfig = { "HEADER_SEARCH_PATHS" => "\"$(PODS_TARGET_SRCROOT)/ReactCommon\" \"$(PODS_ROOT)/RCT-Folly\"" } + if using_hermes + sss.dependency "hermes-engine" + end end ss.subspec "core" do |sss| diff --git a/ReactCommon/cxxreact/React-cxxreact.podspec b/ReactCommon/cxxreact/React-cxxreact.podspec index a2c66cf7eb5c4b..26747a5b69fd1f 100644 --- a/ReactCommon/cxxreact/React-cxxreact.podspec +++ b/ReactCommon/cxxreact/React-cxxreact.podspec @@ -47,4 +47,8 @@ Pod::Spec.new do |s| s.dependency "React-perflogger", version s.dependency "React-jsi", version s.dependency "React-logger", version + + if ENV['USE_HERMES'] == nil || ENV['USE_HERMES'] == "1" + s.dependency 'hermes-engine' + end end diff --git a/ReactCommon/hermes/React-hermes.podspec b/ReactCommon/hermes/React-hermes.podspec index 96bb1d0e152f62..425ef3c84c4005 100644 --- a/ReactCommon/hermes/React-hermes.podspec +++ b/ReactCommon/hermes/React-hermes.podspec @@ -53,4 +53,5 @@ Pod::Spec.new do |s| s.dependency "glog" s.dependency "RCT-Folly/Futures", folly_version s.dependency "hermes-engine" + s.dependency "React-jsi" end diff --git a/ReactCommon/jsiexecutor/React-jsiexecutor.podspec b/ReactCommon/jsiexecutor/React-jsiexecutor.podspec index 23a29b9ff45614..e97969d5e846bf 100644 --- a/ReactCommon/jsiexecutor/React-jsiexecutor.podspec +++ b/ReactCommon/jsiexecutor/React-jsiexecutor.podspec @@ -41,4 +41,8 @@ Pod::Spec.new do |s| s.dependency "RCT-Folly", folly_version s.dependency "DoubleConversion" s.dependency "glog" + + if ENV['USE_HERMES'] == nil || ENV['USE_HERMES'] == "1" + s.dependency 'hermes-engine' + end end diff --git a/ReactCommon/react/renderer/components/image/ImageProps.cpp b/ReactCommon/react/renderer/components/image/ImageProps.cpp index 7feac6300f8b17..5598746faa9f85 100644 --- a/ReactCommon/react/renderer/components/image/ImageProps.cpp +++ b/ReactCommon/react/renderer/components/image/ImageProps.cpp @@ -87,14 +87,16 @@ void ImageProps::setProp( // reuse the same values. ViewProps::setProp(context, hash, propName, value); + static auto defaults = ImageProps{}; + switch (hash) { - RAW_SET_PROP_SWITCH_CASE(sources, "source", {}); - RAW_SET_PROP_SWITCH_CASE(defaultSources, "defaultSource", {}); - RAW_SET_PROP_SWITCH_CASE_BASIC(resizeMode, ImageResizeMode::Stretch); - RAW_SET_PROP_SWITCH_CASE_BASIC(blurRadius, {}); - RAW_SET_PROP_SWITCH_CASE_BASIC(capInsets, {}); - RAW_SET_PROP_SWITCH_CASE_BASIC(tintColor, {}); - RAW_SET_PROP_SWITCH_CASE_BASIC(internal_analyticTag, {}); + RAW_SET_PROP_SWITCH_CASE(sources, "source"); + RAW_SET_PROP_SWITCH_CASE(defaultSources, "defaultSource"); + RAW_SET_PROP_SWITCH_CASE_BASIC(resizeMode); + RAW_SET_PROP_SWITCH_CASE_BASIC(blurRadius); + RAW_SET_PROP_SWITCH_CASE_BASIC(capInsets); + RAW_SET_PROP_SWITCH_CASE_BASIC(tintColor); + RAW_SET_PROP_SWITCH_CASE_BASIC(internal_analyticTag); } } diff --git a/ReactCommon/react/renderer/components/scrollview/ScrollViewProps.cpp b/ReactCommon/react/renderer/components/scrollview/ScrollViewProps.cpp index 4eff278fdfc1f7..4f0d53929c9602 100644 --- a/ReactCommon/react/renderer/components/scrollview/ScrollViewProps.cpp +++ b/ReactCommon/react/renderer/components/scrollview/ScrollViewProps.cpp @@ -322,42 +322,42 @@ void ScrollViewProps::setProp( // reuse the same values. ViewProps::setProp(context, hash, propName, value); + static auto defaults = ScrollViewProps{}; + switch (hash) { - RAW_SET_PROP_SWITCH_CASE_BASIC(alwaysBounceHorizontal, {}); - RAW_SET_PROP_SWITCH_CASE_BASIC(alwaysBounceVertical, {}); - RAW_SET_PROP_SWITCH_CASE_BASIC(bounces, true); - RAW_SET_PROP_SWITCH_CASE_BASIC(bouncesZoom, true); - RAW_SET_PROP_SWITCH_CASE_BASIC(canCancelContentTouches, true); - RAW_SET_PROP_SWITCH_CASE_BASIC(centerContent, {}); - RAW_SET_PROP_SWITCH_CASE_BASIC(automaticallyAdjustContentInsets, {}); - RAW_SET_PROP_SWITCH_CASE_BASIC( - automaticallyAdjustsScrollIndicatorInsets, true); - RAW_SET_PROP_SWITCH_CASE_BASIC(decelerationRate, (Float)0.998); - RAW_SET_PROP_SWITCH_CASE_BASIC(directionalLockEnabled, {}); - RAW_SET_PROP_SWITCH_CASE_BASIC(indicatorStyle, {}); - RAW_SET_PROP_SWITCH_CASE_BASIC(keyboardDismissMode, {}); - RAW_SET_PROP_SWITCH_CASE_BASIC(maximumZoomScale, (Float)1.0); - RAW_SET_PROP_SWITCH_CASE_BASIC(minimumZoomScale, (Float)1.0); - RAW_SET_PROP_SWITCH_CASE_BASIC(scrollEnabled, true); - RAW_SET_PROP_SWITCH_CASE_BASIC(pagingEnabled, {}); - RAW_SET_PROP_SWITCH_CASE_BASIC(pinchGestureEnabled, true); - RAW_SET_PROP_SWITCH_CASE_BASIC(scrollsToTop, true); - RAW_SET_PROP_SWITCH_CASE_BASIC(showsHorizontalScrollIndicator, true); - RAW_SET_PROP_SWITCH_CASE_BASIC(showsVerticalScrollIndicator, true); - RAW_SET_PROP_SWITCH_CASE_BASIC(scrollEventThrottle, {}); - RAW_SET_PROP_SWITCH_CASE_BASIC(zoomScale, (Float)1.0); - RAW_SET_PROP_SWITCH_CASE_BASIC(contentInset, {}); - RAW_SET_PROP_SWITCH_CASE_BASIC(contentOffset, {}); - RAW_SET_PROP_SWITCH_CASE_BASIC(scrollIndicatorInsets, {}); - RAW_SET_PROP_SWITCH_CASE_BASIC(snapToInterval, {}); - RAW_SET_PROP_SWITCH_CASE_BASIC(snapToAlignment, {}); - RAW_SET_PROP_SWITCH_CASE_BASIC(disableIntervalMomentum, {}); - RAW_SET_PROP_SWITCH_CASE_BASIC(snapToOffsets, {}); - RAW_SET_PROP_SWITCH_CASE_BASIC(snapToStart, true); - RAW_SET_PROP_SWITCH_CASE_BASIC(snapToEnd, true); - RAW_SET_PROP_SWITCH_CASE_BASIC( - contentInsetAdjustmentBehavior, ContentInsetAdjustmentBehavior::Never); - RAW_SET_PROP_SWITCH_CASE_BASIC(scrollToOverflowEnabled, {}); + RAW_SET_PROP_SWITCH_CASE_BASIC(alwaysBounceHorizontal); + RAW_SET_PROP_SWITCH_CASE_BASIC(alwaysBounceVertical); + RAW_SET_PROP_SWITCH_CASE_BASIC(bounces); + RAW_SET_PROP_SWITCH_CASE_BASIC(bouncesZoom); + RAW_SET_PROP_SWITCH_CASE_BASIC(canCancelContentTouches); + RAW_SET_PROP_SWITCH_CASE_BASIC(centerContent); + RAW_SET_PROP_SWITCH_CASE_BASIC(automaticallyAdjustContentInsets); + RAW_SET_PROP_SWITCH_CASE_BASIC(automaticallyAdjustsScrollIndicatorInsets); + RAW_SET_PROP_SWITCH_CASE_BASIC(decelerationRate); + RAW_SET_PROP_SWITCH_CASE_BASIC(directionalLockEnabled); + RAW_SET_PROP_SWITCH_CASE_BASIC(indicatorStyle); + RAW_SET_PROP_SWITCH_CASE_BASIC(keyboardDismissMode); + RAW_SET_PROP_SWITCH_CASE_BASIC(maximumZoomScale); + RAW_SET_PROP_SWITCH_CASE_BASIC(minimumZoomScale); + RAW_SET_PROP_SWITCH_CASE_BASIC(scrollEnabled); + RAW_SET_PROP_SWITCH_CASE_BASIC(pagingEnabled); + RAW_SET_PROP_SWITCH_CASE_BASIC(pinchGestureEnabled); + RAW_SET_PROP_SWITCH_CASE_BASIC(scrollsToTop); + RAW_SET_PROP_SWITCH_CASE_BASIC(showsHorizontalScrollIndicator); + RAW_SET_PROP_SWITCH_CASE_BASIC(showsVerticalScrollIndicator); + RAW_SET_PROP_SWITCH_CASE_BASIC(scrollEventThrottle); + RAW_SET_PROP_SWITCH_CASE_BASIC(zoomScale); + RAW_SET_PROP_SWITCH_CASE_BASIC(contentInset); + RAW_SET_PROP_SWITCH_CASE_BASIC(contentOffset); + RAW_SET_PROP_SWITCH_CASE_BASIC(scrollIndicatorInsets); + RAW_SET_PROP_SWITCH_CASE_BASIC(snapToInterval); + RAW_SET_PROP_SWITCH_CASE_BASIC(snapToAlignment); + RAW_SET_PROP_SWITCH_CASE_BASIC(disableIntervalMomentum); + RAW_SET_PROP_SWITCH_CASE_BASIC(snapToOffsets); + RAW_SET_PROP_SWITCH_CASE_BASIC(snapToStart); + RAW_SET_PROP_SWITCH_CASE_BASIC(snapToEnd); + RAW_SET_PROP_SWITCH_CASE_BASIC(contentInsetAdjustmentBehavior); + RAW_SET_PROP_SWITCH_CASE_BASIC(scrollToOverflowEnabled); } } diff --git a/ReactCommon/react/renderer/components/text/ParagraphProps.cpp b/ReactCommon/react/renderer/components/text/ParagraphProps.cpp index c666e5e2d86ad4..242567dc4b6e63 100644 --- a/ReactCommon/react/renderer/components/text/ParagraphProps.cpp +++ b/ReactCommon/react/renderer/components/text/ParagraphProps.cpp @@ -66,6 +66,8 @@ void ParagraphProps::setProp( ViewProps::setProp(context, hash, propName, value); BaseTextProps::setProp(context, hash, propName, value); + static auto defaults = ParagraphProps{}; + // ParagraphAttributes has its own switch statement - to keep all // of these fields together, and because there are some collisions between // propnames parsed here and outside of ParagraphAttributes. @@ -119,8 +121,8 @@ void ParagraphProps::setProp( } switch (hash) { - RAW_SET_PROP_SWITCH_CASE_BASIC(isSelectable, false); - RAW_SET_PROP_SWITCH_CASE_BASIC(onTextLayout, {}); + RAW_SET_PROP_SWITCH_CASE_BASIC(isSelectable); + RAW_SET_PROP_SWITCH_CASE_BASIC(onTextLayout); } /* 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 c8eaf160ba1ca3..8c0900480c4c54 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 @@ -269,6 +269,8 @@ void AndroidTextInputProps::setProp( ViewProps::setProp(context, hash, propName, value); BaseTextProps::setProp(context, hash, propName, value); + static auto defaults = AndroidTextInputProps{}; + // ParagraphAttributes has its own switch statement - to keep all // of these fields together, and because there are some collisions between // propnames parsed here and outside of ParagraphAttributes. For example, @@ -323,55 +325,59 @@ void AndroidTextInputProps::setProp( } switch (hash) { - RAW_SET_PROP_SWITCH_CASE_BASIC(autoComplete, {}); - RAW_SET_PROP_SWITCH_CASE_BASIC(returnKeyLabel, {}); - RAW_SET_PROP_SWITCH_CASE_BASIC(numberOfLines, 0); - RAW_SET_PROP_SWITCH_CASE_BASIC(disableFullscreenUI, false); - RAW_SET_PROP_SWITCH_CASE_BASIC(textBreakStrategy, {}); - RAW_SET_PROP_SWITCH_CASE_BASIC(underlineColorAndroid, {}); - RAW_SET_PROP_SWITCH_CASE_BASIC(inlineImageLeft, {}); - RAW_SET_PROP_SWITCH_CASE_BASIC(inlineImagePadding, 0); - RAW_SET_PROP_SWITCH_CASE_BASIC(importantForAutofill, {}); - RAW_SET_PROP_SWITCH_CASE_BASIC(showSoftInputOnFocus, false); - RAW_SET_PROP_SWITCH_CASE_BASIC(autoCapitalize, {}); - RAW_SET_PROP_SWITCH_CASE_BASIC(autoCorrect, false); - RAW_SET_PROP_SWITCH_CASE_BASIC(autoFocus, false); - RAW_SET_PROP_SWITCH_CASE_BASIC(allowFontScaling, false); - RAW_SET_PROP_SWITCH_CASE_BASIC(maxFontSizeMultiplier, (Float)0.0); - RAW_SET_PROP_SWITCH_CASE_BASIC(editable, false); - RAW_SET_PROP_SWITCH_CASE_BASIC(keyboardType, {}); - RAW_SET_PROP_SWITCH_CASE_BASIC(returnKeyType, {}); - RAW_SET_PROP_SWITCH_CASE_BASIC(maxLength, 0); - RAW_SET_PROP_SWITCH_CASE_BASIC(multiline, false); - RAW_SET_PROP_SWITCH_CASE_BASIC(placeholder, {}); - RAW_SET_PROP_SWITCH_CASE_BASIC(placeholderTextColor, {}); - RAW_SET_PROP_SWITCH_CASE_BASIC(secureTextEntry, false); - RAW_SET_PROP_SWITCH_CASE_BASIC(selectionColor, {}); - RAW_SET_PROP_SWITCH_CASE_BASIC(selection, {}); - RAW_SET_PROP_SWITCH_CASE_BASIC(this->value, {}); - RAW_SET_PROP_SWITCH_CASE_BASIC(defaultValue, {}); - RAW_SET_PROP_SWITCH_CASE_BASIC(selectTextOnFocus, false); - RAW_SET_PROP_SWITCH_CASE_BASIC(submitBehavior, {}); - RAW_SET_PROP_SWITCH_CASE_BASIC(caretHidden, false); - RAW_SET_PROP_SWITCH_CASE_BASIC(contextMenuHidden, false); - RAW_SET_PROP_SWITCH_CASE_BASIC(textShadowColor, {}); - RAW_SET_PROP_SWITCH_CASE_BASIC(textShadowRadius, (Float)0.0); - RAW_SET_PROP_SWITCH_CASE_BASIC(textDecorationLine, {}); - RAW_SET_PROP_SWITCH_CASE_BASIC(fontStyle, {}); - RAW_SET_PROP_SWITCH_CASE_BASIC(textShadowOffset, {}); - RAW_SET_PROP_SWITCH_CASE_BASIC(lineHeight, (Float)0.0); - RAW_SET_PROP_SWITCH_CASE_BASIC(textTransform, {}); - // RAW_SET_PROP_SWITCH_CASE_BASIC(color, {0}); // currently not being parsed - RAW_SET_PROP_SWITCH_CASE_BASIC(letterSpacing, (Float)0.0); - RAW_SET_PROP_SWITCH_CASE_BASIC(fontSize, (Float)0.0); - RAW_SET_PROP_SWITCH_CASE_BASIC(textAlign, {}); - RAW_SET_PROP_SWITCH_CASE_BASIC(includeFontPadding, false); - RAW_SET_PROP_SWITCH_CASE_BASIC(fontWeight, {}); - RAW_SET_PROP_SWITCH_CASE_BASIC(fontFamily, {}); - RAW_SET_PROP_SWITCH_CASE_BASIC(textAlignVertical, {}); - RAW_SET_PROP_SWITCH_CASE_BASIC(cursorColor, {}); - RAW_SET_PROP_SWITCH_CASE_BASIC(mostRecentEventCount, 0); - RAW_SET_PROP_SWITCH_CASE_BASIC(text, {}); + RAW_SET_PROP_SWITCH_CASE_BASIC(autoComplete); + RAW_SET_PROP_SWITCH_CASE_BASIC(returnKeyLabel); + RAW_SET_PROP_SWITCH_CASE_BASIC(numberOfLines); + RAW_SET_PROP_SWITCH_CASE_BASIC(disableFullscreenUI); + RAW_SET_PROP_SWITCH_CASE_BASIC(textBreakStrategy); + RAW_SET_PROP_SWITCH_CASE_BASIC(underlineColorAndroid); + RAW_SET_PROP_SWITCH_CASE_BASIC(inlineImageLeft); + RAW_SET_PROP_SWITCH_CASE_BASIC(inlineImagePadding); + RAW_SET_PROP_SWITCH_CASE_BASIC(importantForAutofill); + RAW_SET_PROP_SWITCH_CASE_BASIC(showSoftInputOnFocus); + RAW_SET_PROP_SWITCH_CASE_BASIC(autoCapitalize); + RAW_SET_PROP_SWITCH_CASE_BASIC(autoCorrect); + RAW_SET_PROP_SWITCH_CASE_BASIC(autoFocus); + RAW_SET_PROP_SWITCH_CASE_BASIC(allowFontScaling); + RAW_SET_PROP_SWITCH_CASE_BASIC(maxFontSizeMultiplier); + RAW_SET_PROP_SWITCH_CASE_BASIC(editable); + RAW_SET_PROP_SWITCH_CASE_BASIC(keyboardType); + RAW_SET_PROP_SWITCH_CASE_BASIC(returnKeyType); + RAW_SET_PROP_SWITCH_CASE_BASIC(maxLength); + RAW_SET_PROP_SWITCH_CASE_BASIC(multiline); + RAW_SET_PROP_SWITCH_CASE_BASIC(placeholder); + RAW_SET_PROP_SWITCH_CASE_BASIC(placeholderTextColor); + RAW_SET_PROP_SWITCH_CASE_BASIC(secureTextEntry); + RAW_SET_PROP_SWITCH_CASE_BASIC(selectionColor); + RAW_SET_PROP_SWITCH_CASE_BASIC(selection); + RAW_SET_PROP_SWITCH_CASE_BASIC(defaultValue); + RAW_SET_PROP_SWITCH_CASE_BASIC(selectTextOnFocus); + RAW_SET_PROP_SWITCH_CASE_BASIC(submitBehavior); + RAW_SET_PROP_SWITCH_CASE_BASIC(caretHidden); + RAW_SET_PROP_SWITCH_CASE_BASIC(contextMenuHidden); + RAW_SET_PROP_SWITCH_CASE_BASIC(textShadowColor); + RAW_SET_PROP_SWITCH_CASE_BASIC(textShadowRadius); + RAW_SET_PROP_SWITCH_CASE_BASIC(textDecorationLine); + RAW_SET_PROP_SWITCH_CASE_BASIC(fontStyle); + RAW_SET_PROP_SWITCH_CASE_BASIC(textShadowOffset); + RAW_SET_PROP_SWITCH_CASE_BASIC(lineHeight); + RAW_SET_PROP_SWITCH_CASE_BASIC(textTransform); + // RAW_SET_PROP_SWITCH_CASE_BASIC(color); + RAW_SET_PROP_SWITCH_CASE_BASIC(letterSpacing); + RAW_SET_PROP_SWITCH_CASE_BASIC(fontSize); + RAW_SET_PROP_SWITCH_CASE_BASIC(textAlign); + RAW_SET_PROP_SWITCH_CASE_BASIC(includeFontPadding); + RAW_SET_PROP_SWITCH_CASE_BASIC(fontWeight); + RAW_SET_PROP_SWITCH_CASE_BASIC(fontFamily); + RAW_SET_PROP_SWITCH_CASE_BASIC(textAlignVertical); + RAW_SET_PROP_SWITCH_CASE_BASIC(cursorColor); + RAW_SET_PROP_SWITCH_CASE_BASIC(mostRecentEventCount); + RAW_SET_PROP_SWITCH_CASE_BASIC(text); + + case CONSTEXPR_RAW_PROPS_KEY_HASH("value"): { + fromRawValue(context, value, this->value, {}); + return; + } // Paddings are not parsed at this level of the component (they're parsed in // ViewProps) but we do need to know if they're present or not. See diff --git a/ReactCommon/react/renderer/components/view/AccessibilityProps.cpp b/ReactCommon/react/renderer/components/view/AccessibilityProps.cpp index 8ee8640c189478..2e87d5d34f082a 100644 --- a/ReactCommon/react/renderer/components/view/AccessibilityProps.cpp +++ b/ReactCommon/react/renderer/components/view/AccessibilityProps.cpp @@ -208,25 +208,26 @@ void AccessibilityProps::setProp( RawPropsPropNameHash hash, const char * /*propName*/, RawValue const &value) { + static auto defaults = AccessibilityProps{}; + switch (hash) { - RAW_SET_PROP_SWITCH_CASE_BASIC(accessible, false); - RAW_SET_PROP_SWITCH_CASE_BASIC(accessibilityState, {}); - RAW_SET_PROP_SWITCH_CASE_BASIC(accessibilityLabel, std::string{""}); - RAW_SET_PROP_SWITCH_CASE_BASIC(accessibilityLabelledBy, {}); - RAW_SET_PROP_SWITCH_CASE_BASIC(accessibilityHint, std::string{""}); - RAW_SET_PROP_SWITCH_CASE_BASIC(accessibilityLanguage, std::string{""}); - RAW_SET_PROP_SWITCH_CASE_BASIC(accessibilityValue, {}); - RAW_SET_PROP_SWITCH_CASE_BASIC(accessibilityActions, {}); - RAW_SET_PROP_SWITCH_CASE_BASIC(accessibilityViewIsModal, false); - RAW_SET_PROP_SWITCH_CASE_BASIC(accessibilityElementsHidden, false); - RAW_SET_PROP_SWITCH_CASE_BASIC(accessibilityIgnoresInvertColors, false); - RAW_SET_PROP_SWITCH_CASE_BASIC(onAccessibilityTap, {}); - RAW_SET_PROP_SWITCH_CASE_BASIC(onAccessibilityMagicTap, {}); - RAW_SET_PROP_SWITCH_CASE_BASIC(onAccessibilityEscape, {}); - RAW_SET_PROP_SWITCH_CASE_BASIC(onAccessibilityAction, {}); - RAW_SET_PROP_SWITCH_CASE_BASIC( - importantForAccessibility, ImportantForAccessibility::Auto); - RAW_SET_PROP_SWITCH_CASE(testId, "testID", std::string{""}); + RAW_SET_PROP_SWITCH_CASE_BASIC(accessible); + RAW_SET_PROP_SWITCH_CASE_BASIC(accessibilityState); + RAW_SET_PROP_SWITCH_CASE_BASIC(accessibilityLabel); + RAW_SET_PROP_SWITCH_CASE_BASIC(accessibilityLabelledBy); + RAW_SET_PROP_SWITCH_CASE_BASIC(accessibilityHint); + RAW_SET_PROP_SWITCH_CASE_BASIC(accessibilityLanguage); + RAW_SET_PROP_SWITCH_CASE_BASIC(accessibilityValue); + RAW_SET_PROP_SWITCH_CASE_BASIC(accessibilityActions); + RAW_SET_PROP_SWITCH_CASE_BASIC(accessibilityViewIsModal); + RAW_SET_PROP_SWITCH_CASE_BASIC(accessibilityElementsHidden); + RAW_SET_PROP_SWITCH_CASE_BASIC(accessibilityIgnoresInvertColors); + RAW_SET_PROP_SWITCH_CASE_BASIC(onAccessibilityTap); + RAW_SET_PROP_SWITCH_CASE_BASIC(onAccessibilityMagicTap); + RAW_SET_PROP_SWITCH_CASE_BASIC(onAccessibilityEscape); + RAW_SET_PROP_SWITCH_CASE_BASIC(onAccessibilityAction); + RAW_SET_PROP_SWITCH_CASE_BASIC(importantForAccessibility); + RAW_SET_PROP_SWITCH_CASE(testId, "testID"); case CONSTEXPR_RAW_PROPS_KEY_HASH("accessibilityRole"): { AccessibilityTraits traits = AccessibilityTraits::None; std::string roleString; diff --git a/ReactCommon/react/renderer/components/view/ViewProps.cpp b/ReactCommon/react/renderer/components/view/ViewProps.cpp index f8294e40b70fcf..f97a0560f61dd5 100644 --- a/ReactCommon/react/renderer/components/view/ViewProps.cpp +++ b/ReactCommon/react/renderer/components/view/ViewProps.cpp @@ -291,23 +291,25 @@ void ViewProps::setProp( YogaStylableProps::setProp(context, hash, propName, value); AccessibilityProps::setProp(context, hash, propName, value); + static auto defaults = ViewProps{}; + switch (hash) { - RAW_SET_PROP_SWITCH_CASE_BASIC(opacity, (Float)1.0); - RAW_SET_PROP_SWITCH_CASE_BASIC(foregroundColor, {}); - RAW_SET_PROP_SWITCH_CASE_BASIC(backgroundColor, {}); - RAW_SET_PROP_SWITCH_CASE_BASIC(shadowColor, {}); - RAW_SET_PROP_SWITCH_CASE_BASIC(shadowOffset, {}); - RAW_SET_PROP_SWITCH_CASE_BASIC(shadowOpacity, {}); - RAW_SET_PROP_SWITCH_CASE_BASIC(shadowRadius, {}); - RAW_SET_PROP_SWITCH_CASE_BASIC(transform, {}); - RAW_SET_PROP_SWITCH_CASE_BASIC(backfaceVisibility, {}); - RAW_SET_PROP_SWITCH_CASE_BASIC(shouldRasterize, {}); - RAW_SET_PROP_SWITCH_CASE_BASIC(zIndex, {}); - RAW_SET_PROP_SWITCH_CASE_BASIC(pointerEvents, {}); - RAW_SET_PROP_SWITCH_CASE_BASIC(hitSlop, {}); - RAW_SET_PROP_SWITCH_CASE_BASIC(onLayout, {}); - RAW_SET_PROP_SWITCH_CASE_BASIC(collapsable, true); - RAW_SET_PROP_SWITCH_CASE_BASIC(removeClippedSubviews, false); + RAW_SET_PROP_SWITCH_CASE_BASIC(opacity); + RAW_SET_PROP_SWITCH_CASE_BASIC(foregroundColor); + RAW_SET_PROP_SWITCH_CASE_BASIC(backgroundColor); + RAW_SET_PROP_SWITCH_CASE_BASIC(shadowColor); + RAW_SET_PROP_SWITCH_CASE_BASIC(shadowOffset); + RAW_SET_PROP_SWITCH_CASE_BASIC(shadowOpacity); + RAW_SET_PROP_SWITCH_CASE_BASIC(shadowRadius); + RAW_SET_PROP_SWITCH_CASE_BASIC(transform); + RAW_SET_PROP_SWITCH_CASE_BASIC(backfaceVisibility); + RAW_SET_PROP_SWITCH_CASE_BASIC(shouldRasterize); + RAW_SET_PROP_SWITCH_CASE_BASIC(zIndex); + RAW_SET_PROP_SWITCH_CASE_BASIC(pointerEvents); + RAW_SET_PROP_SWITCH_CASE_BASIC(hitSlop); + RAW_SET_PROP_SWITCH_CASE_BASIC(onLayout); + RAW_SET_PROP_SWITCH_CASE_BASIC(collapsable); + RAW_SET_PROP_SWITCH_CASE_BASIC(removeClippedSubviews); // events field VIEW_EVENT_CASE(PointerEnter); VIEW_EVENT_CASE(PointerEnterCapture); @@ -335,13 +337,13 @@ void ViewProps::setProp( VIEW_EVENT_CASE(TouchEnd); VIEW_EVENT_CASE(TouchCancel); #ifdef ANDROID - RAW_SET_PROP_SWITCH_CASE_BASIC(elevation, {}); - RAW_SET_PROP_SWITCH_CASE(nativeBackground, "nativeBackgroundAndroid", {}); - RAW_SET_PROP_SWITCH_CASE(nativeForeground, "nativeForegroundAndroid", {}); - RAW_SET_PROP_SWITCH_CASE_BASIC(focusable, false); - RAW_SET_PROP_SWITCH_CASE_BASIC(hasTVPreferredFocus, false); - RAW_SET_PROP_SWITCH_CASE_BASIC(needsOffscreenAlphaCompositing, false); - RAW_SET_PROP_SWITCH_CASE_BASIC(renderToHardwareTextureAndroid, false); + RAW_SET_PROP_SWITCH_CASE_BASIC(elevation); + RAW_SET_PROP_SWITCH_CASE(nativeBackground, "nativeBackgroundAndroid"); + RAW_SET_PROP_SWITCH_CASE(nativeForeground, "nativeForegroundAndroid"); + RAW_SET_PROP_SWITCH_CASE_BASIC(focusable); + RAW_SET_PROP_SWITCH_CASE_BASIC(hasTVPreferredFocus); + RAW_SET_PROP_SWITCH_CASE_BASIC(needsOffscreenAlphaCompositing); + RAW_SET_PROP_SWITCH_CASE_BASIC(renderToHardwareTextureAndroid); #endif // BorderRadii SET_CASCADED_RECTANGLE_CORNERS(borderRadii, "border", "Radius", value); diff --git a/ReactCommon/react/renderer/components/view/YogaStylableProps.cpp b/ReactCommon/react/renderer/components/view/YogaStylableProps.cpp index 17e342dd6ee14c..724a33ab4a3b80 100644 --- a/ReactCommon/react/renderer/components/view/YogaStylableProps.cpp +++ b/ReactCommon/react/renderer/components/view/YogaStylableProps.cpp @@ -48,10 +48,10 @@ static inline T const getFieldValue( return defaultValue; } -#define REBUILD_FIELD_SWITCH_CASE2(field, fieldName) \ - case CONSTEXPR_RAW_PROPS_KEY_HASH(fieldName): { \ - yogaStyle.field() = getFieldValue(context, value, defaults.field()); \ - return; \ +#define REBUILD_FIELD_SWITCH_CASE2(field, fieldName) \ + case CONSTEXPR_RAW_PROPS_KEY_HASH(fieldName): { \ + yogaStyle.field() = getFieldValue(context, value, ygDefaults.field()); \ + return; \ } // @lint-ignore CLANGTIDY cppcoreguidelines-macro-usage @@ -61,7 +61,7 @@ static inline T const getFieldValue( #define REBUILD_YG_FIELD_SWITCH_CASE_INDEXED(field, index, fieldName) \ case CONSTEXPR_RAW_PROPS_KEY_HASH(fieldName): { \ yogaStyle.field()[index] = \ - getFieldValue(context, value, defaults.field()[index]); \ + getFieldValue(context, value, ygDefaults.field()[index]); \ return; \ } @@ -104,7 +104,7 @@ void YogaStylableProps::setProp( RawPropsPropNameHash hash, const char *propName, RawValue const &value) { - static const auto defaults = YGStyle{}; + static const auto ygDefaults = YGStyle{}; Props::setProp(context, hash, propName, value); @@ -133,44 +133,28 @@ void YogaStylableProps::setProp( REBUILD_FIELD_YG_EDGES(padding, "padding", ""); REBUILD_FIELD_YG_EDGES(border, "border", "Width"); + static const auto defaults = YogaStylableProps{}; + // Aliases - RAW_SET_PROP_SWITCH_CASE(inset, "inset", CompactValue::ofUndefined()); - RAW_SET_PROP_SWITCH_CASE( - insetBlock, "insetBlock", CompactValue::ofUndefined()); - RAW_SET_PROP_SWITCH_CASE( - insetBlockEnd, "insetBlockEnd", CompactValue::ofUndefined()); - RAW_SET_PROP_SWITCH_CASE( - insetBlockStart, "insetBlockStart", CompactValue::ofUndefined()); - RAW_SET_PROP_SWITCH_CASE( - insetInline, "insetInline", CompactValue::ofUndefined()); - RAW_SET_PROP_SWITCH_CASE( - insetInlineEnd, "insetInlineEnd", CompactValue::ofUndefined()); - RAW_SET_PROP_SWITCH_CASE( - insetInlineStart, "insetInlineStart", CompactValue::ofUndefined()); - RAW_SET_PROP_SWITCH_CASE( - marginInline, "marginInline", CompactValue::ofUndefined()); - RAW_SET_PROP_SWITCH_CASE( - marginInlineStart, "marginInlineStart", CompactValue::ofUndefined()); - RAW_SET_PROP_SWITCH_CASE( - marginInlineEnd, "marginInlineEnd", CompactValue::ofUndefined()); - RAW_SET_PROP_SWITCH_CASE( - marginBlock, "marginBlock", CompactValue::ofUndefined()); - RAW_SET_PROP_SWITCH_CASE( - marginBlockStart, "marginBlockStart", CompactValue::ofUndefined()); - RAW_SET_PROP_SWITCH_CASE( - marginBlockEnd, "marginBlockEnd", CompactValue::ofUndefined()); - RAW_SET_PROP_SWITCH_CASE( - paddingInline, "paddingInline", CompactValue::ofUndefined()); - RAW_SET_PROP_SWITCH_CASE( - paddingInlineStart, "paddingInlineStart", CompactValue::ofUndefined()); - RAW_SET_PROP_SWITCH_CASE( - paddingInlineEnd, "paddingInlineEnd", CompactValue::ofUndefined()); - RAW_SET_PROP_SWITCH_CASE( - paddingBlock, "paddingBlock", CompactValue::ofUndefined()); - RAW_SET_PROP_SWITCH_CASE( - paddingBlockStart, "paddingBlockStart", CompactValue::ofUndefined()); - RAW_SET_PROP_SWITCH_CASE( - paddingBlockEnd, "paddingBlockEnd", CompactValue::ofUndefined()); + RAW_SET_PROP_SWITCH_CASE(inset, "inset"); + RAW_SET_PROP_SWITCH_CASE(insetBlock, "insetBlock"); + RAW_SET_PROP_SWITCH_CASE(insetBlockEnd, "insetBlockEnd"); + RAW_SET_PROP_SWITCH_CASE(insetBlockStart, "insetBlockStart"); + RAW_SET_PROP_SWITCH_CASE(insetInline, "insetInline"); + RAW_SET_PROP_SWITCH_CASE(insetInlineEnd, "insetInlineEnd"); + RAW_SET_PROP_SWITCH_CASE(insetInlineStart, "insetInlineStart"); + RAW_SET_PROP_SWITCH_CASE(marginInline, "marginInline"); + RAW_SET_PROP_SWITCH_CASE(marginInlineStart, "marginInlineStart"); + RAW_SET_PROP_SWITCH_CASE(marginInlineEnd, "marginInlineEnd"); + RAW_SET_PROP_SWITCH_CASE(marginBlock, "marginBlock"); + RAW_SET_PROP_SWITCH_CASE(marginBlockStart, "marginBlockStart"); + RAW_SET_PROP_SWITCH_CASE(marginBlockEnd, "marginBlockEnd"); + RAW_SET_PROP_SWITCH_CASE(paddingInline, "paddingInline"); + RAW_SET_PROP_SWITCH_CASE(paddingInlineStart, "paddingInlineStart"); + RAW_SET_PROP_SWITCH_CASE(paddingInlineEnd, "paddingInlineEnd"); + RAW_SET_PROP_SWITCH_CASE(paddingBlock, "paddingBlock"); + RAW_SET_PROP_SWITCH_CASE(paddingBlockStart, "paddingBlockStart"); + RAW_SET_PROP_SWITCH_CASE(paddingBlockEnd, "paddingBlockEnd"); } } diff --git a/ReactCommon/react/renderer/components/view/primitives.h b/ReactCommon/react/renderer/components/view/primitives.h index 34ea20376f1df9..ec8a276d307db3 100644 --- a/ReactCommon/react/renderer/components/view/primitives.h +++ b/ReactCommon/react/renderer/components/view/primitives.h @@ -99,6 +99,9 @@ struct CascadedRectangleEdges { OptionalT horizontal{}; OptionalT vertical{}; OptionalT all{}; + OptionalT block{}; + OptionalT blockStart{}; + OptionalT blockEnd{}; Counterpart resolve(bool isRTL, T defaults) const { const auto leadingEdge = isRTL ? end : start; @@ -111,10 +114,14 @@ struct CascadedRectangleEdges { return { /* .left = */ left.value_or(leadingEdge.value_or(horizontalOrAllOrDefault)), - /* .top = */ top.value_or(verticalOrAllOrDefault), + /* .top = */ + blockStart.value_or( + block.value_or(top.value_or(verticalOrAllOrDefault))), /* .right = */ right.value_or(trailingEdge.value_or(horizontalOrAllOrDefault)), - /* .bottom = */ bottom.value_or(verticalOrAllOrDefault), + /* .bottom = */ + blockEnd.value_or( + block.value_or(bottom.value_or(verticalOrAllOrDefault))), }; } @@ -128,7 +135,10 @@ struct CascadedRectangleEdges { this->end, this->horizontal, this->vertical, - this->all) == + this->all, + this->block, + this->blockStart, + this->blockEnd) == std::tie( rhs.left, rhs.top, @@ -138,7 +148,10 @@ struct CascadedRectangleEdges { rhs.end, rhs.horizontal, rhs.vertical, - rhs.all); + rhs.all, + rhs.block, + rhs.blockStart, + rhs.blockEnd); } bool operator!=(const CascadedRectangleEdges &rhs) const { diff --git a/ReactCommon/react/renderer/components/view/propsConversions.h b/ReactCommon/react/renderer/components/view/propsConversions.h index 97fa6b6d7eeb02..ad7cc2f3a3488c 100644 --- a/ReactCommon/react/renderer/components/view/propsConversions.h +++ b/ReactCommon/react/renderer/components/view/propsConversions.h @@ -515,6 +515,30 @@ static inline CascadedRectangleEdges convertRawProp( defaultValue.vertical, prefix, suffix); + result.block = convertRawProp( + context, + rawProps, + "Block", + sourceValue.block, + defaultValue.block, + prefix, + suffix); + result.blockEnd = convertRawProp( + context, + rawProps, + "BlockEnd", + sourceValue.blockEnd, + defaultValue.blockEnd, + prefix, + suffix); + result.blockStart = convertRawProp( + context, + rawProps, + "BlockStart", + sourceValue.blockStart, + defaultValue.blockStart, + prefix, + suffix); result.all = convertRawProp( context, rawProps, "", sourceValue.all, defaultValue.all, prefix, suffix); diff --git a/ReactCommon/react/renderer/components/view/viewPropConversions.h b/ReactCommon/react/renderer/components/view/viewPropConversions.h index fe253277752cb4..64a0469a9f7c8b 100644 --- a/ReactCommon/react/renderer/components/view/viewPropConversions.h +++ b/ReactCommon/react/renderer/components/view/viewPropConversions.h @@ -28,6 +28,9 @@ constexpr MapBuffer::Key EDGE_BOTTOM = 3; constexpr MapBuffer::Key EDGE_START = 4; constexpr MapBuffer::Key EDGE_END = 5; constexpr MapBuffer::Key EDGE_ALL = 6; +constexpr MapBuffer::Key EDGE_BLOCK = 7; +constexpr MapBuffer::Key EDGE_BLOCK_START = 8; +constexpr MapBuffer::Key EDGE_BLOCK_END = 9; constexpr MapBuffer::Key CORNER_TOP_LEFT = 0; constexpr MapBuffer::Key CORNER_TOP_RIGHT = 1; @@ -107,13 +110,17 @@ inline MapBuffer convertBorderColors(CascadedBorderColors const &colors) { template MapBuffer convertCascadedEdges(CascadedRectangleEdges const &edges) { - MapBufferBuilder builder(7); + MapBufferBuilder builder(10); putOptionalFloat(builder, EDGE_TOP, optionalFromValue(edges.top)); putOptionalFloat(builder, EDGE_RIGHT, optionalFromValue(edges.right)); putOptionalFloat(builder, EDGE_BOTTOM, optionalFromValue(edges.bottom)); putOptionalFloat(builder, EDGE_LEFT, optionalFromValue(edges.left)); putOptionalFloat(builder, EDGE_START, optionalFromValue(edges.start)); putOptionalFloat(builder, EDGE_END, optionalFromValue(edges.end)); + putOptionalFloat(builder, EDGE_BLOCK, optionalFromValue(edges.block)); + putOptionalFloat(builder, EDGE_BLOCK_END, optionalFromValue(edges.blockEnd)); + putOptionalFloat( + builder, EDGE_BLOCK_START, optionalFromValue(edges.blockStart)); putOptionalFloat(builder, EDGE_ALL, optionalFromValue(edges.all)); return builder.build(); } diff --git a/ReactCommon/react/renderer/core/PropsMacros.h b/ReactCommon/react/renderer/core/PropsMacros.h index 2aa75fd4e4216e..a3d07018fb95da 100644 --- a/ReactCommon/react/renderer/core/PropsMacros.h +++ b/ReactCommon/react/renderer/core/PropsMacros.h @@ -31,15 +31,15 @@ // Convenience for building setProps switch statements. // This injects `fromRawValue` into source; each file that uses // this macro must import the proper, respective headers required. -#define RAW_SET_PROP_SWITCH_CASE(field, jsPropName, defaultValue) \ - case CONSTEXPR_RAW_PROPS_KEY_HASH(jsPropName): \ - fromRawValue(context, value, field, defaultValue); \ +#define RAW_SET_PROP_SWITCH_CASE(field, jsPropName) \ + case CONSTEXPR_RAW_PROPS_KEY_HASH(jsPropName): \ + fromRawValue(context, value, field, defaults.field); \ return; // Convenience for building setProps switch statements where the field name is // the same as the string identifier -#define RAW_SET_PROP_SWITCH_CASE_BASIC(field, defaultValue) \ - RAW_SET_PROP_SWITCH_CASE(field, #field, defaultValue) +#define RAW_SET_PROP_SWITCH_CASE_BASIC(field) \ + RAW_SET_PROP_SWITCH_CASE(field, #field) #define CASE_STATEMENT_SET_FIELD_VALUE_INDEXED( \ struct, field, fieldNameString, value) \ @@ -99,7 +99,13 @@ CASE_STATEMENT_SET_FIELD_VALUE_INDEXED( \ struct, vertical, prefix "Vertical" suffix, rawValue) \ CASE_STATEMENT_SET_FIELD_VALUE_INDEXED( \ - struct, all, prefix "" suffix, rawValue) + struct, all, prefix "" suffix, rawValue) \ + CASE_STATEMENT_SET_FIELD_VALUE_INDEXED( \ + struct, block, prefix "Block" suffix, rawValue) \ + CASE_STATEMENT_SET_FIELD_VALUE_INDEXED( \ + struct, blockEnd, prefix "BlockEnd" suffix, rawValue) \ + CASE_STATEMENT_SET_FIELD_VALUE_INDEXED( \ + struct, blockStart, prefix "BlockStart" suffix, rawValue) // Rebuild a type that contains multiple fields from a single field value #define REBUILD_FIELD_SWITCH_CASE( \ diff --git a/ReactCommon/react/renderer/graphics/CMakeLists.txt b/ReactCommon/react/renderer/graphics/CMakeLists.txt index 3e257d5968624b..ac5eae299c1ae0 100644 --- a/ReactCommon/react/renderer/graphics/CMakeLists.txt +++ b/ReactCommon/react/renderer/graphics/CMakeLists.txt @@ -25,3 +25,4 @@ target_include_directories(react_render_graphics ) target_link_libraries(react_render_graphics glog fb fbjni folly_runtime react_debug) + diff --git a/build.gradle.kts b/build.gradle.kts index bcdbd6c874f2a8..dde63fc00734fc 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -33,7 +33,7 @@ buildscript { gradlePluginPortal() } dependencies { - classpath("com.android.tools.build:gradle:7.3.1") + classpath("com.android.tools.build:gradle:7.4.1") classpath("de.undercouch:gradle-download-task:5.0.1") } } diff --git a/index.js b/index.js index 0b6e97c0522640..7149c6463b52fa 100644 --- a/index.js +++ b/index.js @@ -191,7 +191,7 @@ module.exports = { return require('./Libraries/Components/View/View'); }, get VirtualizedList(): VirtualizedList { - return require('./Libraries/Lists/VirtualizedList').default; + return require('./Libraries/Lists/VirtualizedList'); }, get VirtualizedSectionList(): VirtualizedSectionList { return require('./Libraries/Lists/VirtualizedSectionList'); diff --git a/interface.js b/interface.js index 291c81952e340b..8052785f9b5ffa 100644 --- a/interface.js +++ b/interface.js @@ -11,7 +11,7 @@ 'use strict'; // NOTE: Hmm... I don't think declaring variables within this module actually -// accomplishes anything besides documenting that these globals are exepcted to +// accomplishes anything besides documenting that these globals are expected to // exist. So I think the correct "fix" to this lint warning is to delete this // entire file. But in lieu of doing that... no harm for now in keeping this // file around, even if it is only for documentation purposes. ¯\_(ツ)_/¯ diff --git a/package.json b/package.json index d8a95a8941f325..e17aa48a77c965 100644 --- a/package.json +++ b/package.json @@ -85,7 +85,7 @@ "prettier": "prettier --write \"./**/*.{js,md,yml,ts,tsx}\"", "format-check": "prettier --list-different \"./**/*.{js,md,yml,ts,tsx}\"", "update-lock": "npx yarn-deduplicate", - "docker-setup-android": "docker pull reactnativecommunity/react-native-android:6.2", + "docker-setup-android": "docker pull reactnativecommunity/react-native-android:7.0", "docker-build-android": "docker build -t reactnativeci/android -f .circleci/Dockerfiles/Dockerfile.android .", "test-android-run-instrumentation": "docker run --cap-add=SYS_ADMIN -it reactnativeci/android bash .circleci/Dockerfiles/scripts/run-android-docker-instrumentation-tests.sh", "test-android-run-unit": "docker run --cap-add=SYS_ADMIN -it reactnativeci/android bash .circleci/Dockerfiles/scripts/run-android-docker-unit-tests.sh", @@ -118,6 +118,7 @@ "@react-native/gradle-plugin": "^0.72.2", "@react-native/js-polyfills": "^0.72.0", "@react-native/normalize-colors": "^0.72.0", + "@react-native/virtualized-lists": "0.72.0", "abort-controller": "^3.0.0", "anser": "^1.4.9", "base64-js": "^1.1.2", @@ -125,7 +126,7 @@ "event-target-shim": "^5.0.1", "invariant": "^2.2.4", "jest-environment-node": "^29.2.1", - "jsc-android": "^250230.2.1", + "jsc-android": "^250231.0.0", "memoize-one": "^5.0.0", "metro-react-native-babel-transformer": "0.73.5", "metro-runtime": "0.73.5", @@ -145,7 +146,7 @@ "ws": "^6.2.2" }, "devDependencies": { - "flow-bin": "^0.198.2", + "flow-bin": "^0.199.1", "hermes-eslint": "0.8.0", "mock-fs": "^5.1.4", "react": "18.2.0", diff --git a/packages/react-native-codegen/e2e/__test_fixtures__/modules/NativeEnumTurboModule.js b/packages/react-native-codegen/e2e/__test_fixtures__/modules/NativeEnumTurboModule.js new file mode 100644 index 00000000000000..1dbeeec74d8ec2 --- /dev/null +++ b/packages/react-native-codegen/e2e/__test_fixtures__/modules/NativeEnumTurboModule.js @@ -0,0 +1,68 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow strict-local + * @format + */ + +import type {TurboModule} from 'react-native/Libraries/TurboModule/RCTExport'; +import * as TurboModuleRegistry from 'react-native/Libraries/TurboModule/TurboModuleRegistry'; + +export type StateType = {| + state: string, +|}; + +export enum StatusRegularEnum { + Active, + Paused, + Off, +} + +export enum StatusStrEnum { + Active = 'active', + Paused = 'paused', + Off = 'off', +} + +export enum StatusNumEnum { + Active = 2, + Paused = 1, + Off = 0, +} + +export enum StatusFractionEnum { + Active = 0.2, + Paused = 0.1, + Off = 0.0, +} + +export type StateTypeWithEnums = {| + state: string, + regular: StatusRegularEnum, + str: StatusStrEnum, + num: StatusNumEnum, + fraction: StatusFractionEnum, +|}; + +export interface Spec extends TurboModule { + +getStatusRegular: (statusProp: StateType) => StatusRegularEnum; + +getStatusStr: (statusProp: StateType) => StatusStrEnum; + +getStatusNum: (statusProp: StateType) => StatusNumEnum; + +getStatusFraction: (statusProp: StateType) => StatusFractionEnum; + +getStateType: ( + a: StatusRegularEnum, + b: StatusStrEnum, + c: StatusNumEnum, + d: StatusFractionEnum, + ) => StateType; + +getStateTypeWithEnums: ( + paramOfTypeWithEnums: StateTypeWithEnums, + ) => StateTypeWithEnums; +} + +export default (TurboModuleRegistry.getEnforcing( + 'NativeEnumTurboModule', +): Spec); diff --git a/packages/react-native-codegen/e2e/__tests__/modules/GenerateModuleCpp-test.js b/packages/react-native-codegen/e2e/__tests__/modules/GenerateModuleCpp-test.js new file mode 100644 index 00000000000000..662a8fd0ddb3db --- /dev/null +++ b/packages/react-native-codegen/e2e/__tests__/modules/GenerateModuleCpp-test.js @@ -0,0 +1,52 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow strict-local + * @format + * @oncall react_native + */ + +'use strict'; + +const {FlowParser} = require('../../../src/parsers/flow/parser'); +const generator = require('../../../src/generators/modules/GenerateModuleCpp'); +const fs = require('fs'); + +import type {SchemaType} from '../../../src/CodegenSchema'; + +const FIXTURE_DIR = `${__dirname}/../../__test_fixtures__/modules`; + +const parser = new FlowParser(); + +function getModules(): SchemaType { + const filenames: Array = fs.readdirSync(FIXTURE_DIR); + return filenames.reduce( + (accumulator, file) => { + const schema = parser.parseFile(`${FIXTURE_DIR}/${file}`); + return { + modules: { + ...accumulator.modules, + ...schema.modules, + }, + }; + }, + {modules: {}}, + ); +} + +describe('GenerateModuleCpp', () => { + it('can generate an implementation file NativeModule specs', () => { + const libName = 'RNCodegenModuleFixtures'; + const output = generator.generate(libName, getModules(), undefined, false); + expect(output.get(libName + 'JSI-generated.cpp')).toMatchSnapshot(); + }); + + it('can generate a header file NativeModule specs with assume nonnull enabled', () => { + const libName = 'RNCodegenModuleFixtures'; + const output = generator.generate(libName, getModules(), undefined, true); + expect(output.get(libName + 'JSI-generated.cpp')).toMatchSnapshot(); + }); +}); diff --git a/packages/react-native-codegen/e2e/__tests__/modules/GenerateModuleH-test.js b/packages/react-native-codegen/e2e/__tests__/modules/GenerateModuleH-test.js new file mode 100644 index 00000000000000..51b6c8e37b6769 --- /dev/null +++ b/packages/react-native-codegen/e2e/__tests__/modules/GenerateModuleH-test.js @@ -0,0 +1,52 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow strict-local + * @format + * @oncall react_native + */ + +'use strict'; + +const {FlowParser} = require('../../../src/parsers/flow/parser'); +const generator = require('../../../src/generators/modules/GenerateModuleH'); +const fs = require('fs'); + +import type {SchemaType} from '../../../src/CodegenSchema'; + +const FIXTURE_DIR = `${__dirname}/../../__test_fixtures__/modules`; + +const parser = new FlowParser(); + +function getModules(): SchemaType { + const filenames: Array = fs.readdirSync(FIXTURE_DIR); + return filenames.reduce( + (accumulator, file) => { + const schema = parser.parseFile(`${FIXTURE_DIR}/${file}`); + return { + modules: { + ...accumulator.modules, + ...schema.modules, + }, + }; + }, + {modules: {}}, + ); +} + +describe('GenerateModuleH', () => { + it('can generate a header file NativeModule specs', () => { + const libName = 'RNCodegenModuleFixtures'; + const output = generator.generate(libName, getModules(), undefined, false); + expect(output.get(libName + 'JSI.h')).toMatchSnapshot(); + }); + + it('can generate a header file NativeModule specs with assume nonnull enabled', () => { + const libName = 'RNCodegenModuleFixtures'; + const output = generator.generate(libName, getModules(), undefined, true); + expect(output.get(libName + 'JSI.h')).toMatchSnapshot(); + }); +}); diff --git a/packages/react-native-codegen/e2e/__tests__/modules/__snapshots__/GenerateModuleCpp-test.js.snap b/packages/react-native-codegen/e2e/__tests__/modules/__snapshots__/GenerateModuleCpp-test.js.snap new file mode 100644 index 00000000000000..06f976b26535a7 --- /dev/null +++ b/packages/react-native-codegen/e2e/__tests__/modules/__snapshots__/GenerateModuleCpp-test.js.snap @@ -0,0 +1,1047 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`GenerateModuleCpp can generate a header file NativeModule specs with assume nonnull enabled 1`] = ` +"/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleH.js + */ + +#include \\"RNCodegenModuleFixturesJSI.h\\" + +namespace facebook { +namespace react { + +static jsi::Value __hostFunction_NativeArrayTurboModuleCxxSpecJSI_getArray(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getArray(rt, args[0].asObject(rt).asArray(rt)); +} +static jsi::Value __hostFunction_NativeArrayTurboModuleCxxSpecJSI_getReadOnlyArray(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getReadOnlyArray(rt, args[0].asObject(rt).asArray(rt)); +} +static jsi::Value __hostFunction_NativeArrayTurboModuleCxxSpecJSI_getArrayWithAlias(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getArrayWithAlias(rt, args[0].asObject(rt).asArray(rt), args[1].asObject(rt).asArray(rt)); +} + +NativeArrayTurboModuleCxxSpecJSI::NativeArrayTurboModuleCxxSpecJSI(std::shared_ptr jsInvoker) + : TurboModule(\\"SampleTurboModule\\", jsInvoker) { + methodMap_[\\"getArray\\"] = MethodMetadata {1, __hostFunction_NativeArrayTurboModuleCxxSpecJSI_getArray}; + methodMap_[\\"getReadOnlyArray\\"] = MethodMetadata {1, __hostFunction_NativeArrayTurboModuleCxxSpecJSI_getReadOnlyArray}; + methodMap_[\\"getArrayWithAlias\\"] = MethodMetadata {2, __hostFunction_NativeArrayTurboModuleCxxSpecJSI_getArrayWithAlias}; +} +static jsi::Value __hostFunction_NativeBooleanTurboModuleCxxSpecJSI_getBoolean(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getBoolean(rt, args[0].asBool()); +} +static jsi::Value __hostFunction_NativeBooleanTurboModuleCxxSpecJSI_getBooleanWithAlias(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getBooleanWithAlias(rt, args[0].asBool()); +} + +NativeBooleanTurboModuleCxxSpecJSI::NativeBooleanTurboModuleCxxSpecJSI(std::shared_ptr jsInvoker) + : TurboModule(\\"SampleTurboModule\\", jsInvoker) { + methodMap_[\\"getBoolean\\"] = MethodMetadata {1, __hostFunction_NativeBooleanTurboModuleCxxSpecJSI_getBoolean}; + methodMap_[\\"getBooleanWithAlias\\"] = MethodMetadata {1, __hostFunction_NativeBooleanTurboModuleCxxSpecJSI_getBooleanWithAlias}; +} +static jsi::Value __hostFunction_NativeCallbackTurboModuleCxxSpecJSI_getValueWithCallback(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + static_cast(&turboModule)->getValueWithCallback(rt, args[0].asObject(rt).asFunction(rt)); + return jsi::Value::undefined(); +} +static jsi::Value __hostFunction_NativeCallbackTurboModuleCxxSpecJSI_getValueWithCallbackWithAlias(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + static_cast(&turboModule)->getValueWithCallbackWithAlias(rt, args[0].asObject(rt).asFunction(rt)); + return jsi::Value::undefined(); +} + +NativeCallbackTurboModuleCxxSpecJSI::NativeCallbackTurboModuleCxxSpecJSI(std::shared_ptr jsInvoker) + : TurboModule(\\"SampleTurboModule\\", jsInvoker) { + methodMap_[\\"getValueWithCallback\\"] = MethodMetadata {1, __hostFunction_NativeCallbackTurboModuleCxxSpecJSI_getValueWithCallback}; + methodMap_[\\"getValueWithCallbackWithAlias\\"] = MethodMetadata {1, __hostFunction_NativeCallbackTurboModuleCxxSpecJSI_getValueWithCallbackWithAlias}; +} +static jsi::Value __hostFunction_NativeEnumTurboModuleCxxSpecJSI_getStatusRegular(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getStatusRegular(rt, args[0].asObject(rt)); +} +static jsi::Value __hostFunction_NativeEnumTurboModuleCxxSpecJSI_getStatusStr(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getStatusStr(rt, args[0].asObject(rt)); +} +static jsi::Value __hostFunction_NativeEnumTurboModuleCxxSpecJSI_getStatusNum(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getStatusNum(rt, args[0].asObject(rt)); +} +static jsi::Value __hostFunction_NativeEnumTurboModuleCxxSpecJSI_getStatusFraction(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getStatusFraction(rt, args[0].asObject(rt)); +} +static jsi::Value __hostFunction_NativeEnumTurboModuleCxxSpecJSI_getStateType(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getStateType(rt, args[0].asString(rt), args[1].asString(rt), args[2].asNumber(), args[3].asNumber()); +} +static jsi::Value __hostFunction_NativeEnumTurboModuleCxxSpecJSI_getStateTypeWithEnums(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getStateTypeWithEnums(rt, args[0].asObject(rt)); +} + +NativeEnumTurboModuleCxxSpecJSI::NativeEnumTurboModuleCxxSpecJSI(std::shared_ptr jsInvoker) + : TurboModule(\\"NativeEnumTurboModule\\", jsInvoker) { + methodMap_[\\"getStatusRegular\\"] = MethodMetadata {1, __hostFunction_NativeEnumTurboModuleCxxSpecJSI_getStatusRegular}; + methodMap_[\\"getStatusStr\\"] = MethodMetadata {1, __hostFunction_NativeEnumTurboModuleCxxSpecJSI_getStatusStr}; + methodMap_[\\"getStatusNum\\"] = MethodMetadata {1, __hostFunction_NativeEnumTurboModuleCxxSpecJSI_getStatusNum}; + methodMap_[\\"getStatusFraction\\"] = MethodMetadata {1, __hostFunction_NativeEnumTurboModuleCxxSpecJSI_getStatusFraction}; + methodMap_[\\"getStateType\\"] = MethodMetadata {4, __hostFunction_NativeEnumTurboModuleCxxSpecJSI_getStateType}; + methodMap_[\\"getStateTypeWithEnums\\"] = MethodMetadata {1, __hostFunction_NativeEnumTurboModuleCxxSpecJSI_getStateTypeWithEnums}; +} +static jsi::Value __hostFunction_NativeNullableTurboModuleCxxSpecJSI_getBool(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + auto result = static_cast(&turboModule)->getBool(rt, args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].asBool())); + return result ? jsi::Value(std::move(*result)) : jsi::Value::null(); +} +static jsi::Value __hostFunction_NativeNullableTurboModuleCxxSpecJSI_getNumber(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + auto result = static_cast(&turboModule)->getNumber(rt, args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].asNumber())); + return result ? jsi::Value(std::move(*result)) : jsi::Value::null(); +} +static jsi::Value __hostFunction_NativeNullableTurboModuleCxxSpecJSI_getString(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + auto result = static_cast(&turboModule)->getString(rt, args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].asNumber())); + return result ? jsi::Value(std::move(*result)) : jsi::Value::null(); +} +static jsi::Value __hostFunction_NativeNullableTurboModuleCxxSpecJSI_getArray(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + auto result = static_cast(&turboModule)->getArray(rt, args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].asObject(rt).asArray(rt))); + return result ? jsi::Value(std::move(*result)) : jsi::Value::null(); +} +static jsi::Value __hostFunction_NativeNullableTurboModuleCxxSpecJSI_getObject(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + auto result = static_cast(&turboModule)->getObject(rt, args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].asObject(rt))); + return result ? jsi::Value(std::move(*result)) : jsi::Value::null(); +} +static jsi::Value __hostFunction_NativeNullableTurboModuleCxxSpecJSI_getValueWithPromise(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + auto result = static_cast(&turboModule)->getValueWithPromise(rt); + return result ? jsi::Value(std::move(*result)) : jsi::Value::null(); +} + +NativeNullableTurboModuleCxxSpecJSI::NativeNullableTurboModuleCxxSpecJSI(std::shared_ptr jsInvoker) + : TurboModule(\\"SampleTurboModule\\", jsInvoker) { + methodMap_[\\"getBool\\"] = MethodMetadata {1, __hostFunction_NativeNullableTurboModuleCxxSpecJSI_getBool}; + methodMap_[\\"getNumber\\"] = MethodMetadata {1, __hostFunction_NativeNullableTurboModuleCxxSpecJSI_getNumber}; + methodMap_[\\"getString\\"] = MethodMetadata {1, __hostFunction_NativeNullableTurboModuleCxxSpecJSI_getString}; + methodMap_[\\"getArray\\"] = MethodMetadata {1, __hostFunction_NativeNullableTurboModuleCxxSpecJSI_getArray}; + methodMap_[\\"getObject\\"] = MethodMetadata {1, __hostFunction_NativeNullableTurboModuleCxxSpecJSI_getObject}; + methodMap_[\\"getValueWithPromise\\"] = MethodMetadata {0, __hostFunction_NativeNullableTurboModuleCxxSpecJSI_getValueWithPromise}; +} +static jsi::Value __hostFunction_NativeNumberTurboModuleCxxSpecJSI_getNumber(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getNumber(rt, args[0].asNumber()); +} +static jsi::Value __hostFunction_NativeNumberTurboModuleCxxSpecJSI_getNumberWithAlias(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getNumberWithAlias(rt, args[0].asNumber()); +} + +NativeNumberTurboModuleCxxSpecJSI::NativeNumberTurboModuleCxxSpecJSI(std::shared_ptr jsInvoker) + : TurboModule(\\"SampleTurboModule\\", jsInvoker) { + methodMap_[\\"getNumber\\"] = MethodMetadata {1, __hostFunction_NativeNumberTurboModuleCxxSpecJSI_getNumber}; + methodMap_[\\"getNumberWithAlias\\"] = MethodMetadata {1, __hostFunction_NativeNumberTurboModuleCxxSpecJSI_getNumberWithAlias}; +} +static jsi::Value __hostFunction_NativeObjectTurboModuleCxxSpecJSI_getGenericObject(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getGenericObject(rt, args[0].asObject(rt)); +} +static jsi::Value __hostFunction_NativeObjectTurboModuleCxxSpecJSI_getGenericObjectReadOnly(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getGenericObjectReadOnly(rt, args[0].asObject(rt)); +} +static jsi::Value __hostFunction_NativeObjectTurboModuleCxxSpecJSI_getGenericObjectWithAlias(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getGenericObjectWithAlias(rt, args[0].asObject(rt)); +} +static jsi::Value __hostFunction_NativeObjectTurboModuleCxxSpecJSI_difficultObject(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->difficultObject(rt, args[0].asObject(rt)); +} +static jsi::Value __hostFunction_NativeObjectTurboModuleCxxSpecJSI_getConstants(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getConstants(rt); +} + +NativeObjectTurboModuleCxxSpecJSI::NativeObjectTurboModuleCxxSpecJSI(std::shared_ptr jsInvoker) + : TurboModule(\\"SampleTurboModule\\", jsInvoker) { + methodMap_[\\"getGenericObject\\"] = MethodMetadata {1, __hostFunction_NativeObjectTurboModuleCxxSpecJSI_getGenericObject}; + methodMap_[\\"getGenericObjectReadOnly\\"] = MethodMetadata {1, __hostFunction_NativeObjectTurboModuleCxxSpecJSI_getGenericObjectReadOnly}; + methodMap_[\\"getGenericObjectWithAlias\\"] = MethodMetadata {1, __hostFunction_NativeObjectTurboModuleCxxSpecJSI_getGenericObjectWithAlias}; + methodMap_[\\"difficultObject\\"] = MethodMetadata {1, __hostFunction_NativeObjectTurboModuleCxxSpecJSI_difficultObject}; + methodMap_[\\"getConstants\\"] = MethodMetadata {0, __hostFunction_NativeObjectTurboModuleCxxSpecJSI_getConstants}; +} +static jsi::Value __hostFunction_NativeOptionalObjectTurboModuleCxxSpecJSI_getConstants(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getConstants(rt); +} + +NativeOptionalObjectTurboModuleCxxSpecJSI::NativeOptionalObjectTurboModuleCxxSpecJSI(std::shared_ptr jsInvoker) + : TurboModule(\\"SampleTurboModule\\", jsInvoker) { + methodMap_[\\"getConstants\\"] = MethodMetadata {0, __hostFunction_NativeOptionalObjectTurboModuleCxxSpecJSI_getConstants}; +} +static jsi::Value __hostFunction_NativePartialAnnotationTurboModuleCxxSpecJSI_getSomeObj(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getSomeObj(rt); +} +static jsi::Value __hostFunction_NativePartialAnnotationTurboModuleCxxSpecJSI_getPartialSomeObj(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getPartialSomeObj(rt); +} +static jsi::Value __hostFunction_NativePartialAnnotationTurboModuleCxxSpecJSI_getSomeObjFromPartialSomeObj(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getSomeObjFromPartialSomeObj(rt, args[0].asObject(rt)); +} +static jsi::Value __hostFunction_NativePartialAnnotationTurboModuleCxxSpecJSI_getPartialPartial(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getPartialPartial(rt, args[0].asObject(rt), args[1].asObject(rt)); +} + +NativePartialAnnotationTurboModuleCxxSpecJSI::NativePartialAnnotationTurboModuleCxxSpecJSI(std::shared_ptr jsInvoker) + : TurboModule(\\"NativePartialAnnotationTurboModule\\", jsInvoker) { + methodMap_[\\"getSomeObj\\"] = MethodMetadata {0, __hostFunction_NativePartialAnnotationTurboModuleCxxSpecJSI_getSomeObj}; + methodMap_[\\"getPartialSomeObj\\"] = MethodMetadata {0, __hostFunction_NativePartialAnnotationTurboModuleCxxSpecJSI_getPartialSomeObj}; + methodMap_[\\"getSomeObjFromPartialSomeObj\\"] = MethodMetadata {1, __hostFunction_NativePartialAnnotationTurboModuleCxxSpecJSI_getSomeObjFromPartialSomeObj}; + methodMap_[\\"getPartialPartial\\"] = MethodMetadata {2, __hostFunction_NativePartialAnnotationTurboModuleCxxSpecJSI_getPartialPartial}; +} +static jsi::Value __hostFunction_NativePromiseTurboModuleCxxSpecJSI_getValueWithPromise(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getValueWithPromise(rt, args[0].asBool()); +} +static jsi::Value __hostFunction_NativePromiseTurboModuleCxxSpecJSI_getValueWithPromiseWithAlias(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getValueWithPromiseWithAlias(rt, args[0].asString(rt)); +} + +NativePromiseTurboModuleCxxSpecJSI::NativePromiseTurboModuleCxxSpecJSI(std::shared_ptr jsInvoker) + : TurboModule(\\"SampleTurboModule\\", jsInvoker) { + methodMap_[\\"getValueWithPromise\\"] = MethodMetadata {1, __hostFunction_NativePromiseTurboModuleCxxSpecJSI_getValueWithPromise}; + methodMap_[\\"getValueWithPromiseWithAlias\\"] = MethodMetadata {1, __hostFunction_NativePromiseTurboModuleCxxSpecJSI_getValueWithPromiseWithAlias}; +} +static jsi::Value __hostFunction_NativeSampleTurboModuleCxxSpecJSI_getConstants(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getConstants(rt); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleCxxSpecJSI_voidFunc(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + static_cast(&turboModule)->voidFunc(rt); + return jsi::Value::undefined(); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleCxxSpecJSI_getBool(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getBool(rt, args[0].asBool()); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleCxxSpecJSI_getNumber(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getNumber(rt, args[0].asNumber()); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleCxxSpecJSI_getString(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getString(rt, args[0].asString(rt)); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleCxxSpecJSI_getArray(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getArray(rt, args[0].asObject(rt).asArray(rt)); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleCxxSpecJSI_getObject(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getObject(rt, args[0].asObject(rt)); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleCxxSpecJSI_getObjectShape(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getObjectShape(rt, args[0].asObject(rt)); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleCxxSpecJSI_getAlias(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getAlias(rt, args[0].asObject(rt)); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleCxxSpecJSI_getRootTag(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getRootTag(rt, args[0].getNumber()); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleCxxSpecJSI_getValue(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getValue(rt, args[0].asNumber(), args[1].asString(rt), args[2].asObject(rt)); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleCxxSpecJSI_getValueWithCallback(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + static_cast(&turboModule)->getValueWithCallback(rt, args[0].asObject(rt).asFunction(rt)); + return jsi::Value::undefined(); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleCxxSpecJSI_getValueWithPromise(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getValueWithPromise(rt, args[0].asBool()); +} + +NativeSampleTurboModuleCxxSpecJSI::NativeSampleTurboModuleCxxSpecJSI(std::shared_ptr jsInvoker) + : TurboModule(\\"SampleTurboModule\\", jsInvoker) { + methodMap_[\\"getConstants\\"] = MethodMetadata {0, __hostFunction_NativeSampleTurboModuleCxxSpecJSI_getConstants}; + methodMap_[\\"voidFunc\\"] = MethodMetadata {0, __hostFunction_NativeSampleTurboModuleCxxSpecJSI_voidFunc}; + methodMap_[\\"getBool\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleCxxSpecJSI_getBool}; + methodMap_[\\"getNumber\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleCxxSpecJSI_getNumber}; + methodMap_[\\"getString\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleCxxSpecJSI_getString}; + methodMap_[\\"getArray\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleCxxSpecJSI_getArray}; + methodMap_[\\"getObject\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleCxxSpecJSI_getObject}; + methodMap_[\\"getObjectShape\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleCxxSpecJSI_getObjectShape}; + methodMap_[\\"getAlias\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleCxxSpecJSI_getAlias}; + methodMap_[\\"getRootTag\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleCxxSpecJSI_getRootTag}; + methodMap_[\\"getValue\\"] = MethodMetadata {3, __hostFunction_NativeSampleTurboModuleCxxSpecJSI_getValue}; + methodMap_[\\"getValueWithCallback\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleCxxSpecJSI_getValueWithCallback}; + methodMap_[\\"getValueWithPromise\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleCxxSpecJSI_getValueWithPromise}; +} +static jsi::Value __hostFunction_NativeSampleTurboModuleArraysCxxSpecJSI_getConstants(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getConstants(rt); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleArraysCxxSpecJSI_voidFunc(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + static_cast(&turboModule)->voidFunc(rt); + return jsi::Value::undefined(); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleArraysCxxSpecJSI_getBool(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getBool(rt, args[0].asObject(rt).asArray(rt)); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleArraysCxxSpecJSI_getNumber(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getNumber(rt, args[0].asObject(rt).asArray(rt)); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleArraysCxxSpecJSI_getString(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getString(rt, args[0].asObject(rt).asArray(rt)); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleArraysCxxSpecJSI_getArray(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getArray(rt, args[0].asObject(rt).asArray(rt)); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleArraysCxxSpecJSI_getObject(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getObject(rt, args[0].asObject(rt).asArray(rt)); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleArraysCxxSpecJSI_getObjectShape(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getObjectShape(rt, args[0].asObject(rt).asArray(rt)); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleArraysCxxSpecJSI_getAlias(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getAlias(rt, args[0].asObject(rt).asArray(rt)); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleArraysCxxSpecJSI_getRootTag(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getRootTag(rt, args[0].asObject(rt).asArray(rt)); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleArraysCxxSpecJSI_getValue(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getValue(rt, args[0].asObject(rt).asArray(rt), args[1].asObject(rt).asArray(rt), args[2].asObject(rt).asArray(rt)); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleArraysCxxSpecJSI_getValueWithCallback(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + static_cast(&turboModule)->getValueWithCallback(rt, args[0].asObject(rt).asFunction(rt)); + return jsi::Value::undefined(); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleArraysCxxSpecJSI_getValueWithPromise(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getValueWithPromise(rt, args[0].asObject(rt).asArray(rt)); +} + +NativeSampleTurboModuleArraysCxxSpecJSI::NativeSampleTurboModuleArraysCxxSpecJSI(std::shared_ptr jsInvoker) + : TurboModule(\\"SampleTurboModuleArrays\\", jsInvoker) { + methodMap_[\\"getConstants\\"] = MethodMetadata {0, __hostFunction_NativeSampleTurboModuleArraysCxxSpecJSI_getConstants}; + methodMap_[\\"voidFunc\\"] = MethodMetadata {0, __hostFunction_NativeSampleTurboModuleArraysCxxSpecJSI_voidFunc}; + methodMap_[\\"getBool\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleArraysCxxSpecJSI_getBool}; + methodMap_[\\"getNumber\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleArraysCxxSpecJSI_getNumber}; + methodMap_[\\"getString\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleArraysCxxSpecJSI_getString}; + methodMap_[\\"getArray\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleArraysCxxSpecJSI_getArray}; + methodMap_[\\"getObject\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleArraysCxxSpecJSI_getObject}; + methodMap_[\\"getObjectShape\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleArraysCxxSpecJSI_getObjectShape}; + methodMap_[\\"getAlias\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleArraysCxxSpecJSI_getAlias}; + methodMap_[\\"getRootTag\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleArraysCxxSpecJSI_getRootTag}; + methodMap_[\\"getValue\\"] = MethodMetadata {3, __hostFunction_NativeSampleTurboModuleArraysCxxSpecJSI_getValue}; + methodMap_[\\"getValueWithCallback\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleArraysCxxSpecJSI_getValueWithCallback}; + methodMap_[\\"getValueWithPromise\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleArraysCxxSpecJSI_getValueWithPromise}; +} +static jsi::Value __hostFunction_NativeSampleTurboModuleNullableCxxSpecJSI_getConstants(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getConstants(rt); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleNullableCxxSpecJSI_voidFunc(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + static_cast(&turboModule)->voidFunc(rt); + return jsi::Value::undefined(); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleNullableCxxSpecJSI_getBool(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + auto result = static_cast(&turboModule)->getBool(rt, args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].asBool())); + return result ? jsi::Value(std::move(*result)) : jsi::Value::null(); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleNullableCxxSpecJSI_getNumber(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + auto result = static_cast(&turboModule)->getNumber(rt, args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].asNumber())); + return result ? jsi::Value(std::move(*result)) : jsi::Value::null(); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleNullableCxxSpecJSI_getString(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + auto result = static_cast(&turboModule)->getString(rt, args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].asString(rt))); + return result ? jsi::Value(std::move(*result)) : jsi::Value::null(); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleNullableCxxSpecJSI_getArray(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + auto result = static_cast(&turboModule)->getArray(rt, args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].asObject(rt).asArray(rt))); + return result ? jsi::Value(std::move(*result)) : jsi::Value::null(); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleNullableCxxSpecJSI_getObject(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + auto result = static_cast(&turboModule)->getObject(rt, args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].asObject(rt))); + return result ? jsi::Value(std::move(*result)) : jsi::Value::null(); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleNullableCxxSpecJSI_getObjectShape(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + auto result = static_cast(&turboModule)->getObjectShape(rt, args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].asObject(rt))); + return result ? jsi::Value(std::move(*result)) : jsi::Value::null(); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleNullableCxxSpecJSI_getAlias(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + auto result = static_cast(&turboModule)->getAlias(rt, args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].asObject(rt))); + return result ? jsi::Value(std::move(*result)) : jsi::Value::null(); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleNullableCxxSpecJSI_getRootTag(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + auto result = static_cast(&turboModule)->getRootTag(rt, args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].getNumber())); + return result ? jsi::Value(std::move(*result)) : jsi::Value::null(); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleNullableCxxSpecJSI_getValue(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + auto result = static_cast(&turboModule)->getValue(rt, args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].asNumber()), args[1].isNull() || args[1].isUndefined() ? std::nullopt : std::make_optional(args[1].asString(rt)), args[2].isNull() || args[2].isUndefined() ? std::nullopt : std::make_optional(args[2].asObject(rt))); + return result ? jsi::Value(std::move(*result)) : jsi::Value::null(); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleNullableCxxSpecJSI_getValueWithCallback(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + static_cast(&turboModule)->getValueWithCallback(rt, args[0].asObject(rt).asFunction(rt)); + return jsi::Value::undefined(); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleNullableCxxSpecJSI_getValueWithPromise(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + auto result = static_cast(&turboModule)->getValueWithPromise(rt, args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].asBool())); + return result ? jsi::Value(std::move(*result)) : jsi::Value::null(); +} + +NativeSampleTurboModuleNullableCxxSpecJSI::NativeSampleTurboModuleNullableCxxSpecJSI(std::shared_ptr jsInvoker) + : TurboModule(\\"SampleTurboModuleNullable\\", jsInvoker) { + methodMap_[\\"getConstants\\"] = MethodMetadata {0, __hostFunction_NativeSampleTurboModuleNullableCxxSpecJSI_getConstants}; + methodMap_[\\"voidFunc\\"] = MethodMetadata {0, __hostFunction_NativeSampleTurboModuleNullableCxxSpecJSI_voidFunc}; + methodMap_[\\"getBool\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleNullableCxxSpecJSI_getBool}; + methodMap_[\\"getNumber\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleNullableCxxSpecJSI_getNumber}; + methodMap_[\\"getString\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleNullableCxxSpecJSI_getString}; + methodMap_[\\"getArray\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleNullableCxxSpecJSI_getArray}; + methodMap_[\\"getObject\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleNullableCxxSpecJSI_getObject}; + methodMap_[\\"getObjectShape\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleNullableCxxSpecJSI_getObjectShape}; + methodMap_[\\"getAlias\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleNullableCxxSpecJSI_getAlias}; + methodMap_[\\"getRootTag\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleNullableCxxSpecJSI_getRootTag}; + methodMap_[\\"getValue\\"] = MethodMetadata {3, __hostFunction_NativeSampleTurboModuleNullableCxxSpecJSI_getValue}; + methodMap_[\\"getValueWithCallback\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleNullableCxxSpecJSI_getValueWithCallback}; + methodMap_[\\"getValueWithPromise\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleNullableCxxSpecJSI_getValueWithPromise}; +} +static jsi::Value __hostFunction_NativeSampleTurboModuleNullableAndOptionalCxxSpecJSI_getConstants(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getConstants(rt); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleNullableAndOptionalCxxSpecJSI_voidFunc(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + static_cast(&turboModule)->voidFunc(rt); + return jsi::Value::undefined(); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleNullableAndOptionalCxxSpecJSI_getBool(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + auto result = static_cast(&turboModule)->getBool(rt, count < 0 || args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].asBool())); + return result ? jsi::Value(std::move(*result)) : jsi::Value::null(); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleNullableAndOptionalCxxSpecJSI_getNumber(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + auto result = static_cast(&turboModule)->getNumber(rt, count < 0 || args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].asNumber())); + return result ? jsi::Value(std::move(*result)) : jsi::Value::null(); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleNullableAndOptionalCxxSpecJSI_getString(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + auto result = static_cast(&turboModule)->getString(rt, count < 0 || args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].asString(rt))); + return result ? jsi::Value(std::move(*result)) : jsi::Value::null(); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleNullableAndOptionalCxxSpecJSI_getArray(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + auto result = static_cast(&turboModule)->getArray(rt, count < 0 || args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].asObject(rt).asArray(rt))); + return result ? jsi::Value(std::move(*result)) : jsi::Value::null(); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleNullableAndOptionalCxxSpecJSI_getObject(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + auto result = static_cast(&turboModule)->getObject(rt, count < 0 || args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].asObject(rt))); + return result ? jsi::Value(std::move(*result)) : jsi::Value::null(); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleNullableAndOptionalCxxSpecJSI_getObjectShape(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getObjectShape(rt, count < 0 || args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].asObject(rt))); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleNullableAndOptionalCxxSpecJSI_getAlias(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + auto result = static_cast(&turboModule)->getAlias(rt, count < 0 || args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].asObject(rt))); + return result ? jsi::Value(std::move(*result)) : jsi::Value::null(); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleNullableAndOptionalCxxSpecJSI_getRootTag(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + auto result = static_cast(&turboModule)->getRootTag(rt, count < 0 || args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].getNumber())); + return result ? jsi::Value(std::move(*result)) : jsi::Value::null(); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleNullableAndOptionalCxxSpecJSI_getValue(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + auto result = static_cast(&turboModule)->getValue(rt, count < 0 || args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].asNumber()), count < 1 || args[1].isNull() || args[1].isUndefined() ? std::nullopt : std::make_optional(args[1].asString(rt)), count < 2 || args[2].isNull() || args[2].isUndefined() ? std::nullopt : std::make_optional(args[2].asObject(rt))); + return result ? jsi::Value(std::move(*result)) : jsi::Value::null(); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleNullableAndOptionalCxxSpecJSI_getValueWithCallback(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + static_cast(&turboModule)->getValueWithCallback(rt, count < 0 || args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].asObject(rt).asFunction(rt))); + return jsi::Value::undefined(); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleNullableAndOptionalCxxSpecJSI_getValueWithPromise(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + auto result = static_cast(&turboModule)->getValueWithPromise(rt, count < 0 || args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].asBool())); + return result ? jsi::Value(std::move(*result)) : jsi::Value::null(); +} + +NativeSampleTurboModuleNullableAndOptionalCxxSpecJSI::NativeSampleTurboModuleNullableAndOptionalCxxSpecJSI(std::shared_ptr jsInvoker) + : TurboModule(\\"SampleTurboModuleNullableAndOptional\\", jsInvoker) { + methodMap_[\\"getConstants\\"] = MethodMetadata {0, __hostFunction_NativeSampleTurboModuleNullableAndOptionalCxxSpecJSI_getConstants}; + methodMap_[\\"voidFunc\\"] = MethodMetadata {0, __hostFunction_NativeSampleTurboModuleNullableAndOptionalCxxSpecJSI_voidFunc}; + methodMap_[\\"getBool\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleNullableAndOptionalCxxSpecJSI_getBool}; + methodMap_[\\"getNumber\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleNullableAndOptionalCxxSpecJSI_getNumber}; + methodMap_[\\"getString\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleNullableAndOptionalCxxSpecJSI_getString}; + methodMap_[\\"getArray\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleNullableAndOptionalCxxSpecJSI_getArray}; + methodMap_[\\"getObject\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleNullableAndOptionalCxxSpecJSI_getObject}; + methodMap_[\\"getObjectShape\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleNullableAndOptionalCxxSpecJSI_getObjectShape}; + methodMap_[\\"getAlias\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleNullableAndOptionalCxxSpecJSI_getAlias}; + methodMap_[\\"getRootTag\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleNullableAndOptionalCxxSpecJSI_getRootTag}; + methodMap_[\\"getValue\\"] = MethodMetadata {3, __hostFunction_NativeSampleTurboModuleNullableAndOptionalCxxSpecJSI_getValue}; + methodMap_[\\"getValueWithCallback\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleNullableAndOptionalCxxSpecJSI_getValueWithCallback}; + methodMap_[\\"getValueWithPromise\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleNullableAndOptionalCxxSpecJSI_getValueWithPromise}; +} +static jsi::Value __hostFunction_NativeSampleTurboModuleOptionalCxxSpecJSI_getConstants(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getConstants(rt); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleOptionalCxxSpecJSI_voidFunc(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + static_cast(&turboModule)->voidFunc(rt); + return jsi::Value::undefined(); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleOptionalCxxSpecJSI_getBool(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getBool(rt, count < 0 || args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].asBool())); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleOptionalCxxSpecJSI_getNumber(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getNumber(rt, count < 0 || args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].asNumber())); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleOptionalCxxSpecJSI_getString(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getString(rt, count < 0 || args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].asString(rt))); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleOptionalCxxSpecJSI_getArray(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getArray(rt, count < 0 || args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].asObject(rt).asArray(rt))); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleOptionalCxxSpecJSI_getObject(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getObject(rt, count < 0 || args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].asObject(rt))); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleOptionalCxxSpecJSI_getObjectShape(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getObjectShape(rt, count < 0 || args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].asObject(rt))); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleOptionalCxxSpecJSI_getAlias(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getAlias(rt, count < 0 || args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].asObject(rt))); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleOptionalCxxSpecJSI_getRootTag(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getRootTag(rt, count < 0 || args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].getNumber())); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleOptionalCxxSpecJSI_getValue(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getValue(rt, count < 0 || args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].asNumber()), count < 1 || args[1].isNull() || args[1].isUndefined() ? std::nullopt : std::make_optional(args[1].asString(rt)), count < 2 || args[2].isNull() || args[2].isUndefined() ? std::nullopt : std::make_optional(args[2].asObject(rt))); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleOptionalCxxSpecJSI_getValueWithCallback(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + static_cast(&turboModule)->getValueWithCallback(rt, count < 0 || args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].asObject(rt).asFunction(rt))); + return jsi::Value::undefined(); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleOptionalCxxSpecJSI_getValueWithPromise(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getValueWithPromise(rt, count < 0 || args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].asBool())); +} + +NativeSampleTurboModuleOptionalCxxSpecJSI::NativeSampleTurboModuleOptionalCxxSpecJSI(std::shared_ptr jsInvoker) + : TurboModule(\\"SampleTurboModuleOptional\\", jsInvoker) { + methodMap_[\\"getConstants\\"] = MethodMetadata {0, __hostFunction_NativeSampleTurboModuleOptionalCxxSpecJSI_getConstants}; + methodMap_[\\"voidFunc\\"] = MethodMetadata {0, __hostFunction_NativeSampleTurboModuleOptionalCxxSpecJSI_voidFunc}; + methodMap_[\\"getBool\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleOptionalCxxSpecJSI_getBool}; + methodMap_[\\"getNumber\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleOptionalCxxSpecJSI_getNumber}; + methodMap_[\\"getString\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleOptionalCxxSpecJSI_getString}; + methodMap_[\\"getArray\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleOptionalCxxSpecJSI_getArray}; + methodMap_[\\"getObject\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleOptionalCxxSpecJSI_getObject}; + methodMap_[\\"getObjectShape\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleOptionalCxxSpecJSI_getObjectShape}; + methodMap_[\\"getAlias\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleOptionalCxxSpecJSI_getAlias}; + methodMap_[\\"getRootTag\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleOptionalCxxSpecJSI_getRootTag}; + methodMap_[\\"getValue\\"] = MethodMetadata {3, __hostFunction_NativeSampleTurboModuleOptionalCxxSpecJSI_getValue}; + methodMap_[\\"getValueWithCallback\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleOptionalCxxSpecJSI_getValueWithCallback}; + methodMap_[\\"getValueWithPromise\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleOptionalCxxSpecJSI_getValueWithPromise}; +} +static jsi::Value __hostFunction_NativeStringTurboModuleCxxSpecJSI_getString(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getString(rt, args[0].asString(rt)); +} +static jsi::Value __hostFunction_NativeStringTurboModuleCxxSpecJSI_getStringWithAlias(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getStringWithAlias(rt, args[0].asString(rt)); +} + +NativeStringTurboModuleCxxSpecJSI::NativeStringTurboModuleCxxSpecJSI(std::shared_ptr jsInvoker) + : TurboModule(\\"SampleTurboModule\\", jsInvoker) { + methodMap_[\\"getString\\"] = MethodMetadata {1, __hostFunction_NativeStringTurboModuleCxxSpecJSI_getString}; + methodMap_[\\"getStringWithAlias\\"] = MethodMetadata {1, __hostFunction_NativeStringTurboModuleCxxSpecJSI_getStringWithAlias}; +} + + +} // namespace react +} // namespace facebook +" +`; + +exports[`GenerateModuleCpp can generate an implementation file NativeModule specs 1`] = ` +"/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleH.js + */ + +#include \\"RNCodegenModuleFixturesJSI.h\\" + +namespace facebook { +namespace react { + +static jsi::Value __hostFunction_NativeArrayTurboModuleCxxSpecJSI_getArray(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getArray(rt, args[0].asObject(rt).asArray(rt)); +} +static jsi::Value __hostFunction_NativeArrayTurboModuleCxxSpecJSI_getReadOnlyArray(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getReadOnlyArray(rt, args[0].asObject(rt).asArray(rt)); +} +static jsi::Value __hostFunction_NativeArrayTurboModuleCxxSpecJSI_getArrayWithAlias(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getArrayWithAlias(rt, args[0].asObject(rt).asArray(rt), args[1].asObject(rt).asArray(rt)); +} + +NativeArrayTurboModuleCxxSpecJSI::NativeArrayTurboModuleCxxSpecJSI(std::shared_ptr jsInvoker) + : TurboModule(\\"SampleTurboModule\\", jsInvoker) { + methodMap_[\\"getArray\\"] = MethodMetadata {1, __hostFunction_NativeArrayTurboModuleCxxSpecJSI_getArray}; + methodMap_[\\"getReadOnlyArray\\"] = MethodMetadata {1, __hostFunction_NativeArrayTurboModuleCxxSpecJSI_getReadOnlyArray}; + methodMap_[\\"getArrayWithAlias\\"] = MethodMetadata {2, __hostFunction_NativeArrayTurboModuleCxxSpecJSI_getArrayWithAlias}; +} +static jsi::Value __hostFunction_NativeBooleanTurboModuleCxxSpecJSI_getBoolean(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getBoolean(rt, args[0].asBool()); +} +static jsi::Value __hostFunction_NativeBooleanTurboModuleCxxSpecJSI_getBooleanWithAlias(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getBooleanWithAlias(rt, args[0].asBool()); +} + +NativeBooleanTurboModuleCxxSpecJSI::NativeBooleanTurboModuleCxxSpecJSI(std::shared_ptr jsInvoker) + : TurboModule(\\"SampleTurboModule\\", jsInvoker) { + methodMap_[\\"getBoolean\\"] = MethodMetadata {1, __hostFunction_NativeBooleanTurboModuleCxxSpecJSI_getBoolean}; + methodMap_[\\"getBooleanWithAlias\\"] = MethodMetadata {1, __hostFunction_NativeBooleanTurboModuleCxxSpecJSI_getBooleanWithAlias}; +} +static jsi::Value __hostFunction_NativeCallbackTurboModuleCxxSpecJSI_getValueWithCallback(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + static_cast(&turboModule)->getValueWithCallback(rt, args[0].asObject(rt).asFunction(rt)); + return jsi::Value::undefined(); +} +static jsi::Value __hostFunction_NativeCallbackTurboModuleCxxSpecJSI_getValueWithCallbackWithAlias(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + static_cast(&turboModule)->getValueWithCallbackWithAlias(rt, args[0].asObject(rt).asFunction(rt)); + return jsi::Value::undefined(); +} + +NativeCallbackTurboModuleCxxSpecJSI::NativeCallbackTurboModuleCxxSpecJSI(std::shared_ptr jsInvoker) + : TurboModule(\\"SampleTurboModule\\", jsInvoker) { + methodMap_[\\"getValueWithCallback\\"] = MethodMetadata {1, __hostFunction_NativeCallbackTurboModuleCxxSpecJSI_getValueWithCallback}; + methodMap_[\\"getValueWithCallbackWithAlias\\"] = MethodMetadata {1, __hostFunction_NativeCallbackTurboModuleCxxSpecJSI_getValueWithCallbackWithAlias}; +} +static jsi::Value __hostFunction_NativeEnumTurboModuleCxxSpecJSI_getStatusRegular(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getStatusRegular(rt, args[0].asObject(rt)); +} +static jsi::Value __hostFunction_NativeEnumTurboModuleCxxSpecJSI_getStatusStr(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getStatusStr(rt, args[0].asObject(rt)); +} +static jsi::Value __hostFunction_NativeEnumTurboModuleCxxSpecJSI_getStatusNum(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getStatusNum(rt, args[0].asObject(rt)); +} +static jsi::Value __hostFunction_NativeEnumTurboModuleCxxSpecJSI_getStatusFraction(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getStatusFraction(rt, args[0].asObject(rt)); +} +static jsi::Value __hostFunction_NativeEnumTurboModuleCxxSpecJSI_getStateType(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getStateType(rt, args[0].asString(rt), args[1].asString(rt), args[2].asNumber(), args[3].asNumber()); +} +static jsi::Value __hostFunction_NativeEnumTurboModuleCxxSpecJSI_getStateTypeWithEnums(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getStateTypeWithEnums(rt, args[0].asObject(rt)); +} + +NativeEnumTurboModuleCxxSpecJSI::NativeEnumTurboModuleCxxSpecJSI(std::shared_ptr jsInvoker) + : TurboModule(\\"NativeEnumTurboModule\\", jsInvoker) { + methodMap_[\\"getStatusRegular\\"] = MethodMetadata {1, __hostFunction_NativeEnumTurboModuleCxxSpecJSI_getStatusRegular}; + methodMap_[\\"getStatusStr\\"] = MethodMetadata {1, __hostFunction_NativeEnumTurboModuleCxxSpecJSI_getStatusStr}; + methodMap_[\\"getStatusNum\\"] = MethodMetadata {1, __hostFunction_NativeEnumTurboModuleCxxSpecJSI_getStatusNum}; + methodMap_[\\"getStatusFraction\\"] = MethodMetadata {1, __hostFunction_NativeEnumTurboModuleCxxSpecJSI_getStatusFraction}; + methodMap_[\\"getStateType\\"] = MethodMetadata {4, __hostFunction_NativeEnumTurboModuleCxxSpecJSI_getStateType}; + methodMap_[\\"getStateTypeWithEnums\\"] = MethodMetadata {1, __hostFunction_NativeEnumTurboModuleCxxSpecJSI_getStateTypeWithEnums}; +} +static jsi::Value __hostFunction_NativeNullableTurboModuleCxxSpecJSI_getBool(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + auto result = static_cast(&turboModule)->getBool(rt, args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].asBool())); + return result ? jsi::Value(std::move(*result)) : jsi::Value::null(); +} +static jsi::Value __hostFunction_NativeNullableTurboModuleCxxSpecJSI_getNumber(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + auto result = static_cast(&turboModule)->getNumber(rt, args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].asNumber())); + return result ? jsi::Value(std::move(*result)) : jsi::Value::null(); +} +static jsi::Value __hostFunction_NativeNullableTurboModuleCxxSpecJSI_getString(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + auto result = static_cast(&turboModule)->getString(rt, args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].asNumber())); + return result ? jsi::Value(std::move(*result)) : jsi::Value::null(); +} +static jsi::Value __hostFunction_NativeNullableTurboModuleCxxSpecJSI_getArray(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + auto result = static_cast(&turboModule)->getArray(rt, args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].asObject(rt).asArray(rt))); + return result ? jsi::Value(std::move(*result)) : jsi::Value::null(); +} +static jsi::Value __hostFunction_NativeNullableTurboModuleCxxSpecJSI_getObject(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + auto result = static_cast(&turboModule)->getObject(rt, args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].asObject(rt))); + return result ? jsi::Value(std::move(*result)) : jsi::Value::null(); +} +static jsi::Value __hostFunction_NativeNullableTurboModuleCxxSpecJSI_getValueWithPromise(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + auto result = static_cast(&turboModule)->getValueWithPromise(rt); + return result ? jsi::Value(std::move(*result)) : jsi::Value::null(); +} + +NativeNullableTurboModuleCxxSpecJSI::NativeNullableTurboModuleCxxSpecJSI(std::shared_ptr jsInvoker) + : TurboModule(\\"SampleTurboModule\\", jsInvoker) { + methodMap_[\\"getBool\\"] = MethodMetadata {1, __hostFunction_NativeNullableTurboModuleCxxSpecJSI_getBool}; + methodMap_[\\"getNumber\\"] = MethodMetadata {1, __hostFunction_NativeNullableTurboModuleCxxSpecJSI_getNumber}; + methodMap_[\\"getString\\"] = MethodMetadata {1, __hostFunction_NativeNullableTurboModuleCxxSpecJSI_getString}; + methodMap_[\\"getArray\\"] = MethodMetadata {1, __hostFunction_NativeNullableTurboModuleCxxSpecJSI_getArray}; + methodMap_[\\"getObject\\"] = MethodMetadata {1, __hostFunction_NativeNullableTurboModuleCxxSpecJSI_getObject}; + methodMap_[\\"getValueWithPromise\\"] = MethodMetadata {0, __hostFunction_NativeNullableTurboModuleCxxSpecJSI_getValueWithPromise}; +} +static jsi::Value __hostFunction_NativeNumberTurboModuleCxxSpecJSI_getNumber(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getNumber(rt, args[0].asNumber()); +} +static jsi::Value __hostFunction_NativeNumberTurboModuleCxxSpecJSI_getNumberWithAlias(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getNumberWithAlias(rt, args[0].asNumber()); +} + +NativeNumberTurboModuleCxxSpecJSI::NativeNumberTurboModuleCxxSpecJSI(std::shared_ptr jsInvoker) + : TurboModule(\\"SampleTurboModule\\", jsInvoker) { + methodMap_[\\"getNumber\\"] = MethodMetadata {1, __hostFunction_NativeNumberTurboModuleCxxSpecJSI_getNumber}; + methodMap_[\\"getNumberWithAlias\\"] = MethodMetadata {1, __hostFunction_NativeNumberTurboModuleCxxSpecJSI_getNumberWithAlias}; +} +static jsi::Value __hostFunction_NativeObjectTurboModuleCxxSpecJSI_getGenericObject(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getGenericObject(rt, args[0].asObject(rt)); +} +static jsi::Value __hostFunction_NativeObjectTurboModuleCxxSpecJSI_getGenericObjectReadOnly(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getGenericObjectReadOnly(rt, args[0].asObject(rt)); +} +static jsi::Value __hostFunction_NativeObjectTurboModuleCxxSpecJSI_getGenericObjectWithAlias(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getGenericObjectWithAlias(rt, args[0].asObject(rt)); +} +static jsi::Value __hostFunction_NativeObjectTurboModuleCxxSpecJSI_difficultObject(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->difficultObject(rt, args[0].asObject(rt)); +} +static jsi::Value __hostFunction_NativeObjectTurboModuleCxxSpecJSI_getConstants(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getConstants(rt); +} + +NativeObjectTurboModuleCxxSpecJSI::NativeObjectTurboModuleCxxSpecJSI(std::shared_ptr jsInvoker) + : TurboModule(\\"SampleTurboModule\\", jsInvoker) { + methodMap_[\\"getGenericObject\\"] = MethodMetadata {1, __hostFunction_NativeObjectTurboModuleCxxSpecJSI_getGenericObject}; + methodMap_[\\"getGenericObjectReadOnly\\"] = MethodMetadata {1, __hostFunction_NativeObjectTurboModuleCxxSpecJSI_getGenericObjectReadOnly}; + methodMap_[\\"getGenericObjectWithAlias\\"] = MethodMetadata {1, __hostFunction_NativeObjectTurboModuleCxxSpecJSI_getGenericObjectWithAlias}; + methodMap_[\\"difficultObject\\"] = MethodMetadata {1, __hostFunction_NativeObjectTurboModuleCxxSpecJSI_difficultObject}; + methodMap_[\\"getConstants\\"] = MethodMetadata {0, __hostFunction_NativeObjectTurboModuleCxxSpecJSI_getConstants}; +} +static jsi::Value __hostFunction_NativeOptionalObjectTurboModuleCxxSpecJSI_getConstants(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getConstants(rt); +} + +NativeOptionalObjectTurboModuleCxxSpecJSI::NativeOptionalObjectTurboModuleCxxSpecJSI(std::shared_ptr jsInvoker) + : TurboModule(\\"SampleTurboModule\\", jsInvoker) { + methodMap_[\\"getConstants\\"] = MethodMetadata {0, __hostFunction_NativeOptionalObjectTurboModuleCxxSpecJSI_getConstants}; +} +static jsi::Value __hostFunction_NativePartialAnnotationTurboModuleCxxSpecJSI_getSomeObj(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getSomeObj(rt); +} +static jsi::Value __hostFunction_NativePartialAnnotationTurboModuleCxxSpecJSI_getPartialSomeObj(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getPartialSomeObj(rt); +} +static jsi::Value __hostFunction_NativePartialAnnotationTurboModuleCxxSpecJSI_getSomeObjFromPartialSomeObj(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getSomeObjFromPartialSomeObj(rt, args[0].asObject(rt)); +} +static jsi::Value __hostFunction_NativePartialAnnotationTurboModuleCxxSpecJSI_getPartialPartial(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getPartialPartial(rt, args[0].asObject(rt), args[1].asObject(rt)); +} + +NativePartialAnnotationTurboModuleCxxSpecJSI::NativePartialAnnotationTurboModuleCxxSpecJSI(std::shared_ptr jsInvoker) + : TurboModule(\\"NativePartialAnnotationTurboModule\\", jsInvoker) { + methodMap_[\\"getSomeObj\\"] = MethodMetadata {0, __hostFunction_NativePartialAnnotationTurboModuleCxxSpecJSI_getSomeObj}; + methodMap_[\\"getPartialSomeObj\\"] = MethodMetadata {0, __hostFunction_NativePartialAnnotationTurboModuleCxxSpecJSI_getPartialSomeObj}; + methodMap_[\\"getSomeObjFromPartialSomeObj\\"] = MethodMetadata {1, __hostFunction_NativePartialAnnotationTurboModuleCxxSpecJSI_getSomeObjFromPartialSomeObj}; + methodMap_[\\"getPartialPartial\\"] = MethodMetadata {2, __hostFunction_NativePartialAnnotationTurboModuleCxxSpecJSI_getPartialPartial}; +} +static jsi::Value __hostFunction_NativePromiseTurboModuleCxxSpecJSI_getValueWithPromise(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getValueWithPromise(rt, args[0].asBool()); +} +static jsi::Value __hostFunction_NativePromiseTurboModuleCxxSpecJSI_getValueWithPromiseWithAlias(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getValueWithPromiseWithAlias(rt, args[0].asString(rt)); +} + +NativePromiseTurboModuleCxxSpecJSI::NativePromiseTurboModuleCxxSpecJSI(std::shared_ptr jsInvoker) + : TurboModule(\\"SampleTurboModule\\", jsInvoker) { + methodMap_[\\"getValueWithPromise\\"] = MethodMetadata {1, __hostFunction_NativePromiseTurboModuleCxxSpecJSI_getValueWithPromise}; + methodMap_[\\"getValueWithPromiseWithAlias\\"] = MethodMetadata {1, __hostFunction_NativePromiseTurboModuleCxxSpecJSI_getValueWithPromiseWithAlias}; +} +static jsi::Value __hostFunction_NativeSampleTurboModuleCxxSpecJSI_getConstants(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getConstants(rt); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleCxxSpecJSI_voidFunc(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + static_cast(&turboModule)->voidFunc(rt); + return jsi::Value::undefined(); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleCxxSpecJSI_getBool(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getBool(rt, args[0].asBool()); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleCxxSpecJSI_getNumber(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getNumber(rt, args[0].asNumber()); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleCxxSpecJSI_getString(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getString(rt, args[0].asString(rt)); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleCxxSpecJSI_getArray(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getArray(rt, args[0].asObject(rt).asArray(rt)); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleCxxSpecJSI_getObject(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getObject(rt, args[0].asObject(rt)); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleCxxSpecJSI_getObjectShape(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getObjectShape(rt, args[0].asObject(rt)); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleCxxSpecJSI_getAlias(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getAlias(rt, args[0].asObject(rt)); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleCxxSpecJSI_getRootTag(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getRootTag(rt, args[0].getNumber()); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleCxxSpecJSI_getValue(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getValue(rt, args[0].asNumber(), args[1].asString(rt), args[2].asObject(rt)); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleCxxSpecJSI_getValueWithCallback(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + static_cast(&turboModule)->getValueWithCallback(rt, args[0].asObject(rt).asFunction(rt)); + return jsi::Value::undefined(); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleCxxSpecJSI_getValueWithPromise(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getValueWithPromise(rt, args[0].asBool()); +} + +NativeSampleTurboModuleCxxSpecJSI::NativeSampleTurboModuleCxxSpecJSI(std::shared_ptr jsInvoker) + : TurboModule(\\"SampleTurboModule\\", jsInvoker) { + methodMap_[\\"getConstants\\"] = MethodMetadata {0, __hostFunction_NativeSampleTurboModuleCxxSpecJSI_getConstants}; + methodMap_[\\"voidFunc\\"] = MethodMetadata {0, __hostFunction_NativeSampleTurboModuleCxxSpecJSI_voidFunc}; + methodMap_[\\"getBool\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleCxxSpecJSI_getBool}; + methodMap_[\\"getNumber\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleCxxSpecJSI_getNumber}; + methodMap_[\\"getString\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleCxxSpecJSI_getString}; + methodMap_[\\"getArray\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleCxxSpecJSI_getArray}; + methodMap_[\\"getObject\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleCxxSpecJSI_getObject}; + methodMap_[\\"getObjectShape\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleCxxSpecJSI_getObjectShape}; + methodMap_[\\"getAlias\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleCxxSpecJSI_getAlias}; + methodMap_[\\"getRootTag\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleCxxSpecJSI_getRootTag}; + methodMap_[\\"getValue\\"] = MethodMetadata {3, __hostFunction_NativeSampleTurboModuleCxxSpecJSI_getValue}; + methodMap_[\\"getValueWithCallback\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleCxxSpecJSI_getValueWithCallback}; + methodMap_[\\"getValueWithPromise\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleCxxSpecJSI_getValueWithPromise}; +} +static jsi::Value __hostFunction_NativeSampleTurboModuleArraysCxxSpecJSI_getConstants(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getConstants(rt); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleArraysCxxSpecJSI_voidFunc(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + static_cast(&turboModule)->voidFunc(rt); + return jsi::Value::undefined(); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleArraysCxxSpecJSI_getBool(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getBool(rt, args[0].asObject(rt).asArray(rt)); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleArraysCxxSpecJSI_getNumber(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getNumber(rt, args[0].asObject(rt).asArray(rt)); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleArraysCxxSpecJSI_getString(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getString(rt, args[0].asObject(rt).asArray(rt)); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleArraysCxxSpecJSI_getArray(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getArray(rt, args[0].asObject(rt).asArray(rt)); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleArraysCxxSpecJSI_getObject(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getObject(rt, args[0].asObject(rt).asArray(rt)); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleArraysCxxSpecJSI_getObjectShape(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getObjectShape(rt, args[0].asObject(rt).asArray(rt)); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleArraysCxxSpecJSI_getAlias(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getAlias(rt, args[0].asObject(rt).asArray(rt)); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleArraysCxxSpecJSI_getRootTag(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getRootTag(rt, args[0].asObject(rt).asArray(rt)); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleArraysCxxSpecJSI_getValue(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getValue(rt, args[0].asObject(rt).asArray(rt), args[1].asObject(rt).asArray(rt), args[2].asObject(rt).asArray(rt)); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleArraysCxxSpecJSI_getValueWithCallback(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + static_cast(&turboModule)->getValueWithCallback(rt, args[0].asObject(rt).asFunction(rt)); + return jsi::Value::undefined(); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleArraysCxxSpecJSI_getValueWithPromise(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getValueWithPromise(rt, args[0].asObject(rt).asArray(rt)); +} + +NativeSampleTurboModuleArraysCxxSpecJSI::NativeSampleTurboModuleArraysCxxSpecJSI(std::shared_ptr jsInvoker) + : TurboModule(\\"SampleTurboModuleArrays\\", jsInvoker) { + methodMap_[\\"getConstants\\"] = MethodMetadata {0, __hostFunction_NativeSampleTurboModuleArraysCxxSpecJSI_getConstants}; + methodMap_[\\"voidFunc\\"] = MethodMetadata {0, __hostFunction_NativeSampleTurboModuleArraysCxxSpecJSI_voidFunc}; + methodMap_[\\"getBool\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleArraysCxxSpecJSI_getBool}; + methodMap_[\\"getNumber\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleArraysCxxSpecJSI_getNumber}; + methodMap_[\\"getString\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleArraysCxxSpecJSI_getString}; + methodMap_[\\"getArray\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleArraysCxxSpecJSI_getArray}; + methodMap_[\\"getObject\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleArraysCxxSpecJSI_getObject}; + methodMap_[\\"getObjectShape\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleArraysCxxSpecJSI_getObjectShape}; + methodMap_[\\"getAlias\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleArraysCxxSpecJSI_getAlias}; + methodMap_[\\"getRootTag\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleArraysCxxSpecJSI_getRootTag}; + methodMap_[\\"getValue\\"] = MethodMetadata {3, __hostFunction_NativeSampleTurboModuleArraysCxxSpecJSI_getValue}; + methodMap_[\\"getValueWithCallback\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleArraysCxxSpecJSI_getValueWithCallback}; + methodMap_[\\"getValueWithPromise\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleArraysCxxSpecJSI_getValueWithPromise}; +} +static jsi::Value __hostFunction_NativeSampleTurboModuleNullableCxxSpecJSI_getConstants(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getConstants(rt); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleNullableCxxSpecJSI_voidFunc(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + static_cast(&turboModule)->voidFunc(rt); + return jsi::Value::undefined(); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleNullableCxxSpecJSI_getBool(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + auto result = static_cast(&turboModule)->getBool(rt, args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].asBool())); + return result ? jsi::Value(std::move(*result)) : jsi::Value::null(); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleNullableCxxSpecJSI_getNumber(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + auto result = static_cast(&turboModule)->getNumber(rt, args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].asNumber())); + return result ? jsi::Value(std::move(*result)) : jsi::Value::null(); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleNullableCxxSpecJSI_getString(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + auto result = static_cast(&turboModule)->getString(rt, args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].asString(rt))); + return result ? jsi::Value(std::move(*result)) : jsi::Value::null(); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleNullableCxxSpecJSI_getArray(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + auto result = static_cast(&turboModule)->getArray(rt, args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].asObject(rt).asArray(rt))); + return result ? jsi::Value(std::move(*result)) : jsi::Value::null(); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleNullableCxxSpecJSI_getObject(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + auto result = static_cast(&turboModule)->getObject(rt, args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].asObject(rt))); + return result ? jsi::Value(std::move(*result)) : jsi::Value::null(); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleNullableCxxSpecJSI_getObjectShape(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + auto result = static_cast(&turboModule)->getObjectShape(rt, args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].asObject(rt))); + return result ? jsi::Value(std::move(*result)) : jsi::Value::null(); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleNullableCxxSpecJSI_getAlias(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + auto result = static_cast(&turboModule)->getAlias(rt, args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].asObject(rt))); + return result ? jsi::Value(std::move(*result)) : jsi::Value::null(); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleNullableCxxSpecJSI_getRootTag(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + auto result = static_cast(&turboModule)->getRootTag(rt, args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].getNumber())); + return result ? jsi::Value(std::move(*result)) : jsi::Value::null(); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleNullableCxxSpecJSI_getValue(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + auto result = static_cast(&turboModule)->getValue(rt, args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].asNumber()), args[1].isNull() || args[1].isUndefined() ? std::nullopt : std::make_optional(args[1].asString(rt)), args[2].isNull() || args[2].isUndefined() ? std::nullopt : std::make_optional(args[2].asObject(rt))); + return result ? jsi::Value(std::move(*result)) : jsi::Value::null(); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleNullableCxxSpecJSI_getValueWithCallback(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + static_cast(&turboModule)->getValueWithCallback(rt, args[0].asObject(rt).asFunction(rt)); + return jsi::Value::undefined(); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleNullableCxxSpecJSI_getValueWithPromise(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + auto result = static_cast(&turboModule)->getValueWithPromise(rt, args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].asBool())); + return result ? jsi::Value(std::move(*result)) : jsi::Value::null(); +} + +NativeSampleTurboModuleNullableCxxSpecJSI::NativeSampleTurboModuleNullableCxxSpecJSI(std::shared_ptr jsInvoker) + : TurboModule(\\"SampleTurboModuleNullable\\", jsInvoker) { + methodMap_[\\"getConstants\\"] = MethodMetadata {0, __hostFunction_NativeSampleTurboModuleNullableCxxSpecJSI_getConstants}; + methodMap_[\\"voidFunc\\"] = MethodMetadata {0, __hostFunction_NativeSampleTurboModuleNullableCxxSpecJSI_voidFunc}; + methodMap_[\\"getBool\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleNullableCxxSpecJSI_getBool}; + methodMap_[\\"getNumber\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleNullableCxxSpecJSI_getNumber}; + methodMap_[\\"getString\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleNullableCxxSpecJSI_getString}; + methodMap_[\\"getArray\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleNullableCxxSpecJSI_getArray}; + methodMap_[\\"getObject\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleNullableCxxSpecJSI_getObject}; + methodMap_[\\"getObjectShape\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleNullableCxxSpecJSI_getObjectShape}; + methodMap_[\\"getAlias\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleNullableCxxSpecJSI_getAlias}; + methodMap_[\\"getRootTag\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleNullableCxxSpecJSI_getRootTag}; + methodMap_[\\"getValue\\"] = MethodMetadata {3, __hostFunction_NativeSampleTurboModuleNullableCxxSpecJSI_getValue}; + methodMap_[\\"getValueWithCallback\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleNullableCxxSpecJSI_getValueWithCallback}; + methodMap_[\\"getValueWithPromise\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleNullableCxxSpecJSI_getValueWithPromise}; +} +static jsi::Value __hostFunction_NativeSampleTurboModuleNullableAndOptionalCxxSpecJSI_getConstants(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getConstants(rt); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleNullableAndOptionalCxxSpecJSI_voidFunc(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + static_cast(&turboModule)->voidFunc(rt); + return jsi::Value::undefined(); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleNullableAndOptionalCxxSpecJSI_getBool(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + auto result = static_cast(&turboModule)->getBool(rt, count < 0 || args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].asBool())); + return result ? jsi::Value(std::move(*result)) : jsi::Value::null(); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleNullableAndOptionalCxxSpecJSI_getNumber(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + auto result = static_cast(&turboModule)->getNumber(rt, count < 0 || args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].asNumber())); + return result ? jsi::Value(std::move(*result)) : jsi::Value::null(); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleNullableAndOptionalCxxSpecJSI_getString(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + auto result = static_cast(&turboModule)->getString(rt, count < 0 || args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].asString(rt))); + return result ? jsi::Value(std::move(*result)) : jsi::Value::null(); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleNullableAndOptionalCxxSpecJSI_getArray(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + auto result = static_cast(&turboModule)->getArray(rt, count < 0 || args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].asObject(rt).asArray(rt))); + return result ? jsi::Value(std::move(*result)) : jsi::Value::null(); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleNullableAndOptionalCxxSpecJSI_getObject(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + auto result = static_cast(&turboModule)->getObject(rt, count < 0 || args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].asObject(rt))); + return result ? jsi::Value(std::move(*result)) : jsi::Value::null(); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleNullableAndOptionalCxxSpecJSI_getObjectShape(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getObjectShape(rt, count < 0 || args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].asObject(rt))); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleNullableAndOptionalCxxSpecJSI_getAlias(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + auto result = static_cast(&turboModule)->getAlias(rt, count < 0 || args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].asObject(rt))); + return result ? jsi::Value(std::move(*result)) : jsi::Value::null(); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleNullableAndOptionalCxxSpecJSI_getRootTag(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + auto result = static_cast(&turboModule)->getRootTag(rt, count < 0 || args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].getNumber())); + return result ? jsi::Value(std::move(*result)) : jsi::Value::null(); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleNullableAndOptionalCxxSpecJSI_getValue(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + auto result = static_cast(&turboModule)->getValue(rt, count < 0 || args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].asNumber()), count < 1 || args[1].isNull() || args[1].isUndefined() ? std::nullopt : std::make_optional(args[1].asString(rt)), count < 2 || args[2].isNull() || args[2].isUndefined() ? std::nullopt : std::make_optional(args[2].asObject(rt))); + return result ? jsi::Value(std::move(*result)) : jsi::Value::null(); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleNullableAndOptionalCxxSpecJSI_getValueWithCallback(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + static_cast(&turboModule)->getValueWithCallback(rt, count < 0 || args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].asObject(rt).asFunction(rt))); + return jsi::Value::undefined(); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleNullableAndOptionalCxxSpecJSI_getValueWithPromise(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + auto result = static_cast(&turboModule)->getValueWithPromise(rt, count < 0 || args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].asBool())); + return result ? jsi::Value(std::move(*result)) : jsi::Value::null(); +} + +NativeSampleTurboModuleNullableAndOptionalCxxSpecJSI::NativeSampleTurboModuleNullableAndOptionalCxxSpecJSI(std::shared_ptr jsInvoker) + : TurboModule(\\"SampleTurboModuleNullableAndOptional\\", jsInvoker) { + methodMap_[\\"getConstants\\"] = MethodMetadata {0, __hostFunction_NativeSampleTurboModuleNullableAndOptionalCxxSpecJSI_getConstants}; + methodMap_[\\"voidFunc\\"] = MethodMetadata {0, __hostFunction_NativeSampleTurboModuleNullableAndOptionalCxxSpecJSI_voidFunc}; + methodMap_[\\"getBool\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleNullableAndOptionalCxxSpecJSI_getBool}; + methodMap_[\\"getNumber\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleNullableAndOptionalCxxSpecJSI_getNumber}; + methodMap_[\\"getString\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleNullableAndOptionalCxxSpecJSI_getString}; + methodMap_[\\"getArray\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleNullableAndOptionalCxxSpecJSI_getArray}; + methodMap_[\\"getObject\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleNullableAndOptionalCxxSpecJSI_getObject}; + methodMap_[\\"getObjectShape\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleNullableAndOptionalCxxSpecJSI_getObjectShape}; + methodMap_[\\"getAlias\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleNullableAndOptionalCxxSpecJSI_getAlias}; + methodMap_[\\"getRootTag\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleNullableAndOptionalCxxSpecJSI_getRootTag}; + methodMap_[\\"getValue\\"] = MethodMetadata {3, __hostFunction_NativeSampleTurboModuleNullableAndOptionalCxxSpecJSI_getValue}; + methodMap_[\\"getValueWithCallback\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleNullableAndOptionalCxxSpecJSI_getValueWithCallback}; + methodMap_[\\"getValueWithPromise\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleNullableAndOptionalCxxSpecJSI_getValueWithPromise}; +} +static jsi::Value __hostFunction_NativeSampleTurboModuleOptionalCxxSpecJSI_getConstants(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getConstants(rt); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleOptionalCxxSpecJSI_voidFunc(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + static_cast(&turboModule)->voidFunc(rt); + return jsi::Value::undefined(); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleOptionalCxxSpecJSI_getBool(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getBool(rt, count < 0 || args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].asBool())); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleOptionalCxxSpecJSI_getNumber(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getNumber(rt, count < 0 || args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].asNumber())); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleOptionalCxxSpecJSI_getString(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getString(rt, count < 0 || args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].asString(rt))); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleOptionalCxxSpecJSI_getArray(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getArray(rt, count < 0 || args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].asObject(rt).asArray(rt))); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleOptionalCxxSpecJSI_getObject(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getObject(rt, count < 0 || args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].asObject(rt))); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleOptionalCxxSpecJSI_getObjectShape(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getObjectShape(rt, count < 0 || args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].asObject(rt))); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleOptionalCxxSpecJSI_getAlias(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getAlias(rt, count < 0 || args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].asObject(rt))); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleOptionalCxxSpecJSI_getRootTag(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getRootTag(rt, count < 0 || args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].getNumber())); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleOptionalCxxSpecJSI_getValue(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getValue(rt, count < 0 || args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].asNumber()), count < 1 || args[1].isNull() || args[1].isUndefined() ? std::nullopt : std::make_optional(args[1].asString(rt)), count < 2 || args[2].isNull() || args[2].isUndefined() ? std::nullopt : std::make_optional(args[2].asObject(rt))); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleOptionalCxxSpecJSI_getValueWithCallback(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + static_cast(&turboModule)->getValueWithCallback(rt, count < 0 || args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].asObject(rt).asFunction(rt))); + return jsi::Value::undefined(); +} +static jsi::Value __hostFunction_NativeSampleTurboModuleOptionalCxxSpecJSI_getValueWithPromise(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getValueWithPromise(rt, count < 0 || args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].asBool())); +} + +NativeSampleTurboModuleOptionalCxxSpecJSI::NativeSampleTurboModuleOptionalCxxSpecJSI(std::shared_ptr jsInvoker) + : TurboModule(\\"SampleTurboModuleOptional\\", jsInvoker) { + methodMap_[\\"getConstants\\"] = MethodMetadata {0, __hostFunction_NativeSampleTurboModuleOptionalCxxSpecJSI_getConstants}; + methodMap_[\\"voidFunc\\"] = MethodMetadata {0, __hostFunction_NativeSampleTurboModuleOptionalCxxSpecJSI_voidFunc}; + methodMap_[\\"getBool\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleOptionalCxxSpecJSI_getBool}; + methodMap_[\\"getNumber\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleOptionalCxxSpecJSI_getNumber}; + methodMap_[\\"getString\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleOptionalCxxSpecJSI_getString}; + methodMap_[\\"getArray\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleOptionalCxxSpecJSI_getArray}; + methodMap_[\\"getObject\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleOptionalCxxSpecJSI_getObject}; + methodMap_[\\"getObjectShape\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleOptionalCxxSpecJSI_getObjectShape}; + methodMap_[\\"getAlias\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleOptionalCxxSpecJSI_getAlias}; + methodMap_[\\"getRootTag\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleOptionalCxxSpecJSI_getRootTag}; + methodMap_[\\"getValue\\"] = MethodMetadata {3, __hostFunction_NativeSampleTurboModuleOptionalCxxSpecJSI_getValue}; + methodMap_[\\"getValueWithCallback\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleOptionalCxxSpecJSI_getValueWithCallback}; + methodMap_[\\"getValueWithPromise\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleOptionalCxxSpecJSI_getValueWithPromise}; +} +static jsi::Value __hostFunction_NativeStringTurboModuleCxxSpecJSI_getString(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getString(rt, args[0].asString(rt)); +} +static jsi::Value __hostFunction_NativeStringTurboModuleCxxSpecJSI_getStringWithAlias(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getStringWithAlias(rt, args[0].asString(rt)); +} + +NativeStringTurboModuleCxxSpecJSI::NativeStringTurboModuleCxxSpecJSI(std::shared_ptr jsInvoker) + : TurboModule(\\"SampleTurboModule\\", jsInvoker) { + methodMap_[\\"getString\\"] = MethodMetadata {1, __hostFunction_NativeStringTurboModuleCxxSpecJSI_getString}; + methodMap_[\\"getStringWithAlias\\"] = MethodMetadata {1, __hostFunction_NativeStringTurboModuleCxxSpecJSI_getStringWithAlias}; +} + + +} // namespace react +} // namespace facebook +" +`; diff --git a/packages/react-native-codegen/e2e/__tests__/modules/__snapshots__/GenerateModuleH-test.js.snap b/packages/react-native-codegen/e2e/__tests__/modules/__snapshots__/GenerateModuleH-test.js.snap new file mode 100644 index 00000000000000..20b3a737fbee08 --- /dev/null +++ b/packages/react-native-codegen/e2e/__tests__/modules/__snapshots__/GenerateModuleH-test.js.snap @@ -0,0 +1,3601 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`GenerateModuleH can generate a header file NativeModule specs 1`] = ` +"/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleH.js + */ + +#pragma once + +#include +#include + +namespace facebook { +namespace react { + +class JSI_EXPORT NativeArrayTurboModuleCxxSpecJSI : public TurboModule { +protected: + NativeArrayTurboModuleCxxSpecJSI(std::shared_ptr jsInvoker); + +public: + virtual jsi::Array getArray(jsi::Runtime &rt, jsi::Array a) = 0; + virtual jsi::Array getReadOnlyArray(jsi::Runtime &rt, jsi::Array a) = 0; + virtual jsi::Array getArrayWithAlias(jsi::Runtime &rt, jsi::Array a, jsi::Array b) = 0; + +}; + +template +class JSI_EXPORT NativeArrayTurboModuleCxxSpec : public TurboModule { +public: + jsi::Value get(jsi::Runtime &rt, const jsi::PropNameID &propName) override { + return delegate_.get(rt, propName); + } + +protected: + NativeArrayTurboModuleCxxSpec(std::shared_ptr jsInvoker) + : TurboModule(\\"SampleTurboModule\\", jsInvoker), + delegate_(static_cast(this), jsInvoker) {} + +private: + class Delegate : public NativeArrayTurboModuleCxxSpecJSI { + public: + Delegate(T *instance, std::shared_ptr jsInvoker) : + NativeArrayTurboModuleCxxSpecJSI(std::move(jsInvoker)), instance_(instance) {} + + jsi::Array getArray(jsi::Runtime &rt, jsi::Array a) override { + static_assert( + bridging::getParameterCount(&T::getArray) == 2, + \\"Expected getArray(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getArray, jsInvoker_, instance_, std::move(a)); + } + jsi::Array getReadOnlyArray(jsi::Runtime &rt, jsi::Array a) override { + static_assert( + bridging::getParameterCount(&T::getReadOnlyArray) == 2, + \\"Expected getReadOnlyArray(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getReadOnlyArray, jsInvoker_, instance_, std::move(a)); + } + jsi::Array getArrayWithAlias(jsi::Runtime &rt, jsi::Array a, jsi::Array b) override { + static_assert( + bridging::getParameterCount(&T::getArrayWithAlias) == 3, + \\"Expected getArrayWithAlias(...) to have 3 parameters\\"); + + return bridging::callFromJs( + rt, &T::getArrayWithAlias, jsInvoker_, instance_, std::move(a), std::move(b)); + } + + private: + T *instance_; + }; + + Delegate delegate_; +}; + +class JSI_EXPORT NativeBooleanTurboModuleCxxSpecJSI : public TurboModule { +protected: + NativeBooleanTurboModuleCxxSpecJSI(std::shared_ptr jsInvoker); + +public: + virtual bool getBoolean(jsi::Runtime &rt, bool arg) = 0; + virtual bool getBooleanWithAlias(jsi::Runtime &rt, bool arg) = 0; + +}; + +template +class JSI_EXPORT NativeBooleanTurboModuleCxxSpec : public TurboModule { +public: + jsi::Value get(jsi::Runtime &rt, const jsi::PropNameID &propName) override { + return delegate_.get(rt, propName); + } + +protected: + NativeBooleanTurboModuleCxxSpec(std::shared_ptr jsInvoker) + : TurboModule(\\"SampleTurboModule\\", jsInvoker), + delegate_(static_cast(this), jsInvoker) {} + +private: + class Delegate : public NativeBooleanTurboModuleCxxSpecJSI { + public: + Delegate(T *instance, std::shared_ptr jsInvoker) : + NativeBooleanTurboModuleCxxSpecJSI(std::move(jsInvoker)), instance_(instance) {} + + bool getBoolean(jsi::Runtime &rt, bool arg) override { + static_assert( + bridging::getParameterCount(&T::getBoolean) == 2, + \\"Expected getBoolean(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getBoolean, jsInvoker_, instance_, std::move(arg)); + } + bool getBooleanWithAlias(jsi::Runtime &rt, bool arg) override { + static_assert( + bridging::getParameterCount(&T::getBooleanWithAlias) == 2, + \\"Expected getBooleanWithAlias(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getBooleanWithAlias, jsInvoker_, instance_, std::move(arg)); + } + + private: + T *instance_; + }; + + Delegate delegate_; +}; + +class JSI_EXPORT NativeCallbackTurboModuleCxxSpecJSI : public TurboModule { +protected: + NativeCallbackTurboModuleCxxSpecJSI(std::shared_ptr jsInvoker); + +public: + virtual void getValueWithCallback(jsi::Runtime &rt, jsi::Function callback) = 0; + virtual void getValueWithCallbackWithAlias(jsi::Runtime &rt, jsi::Function c) = 0; + +}; + +template +class JSI_EXPORT NativeCallbackTurboModuleCxxSpec : public TurboModule { +public: + jsi::Value get(jsi::Runtime &rt, const jsi::PropNameID &propName) override { + return delegate_.get(rt, propName); + } + +protected: + NativeCallbackTurboModuleCxxSpec(std::shared_ptr jsInvoker) + : TurboModule(\\"SampleTurboModule\\", jsInvoker), + delegate_(static_cast(this), jsInvoker) {} + +private: + class Delegate : public NativeCallbackTurboModuleCxxSpecJSI { + public: + Delegate(T *instance, std::shared_ptr jsInvoker) : + NativeCallbackTurboModuleCxxSpecJSI(std::move(jsInvoker)), instance_(instance) {} + + void getValueWithCallback(jsi::Runtime &rt, jsi::Function callback) override { + static_assert( + bridging::getParameterCount(&T::getValueWithCallback) == 2, + \\"Expected getValueWithCallback(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getValueWithCallback, jsInvoker_, instance_, std::move(callback)); + } + void getValueWithCallbackWithAlias(jsi::Runtime &rt, jsi::Function c) override { + static_assert( + bridging::getParameterCount(&T::getValueWithCallbackWithAlias) == 2, + \\"Expected getValueWithCallbackWithAlias(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getValueWithCallbackWithAlias, jsInvoker_, instance_, std::move(c)); + } + + private: + T *instance_; + }; + + Delegate delegate_; +}; + +#pragma mark - NativeEnumTurboModuleBaseStateType + +template +struct NativeEnumTurboModuleBaseStateType { + P0 state; + bool operator==(const NativeEnumTurboModuleBaseStateType &other) const { + return state == other.state; + } +}; + +template +struct NativeEnumTurboModuleBaseStateTypeBridging { + static NativeEnumTurboModuleBaseStateType fromJs( + jsi::Runtime &rt, + const jsi::Object &value, + const std::shared_ptr &jsInvoker) { + NativeEnumTurboModuleBaseStateType result{ + bridging::fromJs(rt, value.getProperty(rt, \\"state\\"), jsInvoker)}; + return result; + } + +#ifdef DEBUG + static jsi::String stateToJs(jsi::Runtime &rt, P0 value) { + return bridging::toJs(rt, value); + } +#endif + + static jsi::Object toJs( + jsi::Runtime &rt, + const NativeEnumTurboModuleBaseStateType &value, + const std::shared_ptr &jsInvoker) { + auto result = facebook::jsi::Object(rt); + result.setProperty(rt, \\"state\\", bridging::toJs(rt, value.state, jsInvoker)); + return result; + } + }; + + +#pragma mark - NativeEnumTurboModuleBaseStateTypeWithEnums + +template +struct NativeEnumTurboModuleBaseStateTypeWithEnums { + P0 state; + P1 regular; + P2 str; + P3 num; + P4 fraction; + bool operator==(const NativeEnumTurboModuleBaseStateTypeWithEnums &other) const { + return state == other.state && regular == other.regular && str == other.str && num == other.num && fraction == other.fraction; + } +}; + +template +struct NativeEnumTurboModuleBaseStateTypeWithEnumsBridging { + static NativeEnumTurboModuleBaseStateTypeWithEnums fromJs( + jsi::Runtime &rt, + const jsi::Object &value, + const std::shared_ptr &jsInvoker) { + NativeEnumTurboModuleBaseStateTypeWithEnums result{ + bridging::fromJs(rt, value.getProperty(rt, \\"state\\"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, \\"regular\\"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, \\"str\\"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, \\"num\\"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, \\"fraction\\"), jsInvoker)}; + return result; + } + +#ifdef DEBUG + static jsi::String stateToJs(jsi::Runtime &rt, P0 value) { + return bridging::toJs(rt, value); + } + static jsi::String regularToJs(jsi::Runtime &rt, P1 value) { + return bridging::toJs(rt, value); + } + static jsi::String strToJs(jsi::Runtime &rt, P2 value) { + return bridging::toJs(rt, value); + } + static double numToJs(jsi::Runtime &rt, P3 value) { + return bridging::toJs(rt, value); + } + static double fractionToJs(jsi::Runtime &rt, P4 value) { + return bridging::toJs(rt, value); + } +#endif + + static jsi::Object toJs( + jsi::Runtime &rt, + const NativeEnumTurboModuleBaseStateTypeWithEnums &value, + const std::shared_ptr &jsInvoker) { + auto result = facebook::jsi::Object(rt); + result.setProperty(rt, \\"state\\", bridging::toJs(rt, value.state, jsInvoker)); + result.setProperty(rt, \\"regular\\", bridging::toJs(rt, value.regular, jsInvoker)); + result.setProperty(rt, \\"str\\", bridging::toJs(rt, value.str, jsInvoker)); + result.setProperty(rt, \\"num\\", bridging::toJs(rt, value.num, jsInvoker)); + result.setProperty(rt, \\"fraction\\", bridging::toJs(rt, value.fraction, jsInvoker)); + return result; + } + }; + +class JSI_EXPORT NativeEnumTurboModuleCxxSpecJSI : public TurboModule { +protected: + NativeEnumTurboModuleCxxSpecJSI(std::shared_ptr jsInvoker); + +public: + virtual jsi::String getStatusRegular(jsi::Runtime &rt, jsi::Object statusProp) = 0; + virtual jsi::String getStatusStr(jsi::Runtime &rt, jsi::Object statusProp) = 0; + virtual double getStatusNum(jsi::Runtime &rt, jsi::Object statusProp) = 0; + virtual double getStatusFraction(jsi::Runtime &rt, jsi::Object statusProp) = 0; + virtual jsi::Object getStateType(jsi::Runtime &rt, jsi::String a, jsi::String b, double c, double d) = 0; + virtual jsi::Object getStateTypeWithEnums(jsi::Runtime &rt, jsi::Object paramOfTypeWithEnums) = 0; + +}; + +template +class JSI_EXPORT NativeEnumTurboModuleCxxSpec : public TurboModule { +public: + jsi::Value get(jsi::Runtime &rt, const jsi::PropNameID &propName) override { + return delegate_.get(rt, propName); + } + +protected: + NativeEnumTurboModuleCxxSpec(std::shared_ptr jsInvoker) + : TurboModule(\\"NativeEnumTurboModule\\", jsInvoker), + delegate_(static_cast(this), jsInvoker) {} + +private: + class Delegate : public NativeEnumTurboModuleCxxSpecJSI { + public: + Delegate(T *instance, std::shared_ptr jsInvoker) : + NativeEnumTurboModuleCxxSpecJSI(std::move(jsInvoker)), instance_(instance) {} + + jsi::String getStatusRegular(jsi::Runtime &rt, jsi::Object statusProp) override { + static_assert( + bridging::getParameterCount(&T::getStatusRegular) == 2, + \\"Expected getStatusRegular(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getStatusRegular, jsInvoker_, instance_, std::move(statusProp)); + } + jsi::String getStatusStr(jsi::Runtime &rt, jsi::Object statusProp) override { + static_assert( + bridging::getParameterCount(&T::getStatusStr) == 2, + \\"Expected getStatusStr(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getStatusStr, jsInvoker_, instance_, std::move(statusProp)); + } + double getStatusNum(jsi::Runtime &rt, jsi::Object statusProp) override { + static_assert( + bridging::getParameterCount(&T::getStatusNum) == 2, + \\"Expected getStatusNum(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getStatusNum, jsInvoker_, instance_, std::move(statusProp)); + } + double getStatusFraction(jsi::Runtime &rt, jsi::Object statusProp) override { + static_assert( + bridging::getParameterCount(&T::getStatusFraction) == 2, + \\"Expected getStatusFraction(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getStatusFraction, jsInvoker_, instance_, std::move(statusProp)); + } + jsi::Object getStateType(jsi::Runtime &rt, jsi::String a, jsi::String b, double c, double d) override { + static_assert( + bridging::getParameterCount(&T::getStateType) == 5, + \\"Expected getStateType(...) to have 5 parameters\\"); + + return bridging::callFromJs( + rt, &T::getStateType, jsInvoker_, instance_, std::move(a), std::move(b), std::move(c), std::move(d)); + } + jsi::Object getStateTypeWithEnums(jsi::Runtime &rt, jsi::Object paramOfTypeWithEnums) override { + static_assert( + bridging::getParameterCount(&T::getStateTypeWithEnums) == 2, + \\"Expected getStateTypeWithEnums(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getStateTypeWithEnums, jsInvoker_, instance_, std::move(paramOfTypeWithEnums)); + } + + private: + T *instance_; + }; + + Delegate delegate_; +}; + +class JSI_EXPORT NativeNullableTurboModuleCxxSpecJSI : public TurboModule { +protected: + NativeNullableTurboModuleCxxSpecJSI(std::shared_ptr jsInvoker); + +public: + virtual std::optional getBool(jsi::Runtime &rt, std::optional a) = 0; + virtual std::optional getNumber(jsi::Runtime &rt, std::optional a) = 0; + virtual std::optional getString(jsi::Runtime &rt, std::optional a) = 0; + virtual std::optional getArray(jsi::Runtime &rt, std::optional a) = 0; + virtual std::optional getObject(jsi::Runtime &rt, std::optional a) = 0; + virtual std::optional getValueWithPromise(jsi::Runtime &rt) = 0; + +}; + +template +class JSI_EXPORT NativeNullableTurboModuleCxxSpec : public TurboModule { +public: + jsi::Value get(jsi::Runtime &rt, const jsi::PropNameID &propName) override { + return delegate_.get(rt, propName); + } + +protected: + NativeNullableTurboModuleCxxSpec(std::shared_ptr jsInvoker) + : TurboModule(\\"SampleTurboModule\\", jsInvoker), + delegate_(static_cast(this), jsInvoker) {} + +private: + class Delegate : public NativeNullableTurboModuleCxxSpecJSI { + public: + Delegate(T *instance, std::shared_ptr jsInvoker) : + NativeNullableTurboModuleCxxSpecJSI(std::move(jsInvoker)), instance_(instance) {} + + std::optional getBool(jsi::Runtime &rt, std::optional a) override { + static_assert( + bridging::getParameterCount(&T::getBool) == 2, + \\"Expected getBool(...) to have 2 parameters\\"); + + return bridging::callFromJs>( + rt, &T::getBool, jsInvoker_, instance_, std::move(a)); + } + std::optional getNumber(jsi::Runtime &rt, std::optional a) override { + static_assert( + bridging::getParameterCount(&T::getNumber) == 2, + \\"Expected getNumber(...) to have 2 parameters\\"); + + return bridging::callFromJs>( + rt, &T::getNumber, jsInvoker_, instance_, std::move(a)); + } + std::optional getString(jsi::Runtime &rt, std::optional a) override { + static_assert( + bridging::getParameterCount(&T::getString) == 2, + \\"Expected getString(...) to have 2 parameters\\"); + + return bridging::callFromJs>( + rt, &T::getString, jsInvoker_, instance_, std::move(a)); + } + std::optional getArray(jsi::Runtime &rt, std::optional a) override { + static_assert( + bridging::getParameterCount(&T::getArray) == 2, + \\"Expected getArray(...) to have 2 parameters\\"); + + return bridging::callFromJs>( + rt, &T::getArray, jsInvoker_, instance_, std::move(a)); + } + std::optional getObject(jsi::Runtime &rt, std::optional a) override { + static_assert( + bridging::getParameterCount(&T::getObject) == 2, + \\"Expected getObject(...) to have 2 parameters\\"); + + return bridging::callFromJs>( + rt, &T::getObject, jsInvoker_, instance_, std::move(a)); + } + std::optional getValueWithPromise(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::getValueWithPromise) == 1, + \\"Expected getValueWithPromise(...) to have 1 parameters\\"); + + return bridging::callFromJs>( + rt, &T::getValueWithPromise, jsInvoker_, instance_); + } + + private: + T *instance_; + }; + + Delegate delegate_; +}; + +class JSI_EXPORT NativeNumberTurboModuleCxxSpecJSI : public TurboModule { +protected: + NativeNumberTurboModuleCxxSpecJSI(std::shared_ptr jsInvoker); + +public: + virtual double getNumber(jsi::Runtime &rt, double arg) = 0; + virtual double getNumberWithAlias(jsi::Runtime &rt, double arg) = 0; + +}; + +template +class JSI_EXPORT NativeNumberTurboModuleCxxSpec : public TurboModule { +public: + jsi::Value get(jsi::Runtime &rt, const jsi::PropNameID &propName) override { + return delegate_.get(rt, propName); + } + +protected: + NativeNumberTurboModuleCxxSpec(std::shared_ptr jsInvoker) + : TurboModule(\\"SampleTurboModule\\", jsInvoker), + delegate_(static_cast(this), jsInvoker) {} + +private: + class Delegate : public NativeNumberTurboModuleCxxSpecJSI { + public: + Delegate(T *instance, std::shared_ptr jsInvoker) : + NativeNumberTurboModuleCxxSpecJSI(std::move(jsInvoker)), instance_(instance) {} + + double getNumber(jsi::Runtime &rt, double arg) override { + static_assert( + bridging::getParameterCount(&T::getNumber) == 2, + \\"Expected getNumber(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getNumber, jsInvoker_, instance_, std::move(arg)); + } + double getNumberWithAlias(jsi::Runtime &rt, double arg) override { + static_assert( + bridging::getParameterCount(&T::getNumberWithAlias) == 2, + \\"Expected getNumberWithAlias(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getNumberWithAlias, jsInvoker_, instance_, std::move(arg)); + } + + private: + T *instance_; + }; + + Delegate delegate_; +}; + +class JSI_EXPORT NativeObjectTurboModuleCxxSpecJSI : public TurboModule { +protected: + NativeObjectTurboModuleCxxSpecJSI(std::shared_ptr jsInvoker); + +public: + virtual jsi::Object getGenericObject(jsi::Runtime &rt, jsi::Object arg) = 0; + virtual jsi::Object getGenericObjectReadOnly(jsi::Runtime &rt, jsi::Object arg) = 0; + virtual jsi::Object getGenericObjectWithAlias(jsi::Runtime &rt, jsi::Object arg) = 0; + virtual jsi::Object difficultObject(jsi::Runtime &rt, jsi::Object A) = 0; + virtual jsi::Object getConstants(jsi::Runtime &rt) = 0; + +}; + +template +class JSI_EXPORT NativeObjectTurboModuleCxxSpec : public TurboModule { +public: + jsi::Value get(jsi::Runtime &rt, const jsi::PropNameID &propName) override { + return delegate_.get(rt, propName); + } + +protected: + NativeObjectTurboModuleCxxSpec(std::shared_ptr jsInvoker) + : TurboModule(\\"SampleTurboModule\\", jsInvoker), + delegate_(static_cast(this), jsInvoker) {} + +private: + class Delegate : public NativeObjectTurboModuleCxxSpecJSI { + public: + Delegate(T *instance, std::shared_ptr jsInvoker) : + NativeObjectTurboModuleCxxSpecJSI(std::move(jsInvoker)), instance_(instance) {} + + jsi::Object getGenericObject(jsi::Runtime &rt, jsi::Object arg) override { + static_assert( + bridging::getParameterCount(&T::getGenericObject) == 2, + \\"Expected getGenericObject(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getGenericObject, jsInvoker_, instance_, std::move(arg)); + } + jsi::Object getGenericObjectReadOnly(jsi::Runtime &rt, jsi::Object arg) override { + static_assert( + bridging::getParameterCount(&T::getGenericObjectReadOnly) == 2, + \\"Expected getGenericObjectReadOnly(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getGenericObjectReadOnly, jsInvoker_, instance_, std::move(arg)); + } + jsi::Object getGenericObjectWithAlias(jsi::Runtime &rt, jsi::Object arg) override { + static_assert( + bridging::getParameterCount(&T::getGenericObjectWithAlias) == 2, + \\"Expected getGenericObjectWithAlias(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getGenericObjectWithAlias, jsInvoker_, instance_, std::move(arg)); + } + jsi::Object difficultObject(jsi::Runtime &rt, jsi::Object A) override { + static_assert( + bridging::getParameterCount(&T::difficultObject) == 2, + \\"Expected difficultObject(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::difficultObject, jsInvoker_, instance_, std::move(A)); + } + jsi::Object getConstants(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::getConstants) == 1, + \\"Expected getConstants(...) to have 1 parameters\\"); + + return bridging::callFromJs( + rt, &T::getConstants, jsInvoker_, instance_); + } + + private: + T *instance_; + }; + + Delegate delegate_; +}; + +class JSI_EXPORT NativeOptionalObjectTurboModuleCxxSpecJSI : public TurboModule { +protected: + NativeOptionalObjectTurboModuleCxxSpecJSI(std::shared_ptr jsInvoker); + +public: + virtual jsi::Object getConstants(jsi::Runtime &rt) = 0; + +}; + +template +class JSI_EXPORT NativeOptionalObjectTurboModuleCxxSpec : public TurboModule { +public: + jsi::Value get(jsi::Runtime &rt, const jsi::PropNameID &propName) override { + return delegate_.get(rt, propName); + } + +protected: + NativeOptionalObjectTurboModuleCxxSpec(std::shared_ptr jsInvoker) + : TurboModule(\\"SampleTurboModule\\", jsInvoker), + delegate_(static_cast(this), jsInvoker) {} + +private: + class Delegate : public NativeOptionalObjectTurboModuleCxxSpecJSI { + public: + Delegate(T *instance, std::shared_ptr jsInvoker) : + NativeOptionalObjectTurboModuleCxxSpecJSI(std::move(jsInvoker)), instance_(instance) {} + + jsi::Object getConstants(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::getConstants) == 1, + \\"Expected getConstants(...) to have 1 parameters\\"); + + return bridging::callFromJs( + rt, &T::getConstants, jsInvoker_, instance_); + } + + private: + T *instance_; + }; + + Delegate delegate_; +}; + +#pragma mark - NativePartialAnnotationTurboModuleBaseSomeObj + +template +struct NativePartialAnnotationTurboModuleBaseSomeObj { + P0 a; + P1 b; + bool operator==(const NativePartialAnnotationTurboModuleBaseSomeObj &other) const { + return a == other.a && b == other.b; + } +}; + +template +struct NativePartialAnnotationTurboModuleBaseSomeObjBridging { + static NativePartialAnnotationTurboModuleBaseSomeObj fromJs( + jsi::Runtime &rt, + const jsi::Object &value, + const std::shared_ptr &jsInvoker) { + NativePartialAnnotationTurboModuleBaseSomeObj result{ + bridging::fromJs(rt, value.getProperty(rt, \\"a\\"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, \\"b\\"), jsInvoker)}; + return result; + } + +#ifdef DEBUG + static jsi::String aToJs(jsi::Runtime &rt, P0 value) { + return bridging::toJs(rt, value); + } + static bool bToJs(jsi::Runtime &rt, P1 value) { + return bridging::toJs(rt, value); + } +#endif + + static jsi::Object toJs( + jsi::Runtime &rt, + const NativePartialAnnotationTurboModuleBaseSomeObj &value, + const std::shared_ptr &jsInvoker) { + auto result = facebook::jsi::Object(rt); + result.setProperty(rt, \\"a\\", bridging::toJs(rt, value.a, jsInvoker)); + if (value.b) { + result.setProperty(rt, \\"b\\", bridging::toJs(rt, value.b.value(), jsInvoker)); + } + return result; + } + }; + +class JSI_EXPORT NativePartialAnnotationTurboModuleCxxSpecJSI : public TurboModule { +protected: + NativePartialAnnotationTurboModuleCxxSpecJSI(std::shared_ptr jsInvoker); + +public: + virtual jsi::Object getSomeObj(jsi::Runtime &rt) = 0; + virtual jsi::Object getPartialSomeObj(jsi::Runtime &rt) = 0; + virtual jsi::Object getSomeObjFromPartialSomeObj(jsi::Runtime &rt, jsi::Object value) = 0; + virtual jsi::Object getPartialPartial(jsi::Runtime &rt, jsi::Object value1, jsi::Object value2) = 0; + +}; + +template +class JSI_EXPORT NativePartialAnnotationTurboModuleCxxSpec : public TurboModule { +public: + jsi::Value get(jsi::Runtime &rt, const jsi::PropNameID &propName) override { + return delegate_.get(rt, propName); + } + +protected: + NativePartialAnnotationTurboModuleCxxSpec(std::shared_ptr jsInvoker) + : TurboModule(\\"NativePartialAnnotationTurboModule\\", jsInvoker), + delegate_(static_cast(this), jsInvoker) {} + +private: + class Delegate : public NativePartialAnnotationTurboModuleCxxSpecJSI { + public: + Delegate(T *instance, std::shared_ptr jsInvoker) : + NativePartialAnnotationTurboModuleCxxSpecJSI(std::move(jsInvoker)), instance_(instance) {} + + jsi::Object getSomeObj(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::getSomeObj) == 1, + \\"Expected getSomeObj(...) to have 1 parameters\\"); + + return bridging::callFromJs( + rt, &T::getSomeObj, jsInvoker_, instance_); + } + jsi::Object getPartialSomeObj(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::getPartialSomeObj) == 1, + \\"Expected getPartialSomeObj(...) to have 1 parameters\\"); + + return bridging::callFromJs( + rt, &T::getPartialSomeObj, jsInvoker_, instance_); + } + jsi::Object getSomeObjFromPartialSomeObj(jsi::Runtime &rt, jsi::Object value) override { + static_assert( + bridging::getParameterCount(&T::getSomeObjFromPartialSomeObj) == 2, + \\"Expected getSomeObjFromPartialSomeObj(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getSomeObjFromPartialSomeObj, jsInvoker_, instance_, std::move(value)); + } + jsi::Object getPartialPartial(jsi::Runtime &rt, jsi::Object value1, jsi::Object value2) override { + static_assert( + bridging::getParameterCount(&T::getPartialPartial) == 3, + \\"Expected getPartialPartial(...) to have 3 parameters\\"); + + return bridging::callFromJs( + rt, &T::getPartialPartial, jsInvoker_, instance_, std::move(value1), std::move(value2)); + } + + private: + T *instance_; + }; + + Delegate delegate_; +}; + +class JSI_EXPORT NativePromiseTurboModuleCxxSpecJSI : public TurboModule { +protected: + NativePromiseTurboModuleCxxSpecJSI(std::shared_ptr jsInvoker); + +public: + virtual jsi::Value getValueWithPromise(jsi::Runtime &rt, bool error) = 0; + virtual jsi::Value getValueWithPromiseWithAlias(jsi::Runtime &rt, jsi::String arg) = 0; + +}; + +template +class JSI_EXPORT NativePromiseTurboModuleCxxSpec : public TurboModule { +public: + jsi::Value get(jsi::Runtime &rt, const jsi::PropNameID &propName) override { + return delegate_.get(rt, propName); + } + +protected: + NativePromiseTurboModuleCxxSpec(std::shared_ptr jsInvoker) + : TurboModule(\\"SampleTurboModule\\", jsInvoker), + delegate_(static_cast(this), jsInvoker) {} + +private: + class Delegate : public NativePromiseTurboModuleCxxSpecJSI { + public: + Delegate(T *instance, std::shared_ptr jsInvoker) : + NativePromiseTurboModuleCxxSpecJSI(std::move(jsInvoker)), instance_(instance) {} + + jsi::Value getValueWithPromise(jsi::Runtime &rt, bool error) override { + static_assert( + bridging::getParameterCount(&T::getValueWithPromise) == 2, + \\"Expected getValueWithPromise(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getValueWithPromise, jsInvoker_, instance_, std::move(error)); + } + jsi::Value getValueWithPromiseWithAlias(jsi::Runtime &rt, jsi::String arg) override { + static_assert( + bridging::getParameterCount(&T::getValueWithPromiseWithAlias) == 2, + \\"Expected getValueWithPromiseWithAlias(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getValueWithPromiseWithAlias, jsInvoker_, instance_, std::move(arg)); + } + + private: + T *instance_; + }; + + Delegate delegate_; +}; + +#pragma mark - SampleTurboModuleBaseAnimal + +template +struct SampleTurboModuleBaseAnimal { + P0 name; + bool operator==(const SampleTurboModuleBaseAnimal &other) const { + return name == other.name; + } +}; + +template +struct SampleTurboModuleBaseAnimalBridging { + static SampleTurboModuleBaseAnimal fromJs( + jsi::Runtime &rt, + const jsi::Object &value, + const std::shared_ptr &jsInvoker) { + SampleTurboModuleBaseAnimal result{ + bridging::fromJs(rt, value.getProperty(rt, \\"name\\"), jsInvoker)}; + return result; + } + +#ifdef DEBUG + static jsi::String nameToJs(jsi::Runtime &rt, P0 value) { + return bridging::toJs(rt, value); + } +#endif + + static jsi::Object toJs( + jsi::Runtime &rt, + const SampleTurboModuleBaseAnimal &value, + const std::shared_ptr &jsInvoker) { + auto result = facebook::jsi::Object(rt); + result.setProperty(rt, \\"name\\", bridging::toJs(rt, value.name, jsInvoker)); + return result; + } + }; + +class JSI_EXPORT NativeSampleTurboModuleCxxSpecJSI : public TurboModule { +protected: + NativeSampleTurboModuleCxxSpecJSI(std::shared_ptr jsInvoker); + +public: + virtual jsi::Object getConstants(jsi::Runtime &rt) = 0; + virtual void voidFunc(jsi::Runtime &rt) = 0; + virtual bool getBool(jsi::Runtime &rt, bool arg) = 0; + virtual double getNumber(jsi::Runtime &rt, double arg) = 0; + virtual jsi::String getString(jsi::Runtime &rt, jsi::String arg) = 0; + virtual jsi::Array getArray(jsi::Runtime &rt, jsi::Array arg) = 0; + virtual jsi::Object getObject(jsi::Runtime &rt, jsi::Object arg) = 0; + virtual jsi::Object getObjectShape(jsi::Runtime &rt, jsi::Object arg) = 0; + virtual jsi::Object getAlias(jsi::Runtime &rt, jsi::Object arg) = 0; + virtual double getRootTag(jsi::Runtime &rt, double arg) = 0; + virtual jsi::Object getValue(jsi::Runtime &rt, double x, jsi::String getValuegetValuegetValuegetValuegetValuey, jsi::Object z) = 0; + virtual void getValueWithCallback(jsi::Runtime &rt, jsi::Function callback) = 0; + virtual jsi::Value getValueWithPromise(jsi::Runtime &rt, bool error) = 0; + +}; + +template +class JSI_EXPORT NativeSampleTurboModuleCxxSpec : public TurboModule { +public: + jsi::Value get(jsi::Runtime &rt, const jsi::PropNameID &propName) override { + return delegate_.get(rt, propName); + } + +protected: + NativeSampleTurboModuleCxxSpec(std::shared_ptr jsInvoker) + : TurboModule(\\"SampleTurboModule\\", jsInvoker), + delegate_(static_cast(this), jsInvoker) {} + +private: + class Delegate : public NativeSampleTurboModuleCxxSpecJSI { + public: + Delegate(T *instance, std::shared_ptr jsInvoker) : + NativeSampleTurboModuleCxxSpecJSI(std::move(jsInvoker)), instance_(instance) {} + + jsi::Object getConstants(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::getConstants) == 1, + \\"Expected getConstants(...) to have 1 parameters\\"); + + return bridging::callFromJs( + rt, &T::getConstants, jsInvoker_, instance_); + } + void voidFunc(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::voidFunc) == 1, + \\"Expected voidFunc(...) to have 1 parameters\\"); + + return bridging::callFromJs( + rt, &T::voidFunc, jsInvoker_, instance_); + } + bool getBool(jsi::Runtime &rt, bool arg) override { + static_assert( + bridging::getParameterCount(&T::getBool) == 2, + \\"Expected getBool(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getBool, jsInvoker_, instance_, std::move(arg)); + } + double getNumber(jsi::Runtime &rt, double arg) override { + static_assert( + bridging::getParameterCount(&T::getNumber) == 2, + \\"Expected getNumber(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getNumber, jsInvoker_, instance_, std::move(arg)); + } + jsi::String getString(jsi::Runtime &rt, jsi::String arg) override { + static_assert( + bridging::getParameterCount(&T::getString) == 2, + \\"Expected getString(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getString, jsInvoker_, instance_, std::move(arg)); + } + jsi::Array getArray(jsi::Runtime &rt, jsi::Array arg) override { + static_assert( + bridging::getParameterCount(&T::getArray) == 2, + \\"Expected getArray(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getArray, jsInvoker_, instance_, std::move(arg)); + } + jsi::Object getObject(jsi::Runtime &rt, jsi::Object arg) override { + static_assert( + bridging::getParameterCount(&T::getObject) == 2, + \\"Expected getObject(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getObject, jsInvoker_, instance_, std::move(arg)); + } + jsi::Object getObjectShape(jsi::Runtime &rt, jsi::Object arg) override { + static_assert( + bridging::getParameterCount(&T::getObjectShape) == 2, + \\"Expected getObjectShape(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getObjectShape, jsInvoker_, instance_, std::move(arg)); + } + jsi::Object getAlias(jsi::Runtime &rt, jsi::Object arg) override { + static_assert( + bridging::getParameterCount(&T::getAlias) == 2, + \\"Expected getAlias(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getAlias, jsInvoker_, instance_, std::move(arg)); + } + double getRootTag(jsi::Runtime &rt, double arg) override { + static_assert( + bridging::getParameterCount(&T::getRootTag) == 2, + \\"Expected getRootTag(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getRootTag, jsInvoker_, instance_, std::move(arg)); + } + jsi::Object getValue(jsi::Runtime &rt, double x, jsi::String getValuegetValuegetValuegetValuegetValuey, jsi::Object z) override { + static_assert( + bridging::getParameterCount(&T::getValue) == 4, + \\"Expected getValue(...) to have 4 parameters\\"); + + return bridging::callFromJs( + rt, &T::getValue, jsInvoker_, instance_, std::move(x), std::move(getValuegetValuegetValuegetValuegetValuey), std::move(z)); + } + void getValueWithCallback(jsi::Runtime &rt, jsi::Function callback) override { + static_assert( + bridging::getParameterCount(&T::getValueWithCallback) == 2, + \\"Expected getValueWithCallback(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getValueWithCallback, jsInvoker_, instance_, std::move(callback)); + } + jsi::Value getValueWithPromise(jsi::Runtime &rt, bool error) override { + static_assert( + bridging::getParameterCount(&T::getValueWithPromise) == 2, + \\"Expected getValueWithPromise(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getValueWithPromise, jsInvoker_, instance_, std::move(error)); + } + + private: + T *instance_; + }; + + Delegate delegate_; +}; + +#pragma mark - SampleTurboModuleArraysBaseAnimal + +template +struct SampleTurboModuleArraysBaseAnimal { + P0 name; + bool operator==(const SampleTurboModuleArraysBaseAnimal &other) const { + return name == other.name; + } +}; + +template +struct SampleTurboModuleArraysBaseAnimalBridging { + static SampleTurboModuleArraysBaseAnimal fromJs( + jsi::Runtime &rt, + const jsi::Object &value, + const std::shared_ptr &jsInvoker) { + SampleTurboModuleArraysBaseAnimal result{ + bridging::fromJs(rt, value.getProperty(rt, \\"name\\"), jsInvoker)}; + return result; + } + +#ifdef DEBUG + static jsi::String nameToJs(jsi::Runtime &rt, P0 value) { + return bridging::toJs(rt, value); + } +#endif + + static jsi::Object toJs( + jsi::Runtime &rt, + const SampleTurboModuleArraysBaseAnimal &value, + const std::shared_ptr &jsInvoker) { + auto result = facebook::jsi::Object(rt); + result.setProperty(rt, \\"name\\", bridging::toJs(rt, value.name, jsInvoker)); + return result; + } + }; + +class JSI_EXPORT NativeSampleTurboModuleArraysCxxSpecJSI : public TurboModule { +protected: + NativeSampleTurboModuleArraysCxxSpecJSI(std::shared_ptr jsInvoker); + +public: + virtual jsi::Object getConstants(jsi::Runtime &rt) = 0; + virtual void voidFunc(jsi::Runtime &rt) = 0; + virtual jsi::Array getBool(jsi::Runtime &rt, jsi::Array id) = 0; + virtual jsi::Array getNumber(jsi::Runtime &rt, jsi::Array arg) = 0; + virtual jsi::Array getString(jsi::Runtime &rt, jsi::Array arg) = 0; + virtual jsi::Array getArray(jsi::Runtime &rt, jsi::Array arg) = 0; + virtual jsi::Array getObject(jsi::Runtime &rt, jsi::Array arg) = 0; + virtual jsi::Array getObjectShape(jsi::Runtime &rt, jsi::Array arg) = 0; + virtual jsi::Array getAlias(jsi::Runtime &rt, jsi::Array arg) = 0; + virtual jsi::Array getRootTag(jsi::Runtime &rt, jsi::Array arg) = 0; + virtual jsi::Array getValue(jsi::Runtime &rt, jsi::Array x, jsi::Array y, jsi::Array z) = 0; + virtual void getValueWithCallback(jsi::Runtime &rt, jsi::Function callback) = 0; + virtual jsi::Value getValueWithPromise(jsi::Runtime &rt, jsi::Array error) = 0; + +}; + +template +class JSI_EXPORT NativeSampleTurboModuleArraysCxxSpec : public TurboModule { +public: + jsi::Value get(jsi::Runtime &rt, const jsi::PropNameID &propName) override { + return delegate_.get(rt, propName); + } + +protected: + NativeSampleTurboModuleArraysCxxSpec(std::shared_ptr jsInvoker) + : TurboModule(\\"SampleTurboModuleArrays\\", jsInvoker), + delegate_(static_cast(this), jsInvoker) {} + +private: + class Delegate : public NativeSampleTurboModuleArraysCxxSpecJSI { + public: + Delegate(T *instance, std::shared_ptr jsInvoker) : + NativeSampleTurboModuleArraysCxxSpecJSI(std::move(jsInvoker)), instance_(instance) {} + + jsi::Object getConstants(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::getConstants) == 1, + \\"Expected getConstants(...) to have 1 parameters\\"); + + return bridging::callFromJs( + rt, &T::getConstants, jsInvoker_, instance_); + } + void voidFunc(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::voidFunc) == 1, + \\"Expected voidFunc(...) to have 1 parameters\\"); + + return bridging::callFromJs( + rt, &T::voidFunc, jsInvoker_, instance_); + } + jsi::Array getBool(jsi::Runtime &rt, jsi::Array id) override { + static_assert( + bridging::getParameterCount(&T::getBool) == 2, + \\"Expected getBool(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getBool, jsInvoker_, instance_, std::move(id)); + } + jsi::Array getNumber(jsi::Runtime &rt, jsi::Array arg) override { + static_assert( + bridging::getParameterCount(&T::getNumber) == 2, + \\"Expected getNumber(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getNumber, jsInvoker_, instance_, std::move(arg)); + } + jsi::Array getString(jsi::Runtime &rt, jsi::Array arg) override { + static_assert( + bridging::getParameterCount(&T::getString) == 2, + \\"Expected getString(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getString, jsInvoker_, instance_, std::move(arg)); + } + jsi::Array getArray(jsi::Runtime &rt, jsi::Array arg) override { + static_assert( + bridging::getParameterCount(&T::getArray) == 2, + \\"Expected getArray(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getArray, jsInvoker_, instance_, std::move(arg)); + } + jsi::Array getObject(jsi::Runtime &rt, jsi::Array arg) override { + static_assert( + bridging::getParameterCount(&T::getObject) == 2, + \\"Expected getObject(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getObject, jsInvoker_, instance_, std::move(arg)); + } + jsi::Array getObjectShape(jsi::Runtime &rt, jsi::Array arg) override { + static_assert( + bridging::getParameterCount(&T::getObjectShape) == 2, + \\"Expected getObjectShape(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getObjectShape, jsInvoker_, instance_, std::move(arg)); + } + jsi::Array getAlias(jsi::Runtime &rt, jsi::Array arg) override { + static_assert( + bridging::getParameterCount(&T::getAlias) == 2, + \\"Expected getAlias(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getAlias, jsInvoker_, instance_, std::move(arg)); + } + jsi::Array getRootTag(jsi::Runtime &rt, jsi::Array arg) override { + static_assert( + bridging::getParameterCount(&T::getRootTag) == 2, + \\"Expected getRootTag(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getRootTag, jsInvoker_, instance_, std::move(arg)); + } + jsi::Array getValue(jsi::Runtime &rt, jsi::Array x, jsi::Array y, jsi::Array z) override { + static_assert( + bridging::getParameterCount(&T::getValue) == 4, + \\"Expected getValue(...) to have 4 parameters\\"); + + return bridging::callFromJs( + rt, &T::getValue, jsInvoker_, instance_, std::move(x), std::move(y), std::move(z)); + } + void getValueWithCallback(jsi::Runtime &rt, jsi::Function callback) override { + static_assert( + bridging::getParameterCount(&T::getValueWithCallback) == 2, + \\"Expected getValueWithCallback(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getValueWithCallback, jsInvoker_, instance_, std::move(callback)); + } + jsi::Value getValueWithPromise(jsi::Runtime &rt, jsi::Array error) override { + static_assert( + bridging::getParameterCount(&T::getValueWithPromise) == 2, + \\"Expected getValueWithPromise(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getValueWithPromise, jsInvoker_, instance_, std::move(error)); + } + + private: + T *instance_; + }; + + Delegate delegate_; +}; + +#pragma mark - SampleTurboModuleNullableBaseAnimal + +template +struct SampleTurboModuleNullableBaseAnimal { + P0 name; + bool operator==(const SampleTurboModuleNullableBaseAnimal &other) const { + return name == other.name; + } +}; + +template +struct SampleTurboModuleNullableBaseAnimalBridging { + static SampleTurboModuleNullableBaseAnimal fromJs( + jsi::Runtime &rt, + const jsi::Object &value, + const std::shared_ptr &jsInvoker) { + SampleTurboModuleNullableBaseAnimal result{ + bridging::fromJs(rt, value.getProperty(rt, \\"name\\"), jsInvoker)}; + return result; + } + +#ifdef DEBUG + static std::optional nameToJs(jsi::Runtime &rt, P0 value) { + return bridging::toJs(rt, value); + } +#endif + + static jsi::Object toJs( + jsi::Runtime &rt, + const SampleTurboModuleNullableBaseAnimal &value, + const std::shared_ptr &jsInvoker) { + auto result = facebook::jsi::Object(rt); + result.setProperty(rt, \\"name\\", bridging::toJs(rt, value.name, jsInvoker)); + return result; + } + }; + +class JSI_EXPORT NativeSampleTurboModuleNullableCxxSpecJSI : public TurboModule { +protected: + NativeSampleTurboModuleNullableCxxSpecJSI(std::shared_ptr jsInvoker); + +public: + virtual jsi::Object getConstants(jsi::Runtime &rt) = 0; + virtual void voidFunc(jsi::Runtime &rt) = 0; + virtual std::optional getBool(jsi::Runtime &rt, std::optional arg) = 0; + virtual std::optional getNumber(jsi::Runtime &rt, std::optional arg) = 0; + virtual std::optional getString(jsi::Runtime &rt, std::optional arg) = 0; + virtual std::optional getArray(jsi::Runtime &rt, std::optional arg) = 0; + virtual std::optional getObject(jsi::Runtime &rt, std::optional arg) = 0; + virtual std::optional getObjectShape(jsi::Runtime &rt, std::optional arg) = 0; + virtual std::optional getAlias(jsi::Runtime &rt, std::optional arg) = 0; + virtual std::optional getRootTag(jsi::Runtime &rt, std::optional arg) = 0; + virtual std::optional getValue(jsi::Runtime &rt, std::optional x, std::optional y, std::optional z) = 0; + virtual void getValueWithCallback(jsi::Runtime &rt, jsi::Function callback) = 0; + virtual std::optional getValueWithPromise(jsi::Runtime &rt, std::optional error) = 0; + +}; + +template +class JSI_EXPORT NativeSampleTurboModuleNullableCxxSpec : public TurboModule { +public: + jsi::Value get(jsi::Runtime &rt, const jsi::PropNameID &propName) override { + return delegate_.get(rt, propName); + } + +protected: + NativeSampleTurboModuleNullableCxxSpec(std::shared_ptr jsInvoker) + : TurboModule(\\"SampleTurboModuleNullable\\", jsInvoker), + delegate_(static_cast(this), jsInvoker) {} + +private: + class Delegate : public NativeSampleTurboModuleNullableCxxSpecJSI { + public: + Delegate(T *instance, std::shared_ptr jsInvoker) : + NativeSampleTurboModuleNullableCxxSpecJSI(std::move(jsInvoker)), instance_(instance) {} + + jsi::Object getConstants(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::getConstants) == 1, + \\"Expected getConstants(...) to have 1 parameters\\"); + + return bridging::callFromJs( + rt, &T::getConstants, jsInvoker_, instance_); + } + void voidFunc(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::voidFunc) == 1, + \\"Expected voidFunc(...) to have 1 parameters\\"); + + return bridging::callFromJs( + rt, &T::voidFunc, jsInvoker_, instance_); + } + std::optional getBool(jsi::Runtime &rt, std::optional arg) override { + static_assert( + bridging::getParameterCount(&T::getBool) == 2, + \\"Expected getBool(...) to have 2 parameters\\"); + + return bridging::callFromJs>( + rt, &T::getBool, jsInvoker_, instance_, std::move(arg)); + } + std::optional getNumber(jsi::Runtime &rt, std::optional arg) override { + static_assert( + bridging::getParameterCount(&T::getNumber) == 2, + \\"Expected getNumber(...) to have 2 parameters\\"); + + return bridging::callFromJs>( + rt, &T::getNumber, jsInvoker_, instance_, std::move(arg)); + } + std::optional getString(jsi::Runtime &rt, std::optional arg) override { + static_assert( + bridging::getParameterCount(&T::getString) == 2, + \\"Expected getString(...) to have 2 parameters\\"); + + return bridging::callFromJs>( + rt, &T::getString, jsInvoker_, instance_, std::move(arg)); + } + std::optional getArray(jsi::Runtime &rt, std::optional arg) override { + static_assert( + bridging::getParameterCount(&T::getArray) == 2, + \\"Expected getArray(...) to have 2 parameters\\"); + + return bridging::callFromJs>( + rt, &T::getArray, jsInvoker_, instance_, std::move(arg)); + } + std::optional getObject(jsi::Runtime &rt, std::optional arg) override { + static_assert( + bridging::getParameterCount(&T::getObject) == 2, + \\"Expected getObject(...) to have 2 parameters\\"); + + return bridging::callFromJs>( + rt, &T::getObject, jsInvoker_, instance_, std::move(arg)); + } + std::optional getObjectShape(jsi::Runtime &rt, std::optional arg) override { + static_assert( + bridging::getParameterCount(&T::getObjectShape) == 2, + \\"Expected getObjectShape(...) to have 2 parameters\\"); + + return bridging::callFromJs>( + rt, &T::getObjectShape, jsInvoker_, instance_, std::move(arg)); + } + std::optional getAlias(jsi::Runtime &rt, std::optional arg) override { + static_assert( + bridging::getParameterCount(&T::getAlias) == 2, + \\"Expected getAlias(...) to have 2 parameters\\"); + + return bridging::callFromJs>( + rt, &T::getAlias, jsInvoker_, instance_, std::move(arg)); + } + std::optional getRootTag(jsi::Runtime &rt, std::optional arg) override { + static_assert( + bridging::getParameterCount(&T::getRootTag) == 2, + \\"Expected getRootTag(...) to have 2 parameters\\"); + + return bridging::callFromJs>( + rt, &T::getRootTag, jsInvoker_, instance_, std::move(arg)); + } + std::optional getValue(jsi::Runtime &rt, std::optional x, std::optional y, std::optional z) override { + static_assert( + bridging::getParameterCount(&T::getValue) == 4, + \\"Expected getValue(...) to have 4 parameters\\"); + + return bridging::callFromJs>( + rt, &T::getValue, jsInvoker_, instance_, std::move(x), std::move(y), std::move(z)); + } + void getValueWithCallback(jsi::Runtime &rt, jsi::Function callback) override { + static_assert( + bridging::getParameterCount(&T::getValueWithCallback) == 2, + \\"Expected getValueWithCallback(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getValueWithCallback, jsInvoker_, instance_, std::move(callback)); + } + std::optional getValueWithPromise(jsi::Runtime &rt, std::optional error) override { + static_assert( + bridging::getParameterCount(&T::getValueWithPromise) == 2, + \\"Expected getValueWithPromise(...) to have 2 parameters\\"); + + return bridging::callFromJs>( + rt, &T::getValueWithPromise, jsInvoker_, instance_, std::move(error)); + } + + private: + T *instance_; + }; + + Delegate delegate_; +}; + +#pragma mark - SampleTurboModuleNullableAndOptionalBaseAnimal + +template +struct SampleTurboModuleNullableAndOptionalBaseAnimal { + P0 name; + bool operator==(const SampleTurboModuleNullableAndOptionalBaseAnimal &other) const { + return name == other.name; + } +}; + +template +struct SampleTurboModuleNullableAndOptionalBaseAnimalBridging { + static SampleTurboModuleNullableAndOptionalBaseAnimal fromJs( + jsi::Runtime &rt, + const jsi::Object &value, + const std::shared_ptr &jsInvoker) { + SampleTurboModuleNullableAndOptionalBaseAnimal result{ + bridging::fromJs(rt, value.getProperty(rt, \\"name\\"), jsInvoker)}; + return result; + } + +#ifdef DEBUG + static std::optional nameToJs(jsi::Runtime &rt, P0 value) { + return bridging::toJs(rt, value); + } +#endif + + static jsi::Object toJs( + jsi::Runtime &rt, + const SampleTurboModuleNullableAndOptionalBaseAnimal &value, + const std::shared_ptr &jsInvoker) { + auto result = facebook::jsi::Object(rt); + if (value.name) { + result.setProperty(rt, \\"name\\", bridging::toJs(rt, value.name.value(), jsInvoker)); + } + return result; + } + }; + +class JSI_EXPORT NativeSampleTurboModuleNullableAndOptionalCxxSpecJSI : public TurboModule { +protected: + NativeSampleTurboModuleNullableAndOptionalCxxSpecJSI(std::shared_ptr jsInvoker); + +public: + virtual jsi::Object getConstants(jsi::Runtime &rt) = 0; + virtual void voidFunc(jsi::Runtime &rt) = 0; + virtual std::optional getBool(jsi::Runtime &rt, std::optional arg) = 0; + virtual std::optional getNumber(jsi::Runtime &rt, std::optional arg) = 0; + virtual std::optional getString(jsi::Runtime &rt, std::optional arg) = 0; + virtual std::optional getArray(jsi::Runtime &rt, std::optional arg) = 0; + virtual std::optional getObject(jsi::Runtime &rt, std::optional arg) = 0; + virtual jsi::Object getObjectShape(jsi::Runtime &rt, std::optional arg) = 0; + virtual std::optional getAlias(jsi::Runtime &rt, std::optional arg) = 0; + virtual std::optional getRootTag(jsi::Runtime &rt, std::optional arg) = 0; + virtual std::optional getValue(jsi::Runtime &rt, std::optional x, std::optional y, std::optional z) = 0; + virtual void getValueWithCallback(jsi::Runtime &rt, std::optional callback) = 0; + virtual std::optional getValueWithPromise(jsi::Runtime &rt, std::optional error) = 0; + +}; + +template +class JSI_EXPORT NativeSampleTurboModuleNullableAndOptionalCxxSpec : public TurboModule { +public: + jsi::Value get(jsi::Runtime &rt, const jsi::PropNameID &propName) override { + return delegate_.get(rt, propName); + } + +protected: + NativeSampleTurboModuleNullableAndOptionalCxxSpec(std::shared_ptr jsInvoker) + : TurboModule(\\"SampleTurboModuleNullableAndOptional\\", jsInvoker), + delegate_(static_cast(this), jsInvoker) {} + +private: + class Delegate : public NativeSampleTurboModuleNullableAndOptionalCxxSpecJSI { + public: + Delegate(T *instance, std::shared_ptr jsInvoker) : + NativeSampleTurboModuleNullableAndOptionalCxxSpecJSI(std::move(jsInvoker)), instance_(instance) {} + + jsi::Object getConstants(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::getConstants) == 1, + \\"Expected getConstants(...) to have 1 parameters\\"); + + return bridging::callFromJs( + rt, &T::getConstants, jsInvoker_, instance_); + } + void voidFunc(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::voidFunc) == 1, + \\"Expected voidFunc(...) to have 1 parameters\\"); + + return bridging::callFromJs( + rt, &T::voidFunc, jsInvoker_, instance_); + } + std::optional getBool(jsi::Runtime &rt, std::optional arg) override { + static_assert( + bridging::getParameterCount(&T::getBool) == 2, + \\"Expected getBool(...) to have 2 parameters\\"); + + return bridging::callFromJs>( + rt, &T::getBool, jsInvoker_, instance_, std::move(arg)); + } + std::optional getNumber(jsi::Runtime &rt, std::optional arg) override { + static_assert( + bridging::getParameterCount(&T::getNumber) == 2, + \\"Expected getNumber(...) to have 2 parameters\\"); + + return bridging::callFromJs>( + rt, &T::getNumber, jsInvoker_, instance_, std::move(arg)); + } + std::optional getString(jsi::Runtime &rt, std::optional arg) override { + static_assert( + bridging::getParameterCount(&T::getString) == 2, + \\"Expected getString(...) to have 2 parameters\\"); + + return bridging::callFromJs>( + rt, &T::getString, jsInvoker_, instance_, std::move(arg)); + } + std::optional getArray(jsi::Runtime &rt, std::optional arg) override { + static_assert( + bridging::getParameterCount(&T::getArray) == 2, + \\"Expected getArray(...) to have 2 parameters\\"); + + return bridging::callFromJs>( + rt, &T::getArray, jsInvoker_, instance_, std::move(arg)); + } + std::optional getObject(jsi::Runtime &rt, std::optional arg) override { + static_assert( + bridging::getParameterCount(&T::getObject) == 2, + \\"Expected getObject(...) to have 2 parameters\\"); + + return bridging::callFromJs>( + rt, &T::getObject, jsInvoker_, instance_, std::move(arg)); + } + jsi::Object getObjectShape(jsi::Runtime &rt, std::optional arg) override { + static_assert( + bridging::getParameterCount(&T::getObjectShape) == 2, + \\"Expected getObjectShape(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getObjectShape, jsInvoker_, instance_, std::move(arg)); + } + std::optional getAlias(jsi::Runtime &rt, std::optional arg) override { + static_assert( + bridging::getParameterCount(&T::getAlias) == 2, + \\"Expected getAlias(...) to have 2 parameters\\"); + + return bridging::callFromJs>( + rt, &T::getAlias, jsInvoker_, instance_, std::move(arg)); + } + std::optional getRootTag(jsi::Runtime &rt, std::optional arg) override { + static_assert( + bridging::getParameterCount(&T::getRootTag) == 2, + \\"Expected getRootTag(...) to have 2 parameters\\"); + + return bridging::callFromJs>( + rt, &T::getRootTag, jsInvoker_, instance_, std::move(arg)); + } + std::optional getValue(jsi::Runtime &rt, std::optional x, std::optional y, std::optional z) override { + static_assert( + bridging::getParameterCount(&T::getValue) == 4, + \\"Expected getValue(...) to have 4 parameters\\"); + + return bridging::callFromJs>( + rt, &T::getValue, jsInvoker_, instance_, std::move(x), std::move(y), std::move(z)); + } + void getValueWithCallback(jsi::Runtime &rt, std::optional callback) override { + static_assert( + bridging::getParameterCount(&T::getValueWithCallback) == 2, + \\"Expected getValueWithCallback(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getValueWithCallback, jsInvoker_, instance_, std::move(callback)); + } + std::optional getValueWithPromise(jsi::Runtime &rt, std::optional error) override { + static_assert( + bridging::getParameterCount(&T::getValueWithPromise) == 2, + \\"Expected getValueWithPromise(...) to have 2 parameters\\"); + + return bridging::callFromJs>( + rt, &T::getValueWithPromise, jsInvoker_, instance_, std::move(error)); + } + + private: + T *instance_; + }; + + Delegate delegate_; +}; + +#pragma mark - SampleTurboModuleOptionalBaseAnimal + +template +struct SampleTurboModuleOptionalBaseAnimal { + P0 name; + bool operator==(const SampleTurboModuleOptionalBaseAnimal &other) const { + return name == other.name; + } +}; + +template +struct SampleTurboModuleOptionalBaseAnimalBridging { + static SampleTurboModuleOptionalBaseAnimal fromJs( + jsi::Runtime &rt, + const jsi::Object &value, + const std::shared_ptr &jsInvoker) { + SampleTurboModuleOptionalBaseAnimal result{ + bridging::fromJs(rt, value.getProperty(rt, \\"name\\"), jsInvoker)}; + return result; + } + +#ifdef DEBUG + static jsi::String nameToJs(jsi::Runtime &rt, P0 value) { + return bridging::toJs(rt, value); + } +#endif + + static jsi::Object toJs( + jsi::Runtime &rt, + const SampleTurboModuleOptionalBaseAnimal &value, + const std::shared_ptr &jsInvoker) { + auto result = facebook::jsi::Object(rt); + if (value.name) { + result.setProperty(rt, \\"name\\", bridging::toJs(rt, value.name.value(), jsInvoker)); + } + return result; + } + }; + +class JSI_EXPORT NativeSampleTurboModuleOptionalCxxSpecJSI : public TurboModule { +protected: + NativeSampleTurboModuleOptionalCxxSpecJSI(std::shared_ptr jsInvoker); + +public: + virtual jsi::Object getConstants(jsi::Runtime &rt) = 0; + virtual void voidFunc(jsi::Runtime &rt) = 0; + virtual bool getBool(jsi::Runtime &rt, std::optional arg) = 0; + virtual double getNumber(jsi::Runtime &rt, std::optional arg) = 0; + virtual jsi::String getString(jsi::Runtime &rt, std::optional arg) = 0; + virtual jsi::Array getArray(jsi::Runtime &rt, std::optional arg) = 0; + virtual jsi::Object getObject(jsi::Runtime &rt, std::optional arg) = 0; + virtual jsi::Object getObjectShape(jsi::Runtime &rt, std::optional arg) = 0; + virtual jsi::Object getAlias(jsi::Runtime &rt, std::optional arg) = 0; + virtual double getRootTag(jsi::Runtime &rt, std::optional arg) = 0; + virtual jsi::Object getValue(jsi::Runtime &rt, std::optional x, std::optional y, std::optional z) = 0; + virtual void getValueWithCallback(jsi::Runtime &rt, std::optional callback) = 0; + virtual jsi::Value getValueWithPromise(jsi::Runtime &rt, std::optional error) = 0; + +}; + +template +class JSI_EXPORT NativeSampleTurboModuleOptionalCxxSpec : public TurboModule { +public: + jsi::Value get(jsi::Runtime &rt, const jsi::PropNameID &propName) override { + return delegate_.get(rt, propName); + } + +protected: + NativeSampleTurboModuleOptionalCxxSpec(std::shared_ptr jsInvoker) + : TurboModule(\\"SampleTurboModuleOptional\\", jsInvoker), + delegate_(static_cast(this), jsInvoker) {} + +private: + class Delegate : public NativeSampleTurboModuleOptionalCxxSpecJSI { + public: + Delegate(T *instance, std::shared_ptr jsInvoker) : + NativeSampleTurboModuleOptionalCxxSpecJSI(std::move(jsInvoker)), instance_(instance) {} + + jsi::Object getConstants(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::getConstants) == 1, + \\"Expected getConstants(...) to have 1 parameters\\"); + + return bridging::callFromJs( + rt, &T::getConstants, jsInvoker_, instance_); + } + void voidFunc(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::voidFunc) == 1, + \\"Expected voidFunc(...) to have 1 parameters\\"); + + return bridging::callFromJs( + rt, &T::voidFunc, jsInvoker_, instance_); + } + bool getBool(jsi::Runtime &rt, std::optional arg) override { + static_assert( + bridging::getParameterCount(&T::getBool) == 2, + \\"Expected getBool(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getBool, jsInvoker_, instance_, std::move(arg)); + } + double getNumber(jsi::Runtime &rt, std::optional arg) override { + static_assert( + bridging::getParameterCount(&T::getNumber) == 2, + \\"Expected getNumber(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getNumber, jsInvoker_, instance_, std::move(arg)); + } + jsi::String getString(jsi::Runtime &rt, std::optional arg) override { + static_assert( + bridging::getParameterCount(&T::getString) == 2, + \\"Expected getString(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getString, jsInvoker_, instance_, std::move(arg)); + } + jsi::Array getArray(jsi::Runtime &rt, std::optional arg) override { + static_assert( + bridging::getParameterCount(&T::getArray) == 2, + \\"Expected getArray(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getArray, jsInvoker_, instance_, std::move(arg)); + } + jsi::Object getObject(jsi::Runtime &rt, std::optional arg) override { + static_assert( + bridging::getParameterCount(&T::getObject) == 2, + \\"Expected getObject(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getObject, jsInvoker_, instance_, std::move(arg)); + } + jsi::Object getObjectShape(jsi::Runtime &rt, std::optional arg) override { + static_assert( + bridging::getParameterCount(&T::getObjectShape) == 2, + \\"Expected getObjectShape(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getObjectShape, jsInvoker_, instance_, std::move(arg)); + } + jsi::Object getAlias(jsi::Runtime &rt, std::optional arg) override { + static_assert( + bridging::getParameterCount(&T::getAlias) == 2, + \\"Expected getAlias(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getAlias, jsInvoker_, instance_, std::move(arg)); + } + double getRootTag(jsi::Runtime &rt, std::optional arg) override { + static_assert( + bridging::getParameterCount(&T::getRootTag) == 2, + \\"Expected getRootTag(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getRootTag, jsInvoker_, instance_, std::move(arg)); + } + jsi::Object getValue(jsi::Runtime &rt, std::optional x, std::optional y, std::optional z) override { + static_assert( + bridging::getParameterCount(&T::getValue) == 4, + \\"Expected getValue(...) to have 4 parameters\\"); + + return bridging::callFromJs( + rt, &T::getValue, jsInvoker_, instance_, std::move(x), std::move(y), std::move(z)); + } + void getValueWithCallback(jsi::Runtime &rt, std::optional callback) override { + static_assert( + bridging::getParameterCount(&T::getValueWithCallback) == 2, + \\"Expected getValueWithCallback(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getValueWithCallback, jsInvoker_, instance_, std::move(callback)); + } + jsi::Value getValueWithPromise(jsi::Runtime &rt, std::optional error) override { + static_assert( + bridging::getParameterCount(&T::getValueWithPromise) == 2, + \\"Expected getValueWithPromise(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getValueWithPromise, jsInvoker_, instance_, std::move(error)); + } + + private: + T *instance_; + }; + + Delegate delegate_; +}; + +class JSI_EXPORT NativeStringTurboModuleCxxSpecJSI : public TurboModule { +protected: + NativeStringTurboModuleCxxSpecJSI(std::shared_ptr jsInvoker); + +public: + virtual jsi::String getString(jsi::Runtime &rt, jsi::String arg) = 0; + virtual jsi::String getStringWithAlias(jsi::Runtime &rt, jsi::String arg) = 0; + +}; + +template +class JSI_EXPORT NativeStringTurboModuleCxxSpec : public TurboModule { +public: + jsi::Value get(jsi::Runtime &rt, const jsi::PropNameID &propName) override { + return delegate_.get(rt, propName); + } + +protected: + NativeStringTurboModuleCxxSpec(std::shared_ptr jsInvoker) + : TurboModule(\\"SampleTurboModule\\", jsInvoker), + delegate_(static_cast(this), jsInvoker) {} + +private: + class Delegate : public NativeStringTurboModuleCxxSpecJSI { + public: + Delegate(T *instance, std::shared_ptr jsInvoker) : + NativeStringTurboModuleCxxSpecJSI(std::move(jsInvoker)), instance_(instance) {} + + jsi::String getString(jsi::Runtime &rt, jsi::String arg) override { + static_assert( + bridging::getParameterCount(&T::getString) == 2, + \\"Expected getString(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getString, jsInvoker_, instance_, std::move(arg)); + } + jsi::String getStringWithAlias(jsi::Runtime &rt, jsi::String arg) override { + static_assert( + bridging::getParameterCount(&T::getStringWithAlias) == 2, + \\"Expected getStringWithAlias(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getStringWithAlias, jsInvoker_, instance_, std::move(arg)); + } + + private: + T *instance_; + }; + + Delegate delegate_; +}; + +} // namespace react +} // namespace facebook +" +`; + +exports[`GenerateModuleH can generate a header file NativeModule specs with assume nonnull enabled 1`] = ` +"/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleH.js + */ + +#pragma once + +#include +#include + +namespace facebook { +namespace react { + +class JSI_EXPORT NativeArrayTurboModuleCxxSpecJSI : public TurboModule { +protected: + NativeArrayTurboModuleCxxSpecJSI(std::shared_ptr jsInvoker); + +public: + virtual jsi::Array getArray(jsi::Runtime &rt, jsi::Array a) = 0; + virtual jsi::Array getReadOnlyArray(jsi::Runtime &rt, jsi::Array a) = 0; + virtual jsi::Array getArrayWithAlias(jsi::Runtime &rt, jsi::Array a, jsi::Array b) = 0; + +}; + +template +class JSI_EXPORT NativeArrayTurboModuleCxxSpec : public TurboModule { +public: + jsi::Value get(jsi::Runtime &rt, const jsi::PropNameID &propName) override { + return delegate_.get(rt, propName); + } + +protected: + NativeArrayTurboModuleCxxSpec(std::shared_ptr jsInvoker) + : TurboModule(\\"SampleTurboModule\\", jsInvoker), + delegate_(static_cast(this), jsInvoker) {} + +private: + class Delegate : public NativeArrayTurboModuleCxxSpecJSI { + public: + Delegate(T *instance, std::shared_ptr jsInvoker) : + NativeArrayTurboModuleCxxSpecJSI(std::move(jsInvoker)), instance_(instance) {} + + jsi::Array getArray(jsi::Runtime &rt, jsi::Array a) override { + static_assert( + bridging::getParameterCount(&T::getArray) == 2, + \\"Expected getArray(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getArray, jsInvoker_, instance_, std::move(a)); + } + jsi::Array getReadOnlyArray(jsi::Runtime &rt, jsi::Array a) override { + static_assert( + bridging::getParameterCount(&T::getReadOnlyArray) == 2, + \\"Expected getReadOnlyArray(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getReadOnlyArray, jsInvoker_, instance_, std::move(a)); + } + jsi::Array getArrayWithAlias(jsi::Runtime &rt, jsi::Array a, jsi::Array b) override { + static_assert( + bridging::getParameterCount(&T::getArrayWithAlias) == 3, + \\"Expected getArrayWithAlias(...) to have 3 parameters\\"); + + return bridging::callFromJs( + rt, &T::getArrayWithAlias, jsInvoker_, instance_, std::move(a), std::move(b)); + } + + private: + T *instance_; + }; + + Delegate delegate_; +}; + +class JSI_EXPORT NativeBooleanTurboModuleCxxSpecJSI : public TurboModule { +protected: + NativeBooleanTurboModuleCxxSpecJSI(std::shared_ptr jsInvoker); + +public: + virtual bool getBoolean(jsi::Runtime &rt, bool arg) = 0; + virtual bool getBooleanWithAlias(jsi::Runtime &rt, bool arg) = 0; + +}; + +template +class JSI_EXPORT NativeBooleanTurboModuleCxxSpec : public TurboModule { +public: + jsi::Value get(jsi::Runtime &rt, const jsi::PropNameID &propName) override { + return delegate_.get(rt, propName); + } + +protected: + NativeBooleanTurboModuleCxxSpec(std::shared_ptr jsInvoker) + : TurboModule(\\"SampleTurboModule\\", jsInvoker), + delegate_(static_cast(this), jsInvoker) {} + +private: + class Delegate : public NativeBooleanTurboModuleCxxSpecJSI { + public: + Delegate(T *instance, std::shared_ptr jsInvoker) : + NativeBooleanTurboModuleCxxSpecJSI(std::move(jsInvoker)), instance_(instance) {} + + bool getBoolean(jsi::Runtime &rt, bool arg) override { + static_assert( + bridging::getParameterCount(&T::getBoolean) == 2, + \\"Expected getBoolean(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getBoolean, jsInvoker_, instance_, std::move(arg)); + } + bool getBooleanWithAlias(jsi::Runtime &rt, bool arg) override { + static_assert( + bridging::getParameterCount(&T::getBooleanWithAlias) == 2, + \\"Expected getBooleanWithAlias(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getBooleanWithAlias, jsInvoker_, instance_, std::move(arg)); + } + + private: + T *instance_; + }; + + Delegate delegate_; +}; + +class JSI_EXPORT NativeCallbackTurboModuleCxxSpecJSI : public TurboModule { +protected: + NativeCallbackTurboModuleCxxSpecJSI(std::shared_ptr jsInvoker); + +public: + virtual void getValueWithCallback(jsi::Runtime &rt, jsi::Function callback) = 0; + virtual void getValueWithCallbackWithAlias(jsi::Runtime &rt, jsi::Function c) = 0; + +}; + +template +class JSI_EXPORT NativeCallbackTurboModuleCxxSpec : public TurboModule { +public: + jsi::Value get(jsi::Runtime &rt, const jsi::PropNameID &propName) override { + return delegate_.get(rt, propName); + } + +protected: + NativeCallbackTurboModuleCxxSpec(std::shared_ptr jsInvoker) + : TurboModule(\\"SampleTurboModule\\", jsInvoker), + delegate_(static_cast(this), jsInvoker) {} + +private: + class Delegate : public NativeCallbackTurboModuleCxxSpecJSI { + public: + Delegate(T *instance, std::shared_ptr jsInvoker) : + NativeCallbackTurboModuleCxxSpecJSI(std::move(jsInvoker)), instance_(instance) {} + + void getValueWithCallback(jsi::Runtime &rt, jsi::Function callback) override { + static_assert( + bridging::getParameterCount(&T::getValueWithCallback) == 2, + \\"Expected getValueWithCallback(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getValueWithCallback, jsInvoker_, instance_, std::move(callback)); + } + void getValueWithCallbackWithAlias(jsi::Runtime &rt, jsi::Function c) override { + static_assert( + bridging::getParameterCount(&T::getValueWithCallbackWithAlias) == 2, + \\"Expected getValueWithCallbackWithAlias(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getValueWithCallbackWithAlias, jsInvoker_, instance_, std::move(c)); + } + + private: + T *instance_; + }; + + Delegate delegate_; +}; + +#pragma mark - NativeEnumTurboModuleBaseStateType + +template +struct NativeEnumTurboModuleBaseStateType { + P0 state; + bool operator==(const NativeEnumTurboModuleBaseStateType &other) const { + return state == other.state; + } +}; + +template +struct NativeEnumTurboModuleBaseStateTypeBridging { + static NativeEnumTurboModuleBaseStateType fromJs( + jsi::Runtime &rt, + const jsi::Object &value, + const std::shared_ptr &jsInvoker) { + NativeEnumTurboModuleBaseStateType result{ + bridging::fromJs(rt, value.getProperty(rt, \\"state\\"), jsInvoker)}; + return result; + } + +#ifdef DEBUG + static jsi::String stateToJs(jsi::Runtime &rt, P0 value) { + return bridging::toJs(rt, value); + } +#endif + + static jsi::Object toJs( + jsi::Runtime &rt, + const NativeEnumTurboModuleBaseStateType &value, + const std::shared_ptr &jsInvoker) { + auto result = facebook::jsi::Object(rt); + result.setProperty(rt, \\"state\\", bridging::toJs(rt, value.state, jsInvoker)); + return result; + } + }; + + +#pragma mark - NativeEnumTurboModuleBaseStateTypeWithEnums + +template +struct NativeEnumTurboModuleBaseStateTypeWithEnums { + P0 state; + P1 regular; + P2 str; + P3 num; + P4 fraction; + bool operator==(const NativeEnumTurboModuleBaseStateTypeWithEnums &other) const { + return state == other.state && regular == other.regular && str == other.str && num == other.num && fraction == other.fraction; + } +}; + +template +struct NativeEnumTurboModuleBaseStateTypeWithEnumsBridging { + static NativeEnumTurboModuleBaseStateTypeWithEnums fromJs( + jsi::Runtime &rt, + const jsi::Object &value, + const std::shared_ptr &jsInvoker) { + NativeEnumTurboModuleBaseStateTypeWithEnums result{ + bridging::fromJs(rt, value.getProperty(rt, \\"state\\"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, \\"regular\\"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, \\"str\\"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, \\"num\\"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, \\"fraction\\"), jsInvoker)}; + return result; + } + +#ifdef DEBUG + static jsi::String stateToJs(jsi::Runtime &rt, P0 value) { + return bridging::toJs(rt, value); + } + static jsi::String regularToJs(jsi::Runtime &rt, P1 value) { + return bridging::toJs(rt, value); + } + static jsi::String strToJs(jsi::Runtime &rt, P2 value) { + return bridging::toJs(rt, value); + } + static double numToJs(jsi::Runtime &rt, P3 value) { + return bridging::toJs(rt, value); + } + static double fractionToJs(jsi::Runtime &rt, P4 value) { + return bridging::toJs(rt, value); + } +#endif + + static jsi::Object toJs( + jsi::Runtime &rt, + const NativeEnumTurboModuleBaseStateTypeWithEnums &value, + const std::shared_ptr &jsInvoker) { + auto result = facebook::jsi::Object(rt); + result.setProperty(rt, \\"state\\", bridging::toJs(rt, value.state, jsInvoker)); + result.setProperty(rt, \\"regular\\", bridging::toJs(rt, value.regular, jsInvoker)); + result.setProperty(rt, \\"str\\", bridging::toJs(rt, value.str, jsInvoker)); + result.setProperty(rt, \\"num\\", bridging::toJs(rt, value.num, jsInvoker)); + result.setProperty(rt, \\"fraction\\", bridging::toJs(rt, value.fraction, jsInvoker)); + return result; + } + }; + +class JSI_EXPORT NativeEnumTurboModuleCxxSpecJSI : public TurboModule { +protected: + NativeEnumTurboModuleCxxSpecJSI(std::shared_ptr jsInvoker); + +public: + virtual jsi::String getStatusRegular(jsi::Runtime &rt, jsi::Object statusProp) = 0; + virtual jsi::String getStatusStr(jsi::Runtime &rt, jsi::Object statusProp) = 0; + virtual double getStatusNum(jsi::Runtime &rt, jsi::Object statusProp) = 0; + virtual double getStatusFraction(jsi::Runtime &rt, jsi::Object statusProp) = 0; + virtual jsi::Object getStateType(jsi::Runtime &rt, jsi::String a, jsi::String b, double c, double d) = 0; + virtual jsi::Object getStateTypeWithEnums(jsi::Runtime &rt, jsi::Object paramOfTypeWithEnums) = 0; + +}; + +template +class JSI_EXPORT NativeEnumTurboModuleCxxSpec : public TurboModule { +public: + jsi::Value get(jsi::Runtime &rt, const jsi::PropNameID &propName) override { + return delegate_.get(rt, propName); + } + +protected: + NativeEnumTurboModuleCxxSpec(std::shared_ptr jsInvoker) + : TurboModule(\\"NativeEnumTurboModule\\", jsInvoker), + delegate_(static_cast(this), jsInvoker) {} + +private: + class Delegate : public NativeEnumTurboModuleCxxSpecJSI { + public: + Delegate(T *instance, std::shared_ptr jsInvoker) : + NativeEnumTurboModuleCxxSpecJSI(std::move(jsInvoker)), instance_(instance) {} + + jsi::String getStatusRegular(jsi::Runtime &rt, jsi::Object statusProp) override { + static_assert( + bridging::getParameterCount(&T::getStatusRegular) == 2, + \\"Expected getStatusRegular(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getStatusRegular, jsInvoker_, instance_, std::move(statusProp)); + } + jsi::String getStatusStr(jsi::Runtime &rt, jsi::Object statusProp) override { + static_assert( + bridging::getParameterCount(&T::getStatusStr) == 2, + \\"Expected getStatusStr(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getStatusStr, jsInvoker_, instance_, std::move(statusProp)); + } + double getStatusNum(jsi::Runtime &rt, jsi::Object statusProp) override { + static_assert( + bridging::getParameterCount(&T::getStatusNum) == 2, + \\"Expected getStatusNum(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getStatusNum, jsInvoker_, instance_, std::move(statusProp)); + } + double getStatusFraction(jsi::Runtime &rt, jsi::Object statusProp) override { + static_assert( + bridging::getParameterCount(&T::getStatusFraction) == 2, + \\"Expected getStatusFraction(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getStatusFraction, jsInvoker_, instance_, std::move(statusProp)); + } + jsi::Object getStateType(jsi::Runtime &rt, jsi::String a, jsi::String b, double c, double d) override { + static_assert( + bridging::getParameterCount(&T::getStateType) == 5, + \\"Expected getStateType(...) to have 5 parameters\\"); + + return bridging::callFromJs( + rt, &T::getStateType, jsInvoker_, instance_, std::move(a), std::move(b), std::move(c), std::move(d)); + } + jsi::Object getStateTypeWithEnums(jsi::Runtime &rt, jsi::Object paramOfTypeWithEnums) override { + static_assert( + bridging::getParameterCount(&T::getStateTypeWithEnums) == 2, + \\"Expected getStateTypeWithEnums(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getStateTypeWithEnums, jsInvoker_, instance_, std::move(paramOfTypeWithEnums)); + } + + private: + T *instance_; + }; + + Delegate delegate_; +}; + +class JSI_EXPORT NativeNullableTurboModuleCxxSpecJSI : public TurboModule { +protected: + NativeNullableTurboModuleCxxSpecJSI(std::shared_ptr jsInvoker); + +public: + virtual std::optional getBool(jsi::Runtime &rt, std::optional a) = 0; + virtual std::optional getNumber(jsi::Runtime &rt, std::optional a) = 0; + virtual std::optional getString(jsi::Runtime &rt, std::optional a) = 0; + virtual std::optional getArray(jsi::Runtime &rt, std::optional a) = 0; + virtual std::optional getObject(jsi::Runtime &rt, std::optional a) = 0; + virtual std::optional getValueWithPromise(jsi::Runtime &rt) = 0; + +}; + +template +class JSI_EXPORT NativeNullableTurboModuleCxxSpec : public TurboModule { +public: + jsi::Value get(jsi::Runtime &rt, const jsi::PropNameID &propName) override { + return delegate_.get(rt, propName); + } + +protected: + NativeNullableTurboModuleCxxSpec(std::shared_ptr jsInvoker) + : TurboModule(\\"SampleTurboModule\\", jsInvoker), + delegate_(static_cast(this), jsInvoker) {} + +private: + class Delegate : public NativeNullableTurboModuleCxxSpecJSI { + public: + Delegate(T *instance, std::shared_ptr jsInvoker) : + NativeNullableTurboModuleCxxSpecJSI(std::move(jsInvoker)), instance_(instance) {} + + std::optional getBool(jsi::Runtime &rt, std::optional a) override { + static_assert( + bridging::getParameterCount(&T::getBool) == 2, + \\"Expected getBool(...) to have 2 parameters\\"); + + return bridging::callFromJs>( + rt, &T::getBool, jsInvoker_, instance_, std::move(a)); + } + std::optional getNumber(jsi::Runtime &rt, std::optional a) override { + static_assert( + bridging::getParameterCount(&T::getNumber) == 2, + \\"Expected getNumber(...) to have 2 parameters\\"); + + return bridging::callFromJs>( + rt, &T::getNumber, jsInvoker_, instance_, std::move(a)); + } + std::optional getString(jsi::Runtime &rt, std::optional a) override { + static_assert( + bridging::getParameterCount(&T::getString) == 2, + \\"Expected getString(...) to have 2 parameters\\"); + + return bridging::callFromJs>( + rt, &T::getString, jsInvoker_, instance_, std::move(a)); + } + std::optional getArray(jsi::Runtime &rt, std::optional a) override { + static_assert( + bridging::getParameterCount(&T::getArray) == 2, + \\"Expected getArray(...) to have 2 parameters\\"); + + return bridging::callFromJs>( + rt, &T::getArray, jsInvoker_, instance_, std::move(a)); + } + std::optional getObject(jsi::Runtime &rt, std::optional a) override { + static_assert( + bridging::getParameterCount(&T::getObject) == 2, + \\"Expected getObject(...) to have 2 parameters\\"); + + return bridging::callFromJs>( + rt, &T::getObject, jsInvoker_, instance_, std::move(a)); + } + std::optional getValueWithPromise(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::getValueWithPromise) == 1, + \\"Expected getValueWithPromise(...) to have 1 parameters\\"); + + return bridging::callFromJs>( + rt, &T::getValueWithPromise, jsInvoker_, instance_); + } + + private: + T *instance_; + }; + + Delegate delegate_; +}; + +class JSI_EXPORT NativeNumberTurboModuleCxxSpecJSI : public TurboModule { +protected: + NativeNumberTurboModuleCxxSpecJSI(std::shared_ptr jsInvoker); + +public: + virtual double getNumber(jsi::Runtime &rt, double arg) = 0; + virtual double getNumberWithAlias(jsi::Runtime &rt, double arg) = 0; + +}; + +template +class JSI_EXPORT NativeNumberTurboModuleCxxSpec : public TurboModule { +public: + jsi::Value get(jsi::Runtime &rt, const jsi::PropNameID &propName) override { + return delegate_.get(rt, propName); + } + +protected: + NativeNumberTurboModuleCxxSpec(std::shared_ptr jsInvoker) + : TurboModule(\\"SampleTurboModule\\", jsInvoker), + delegate_(static_cast(this), jsInvoker) {} + +private: + class Delegate : public NativeNumberTurboModuleCxxSpecJSI { + public: + Delegate(T *instance, std::shared_ptr jsInvoker) : + NativeNumberTurboModuleCxxSpecJSI(std::move(jsInvoker)), instance_(instance) {} + + double getNumber(jsi::Runtime &rt, double arg) override { + static_assert( + bridging::getParameterCount(&T::getNumber) == 2, + \\"Expected getNumber(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getNumber, jsInvoker_, instance_, std::move(arg)); + } + double getNumberWithAlias(jsi::Runtime &rt, double arg) override { + static_assert( + bridging::getParameterCount(&T::getNumberWithAlias) == 2, + \\"Expected getNumberWithAlias(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getNumberWithAlias, jsInvoker_, instance_, std::move(arg)); + } + + private: + T *instance_; + }; + + Delegate delegate_; +}; + +class JSI_EXPORT NativeObjectTurboModuleCxxSpecJSI : public TurboModule { +protected: + NativeObjectTurboModuleCxxSpecJSI(std::shared_ptr jsInvoker); + +public: + virtual jsi::Object getGenericObject(jsi::Runtime &rt, jsi::Object arg) = 0; + virtual jsi::Object getGenericObjectReadOnly(jsi::Runtime &rt, jsi::Object arg) = 0; + virtual jsi::Object getGenericObjectWithAlias(jsi::Runtime &rt, jsi::Object arg) = 0; + virtual jsi::Object difficultObject(jsi::Runtime &rt, jsi::Object A) = 0; + virtual jsi::Object getConstants(jsi::Runtime &rt) = 0; + +}; + +template +class JSI_EXPORT NativeObjectTurboModuleCxxSpec : public TurboModule { +public: + jsi::Value get(jsi::Runtime &rt, const jsi::PropNameID &propName) override { + return delegate_.get(rt, propName); + } + +protected: + NativeObjectTurboModuleCxxSpec(std::shared_ptr jsInvoker) + : TurboModule(\\"SampleTurboModule\\", jsInvoker), + delegate_(static_cast(this), jsInvoker) {} + +private: + class Delegate : public NativeObjectTurboModuleCxxSpecJSI { + public: + Delegate(T *instance, std::shared_ptr jsInvoker) : + NativeObjectTurboModuleCxxSpecJSI(std::move(jsInvoker)), instance_(instance) {} + + jsi::Object getGenericObject(jsi::Runtime &rt, jsi::Object arg) override { + static_assert( + bridging::getParameterCount(&T::getGenericObject) == 2, + \\"Expected getGenericObject(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getGenericObject, jsInvoker_, instance_, std::move(arg)); + } + jsi::Object getGenericObjectReadOnly(jsi::Runtime &rt, jsi::Object arg) override { + static_assert( + bridging::getParameterCount(&T::getGenericObjectReadOnly) == 2, + \\"Expected getGenericObjectReadOnly(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getGenericObjectReadOnly, jsInvoker_, instance_, std::move(arg)); + } + jsi::Object getGenericObjectWithAlias(jsi::Runtime &rt, jsi::Object arg) override { + static_assert( + bridging::getParameterCount(&T::getGenericObjectWithAlias) == 2, + \\"Expected getGenericObjectWithAlias(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getGenericObjectWithAlias, jsInvoker_, instance_, std::move(arg)); + } + jsi::Object difficultObject(jsi::Runtime &rt, jsi::Object A) override { + static_assert( + bridging::getParameterCount(&T::difficultObject) == 2, + \\"Expected difficultObject(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::difficultObject, jsInvoker_, instance_, std::move(A)); + } + jsi::Object getConstants(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::getConstants) == 1, + \\"Expected getConstants(...) to have 1 parameters\\"); + + return bridging::callFromJs( + rt, &T::getConstants, jsInvoker_, instance_); + } + + private: + T *instance_; + }; + + Delegate delegate_; +}; + +class JSI_EXPORT NativeOptionalObjectTurboModuleCxxSpecJSI : public TurboModule { +protected: + NativeOptionalObjectTurboModuleCxxSpecJSI(std::shared_ptr jsInvoker); + +public: + virtual jsi::Object getConstants(jsi::Runtime &rt) = 0; + +}; + +template +class JSI_EXPORT NativeOptionalObjectTurboModuleCxxSpec : public TurboModule { +public: + jsi::Value get(jsi::Runtime &rt, const jsi::PropNameID &propName) override { + return delegate_.get(rt, propName); + } + +protected: + NativeOptionalObjectTurboModuleCxxSpec(std::shared_ptr jsInvoker) + : TurboModule(\\"SampleTurboModule\\", jsInvoker), + delegate_(static_cast(this), jsInvoker) {} + +private: + class Delegate : public NativeOptionalObjectTurboModuleCxxSpecJSI { + public: + Delegate(T *instance, std::shared_ptr jsInvoker) : + NativeOptionalObjectTurboModuleCxxSpecJSI(std::move(jsInvoker)), instance_(instance) {} + + jsi::Object getConstants(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::getConstants) == 1, + \\"Expected getConstants(...) to have 1 parameters\\"); + + return bridging::callFromJs( + rt, &T::getConstants, jsInvoker_, instance_); + } + + private: + T *instance_; + }; + + Delegate delegate_; +}; + +#pragma mark - NativePartialAnnotationTurboModuleBaseSomeObj + +template +struct NativePartialAnnotationTurboModuleBaseSomeObj { + P0 a; + P1 b; + bool operator==(const NativePartialAnnotationTurboModuleBaseSomeObj &other) const { + return a == other.a && b == other.b; + } +}; + +template +struct NativePartialAnnotationTurboModuleBaseSomeObjBridging { + static NativePartialAnnotationTurboModuleBaseSomeObj fromJs( + jsi::Runtime &rt, + const jsi::Object &value, + const std::shared_ptr &jsInvoker) { + NativePartialAnnotationTurboModuleBaseSomeObj result{ + bridging::fromJs(rt, value.getProperty(rt, \\"a\\"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, \\"b\\"), jsInvoker)}; + return result; + } + +#ifdef DEBUG + static jsi::String aToJs(jsi::Runtime &rt, P0 value) { + return bridging::toJs(rt, value); + } + static bool bToJs(jsi::Runtime &rt, P1 value) { + return bridging::toJs(rt, value); + } +#endif + + static jsi::Object toJs( + jsi::Runtime &rt, + const NativePartialAnnotationTurboModuleBaseSomeObj &value, + const std::shared_ptr &jsInvoker) { + auto result = facebook::jsi::Object(rt); + result.setProperty(rt, \\"a\\", bridging::toJs(rt, value.a, jsInvoker)); + if (value.b) { + result.setProperty(rt, \\"b\\", bridging::toJs(rt, value.b.value(), jsInvoker)); + } + return result; + } + }; + +class JSI_EXPORT NativePartialAnnotationTurboModuleCxxSpecJSI : public TurboModule { +protected: + NativePartialAnnotationTurboModuleCxxSpecJSI(std::shared_ptr jsInvoker); + +public: + virtual jsi::Object getSomeObj(jsi::Runtime &rt) = 0; + virtual jsi::Object getPartialSomeObj(jsi::Runtime &rt) = 0; + virtual jsi::Object getSomeObjFromPartialSomeObj(jsi::Runtime &rt, jsi::Object value) = 0; + virtual jsi::Object getPartialPartial(jsi::Runtime &rt, jsi::Object value1, jsi::Object value2) = 0; + +}; + +template +class JSI_EXPORT NativePartialAnnotationTurboModuleCxxSpec : public TurboModule { +public: + jsi::Value get(jsi::Runtime &rt, const jsi::PropNameID &propName) override { + return delegate_.get(rt, propName); + } + +protected: + NativePartialAnnotationTurboModuleCxxSpec(std::shared_ptr jsInvoker) + : TurboModule(\\"NativePartialAnnotationTurboModule\\", jsInvoker), + delegate_(static_cast(this), jsInvoker) {} + +private: + class Delegate : public NativePartialAnnotationTurboModuleCxxSpecJSI { + public: + Delegate(T *instance, std::shared_ptr jsInvoker) : + NativePartialAnnotationTurboModuleCxxSpecJSI(std::move(jsInvoker)), instance_(instance) {} + + jsi::Object getSomeObj(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::getSomeObj) == 1, + \\"Expected getSomeObj(...) to have 1 parameters\\"); + + return bridging::callFromJs( + rt, &T::getSomeObj, jsInvoker_, instance_); + } + jsi::Object getPartialSomeObj(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::getPartialSomeObj) == 1, + \\"Expected getPartialSomeObj(...) to have 1 parameters\\"); + + return bridging::callFromJs( + rt, &T::getPartialSomeObj, jsInvoker_, instance_); + } + jsi::Object getSomeObjFromPartialSomeObj(jsi::Runtime &rt, jsi::Object value) override { + static_assert( + bridging::getParameterCount(&T::getSomeObjFromPartialSomeObj) == 2, + \\"Expected getSomeObjFromPartialSomeObj(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getSomeObjFromPartialSomeObj, jsInvoker_, instance_, std::move(value)); + } + jsi::Object getPartialPartial(jsi::Runtime &rt, jsi::Object value1, jsi::Object value2) override { + static_assert( + bridging::getParameterCount(&T::getPartialPartial) == 3, + \\"Expected getPartialPartial(...) to have 3 parameters\\"); + + return bridging::callFromJs( + rt, &T::getPartialPartial, jsInvoker_, instance_, std::move(value1), std::move(value2)); + } + + private: + T *instance_; + }; + + Delegate delegate_; +}; + +class JSI_EXPORT NativePromiseTurboModuleCxxSpecJSI : public TurboModule { +protected: + NativePromiseTurboModuleCxxSpecJSI(std::shared_ptr jsInvoker); + +public: + virtual jsi::Value getValueWithPromise(jsi::Runtime &rt, bool error) = 0; + virtual jsi::Value getValueWithPromiseWithAlias(jsi::Runtime &rt, jsi::String arg) = 0; + +}; + +template +class JSI_EXPORT NativePromiseTurboModuleCxxSpec : public TurboModule { +public: + jsi::Value get(jsi::Runtime &rt, const jsi::PropNameID &propName) override { + return delegate_.get(rt, propName); + } + +protected: + NativePromiseTurboModuleCxxSpec(std::shared_ptr jsInvoker) + : TurboModule(\\"SampleTurboModule\\", jsInvoker), + delegate_(static_cast(this), jsInvoker) {} + +private: + class Delegate : public NativePromiseTurboModuleCxxSpecJSI { + public: + Delegate(T *instance, std::shared_ptr jsInvoker) : + NativePromiseTurboModuleCxxSpecJSI(std::move(jsInvoker)), instance_(instance) {} + + jsi::Value getValueWithPromise(jsi::Runtime &rt, bool error) override { + static_assert( + bridging::getParameterCount(&T::getValueWithPromise) == 2, + \\"Expected getValueWithPromise(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getValueWithPromise, jsInvoker_, instance_, std::move(error)); + } + jsi::Value getValueWithPromiseWithAlias(jsi::Runtime &rt, jsi::String arg) override { + static_assert( + bridging::getParameterCount(&T::getValueWithPromiseWithAlias) == 2, + \\"Expected getValueWithPromiseWithAlias(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getValueWithPromiseWithAlias, jsInvoker_, instance_, std::move(arg)); + } + + private: + T *instance_; + }; + + Delegate delegate_; +}; + +#pragma mark - SampleTurboModuleBaseAnimal + +template +struct SampleTurboModuleBaseAnimal { + P0 name; + bool operator==(const SampleTurboModuleBaseAnimal &other) const { + return name == other.name; + } +}; + +template +struct SampleTurboModuleBaseAnimalBridging { + static SampleTurboModuleBaseAnimal fromJs( + jsi::Runtime &rt, + const jsi::Object &value, + const std::shared_ptr &jsInvoker) { + SampleTurboModuleBaseAnimal result{ + bridging::fromJs(rt, value.getProperty(rt, \\"name\\"), jsInvoker)}; + return result; + } + +#ifdef DEBUG + static jsi::String nameToJs(jsi::Runtime &rt, P0 value) { + return bridging::toJs(rt, value); + } +#endif + + static jsi::Object toJs( + jsi::Runtime &rt, + const SampleTurboModuleBaseAnimal &value, + const std::shared_ptr &jsInvoker) { + auto result = facebook::jsi::Object(rt); + result.setProperty(rt, \\"name\\", bridging::toJs(rt, value.name, jsInvoker)); + return result; + } + }; + +class JSI_EXPORT NativeSampleTurboModuleCxxSpecJSI : public TurboModule { +protected: + NativeSampleTurboModuleCxxSpecJSI(std::shared_ptr jsInvoker); + +public: + virtual jsi::Object getConstants(jsi::Runtime &rt) = 0; + virtual void voidFunc(jsi::Runtime &rt) = 0; + virtual bool getBool(jsi::Runtime &rt, bool arg) = 0; + virtual double getNumber(jsi::Runtime &rt, double arg) = 0; + virtual jsi::String getString(jsi::Runtime &rt, jsi::String arg) = 0; + virtual jsi::Array getArray(jsi::Runtime &rt, jsi::Array arg) = 0; + virtual jsi::Object getObject(jsi::Runtime &rt, jsi::Object arg) = 0; + virtual jsi::Object getObjectShape(jsi::Runtime &rt, jsi::Object arg) = 0; + virtual jsi::Object getAlias(jsi::Runtime &rt, jsi::Object arg) = 0; + virtual double getRootTag(jsi::Runtime &rt, double arg) = 0; + virtual jsi::Object getValue(jsi::Runtime &rt, double x, jsi::String getValuegetValuegetValuegetValuegetValuey, jsi::Object z) = 0; + virtual void getValueWithCallback(jsi::Runtime &rt, jsi::Function callback) = 0; + virtual jsi::Value getValueWithPromise(jsi::Runtime &rt, bool error) = 0; + +}; + +template +class JSI_EXPORT NativeSampleTurboModuleCxxSpec : public TurboModule { +public: + jsi::Value get(jsi::Runtime &rt, const jsi::PropNameID &propName) override { + return delegate_.get(rt, propName); + } + +protected: + NativeSampleTurboModuleCxxSpec(std::shared_ptr jsInvoker) + : TurboModule(\\"SampleTurboModule\\", jsInvoker), + delegate_(static_cast(this), jsInvoker) {} + +private: + class Delegate : public NativeSampleTurboModuleCxxSpecJSI { + public: + Delegate(T *instance, std::shared_ptr jsInvoker) : + NativeSampleTurboModuleCxxSpecJSI(std::move(jsInvoker)), instance_(instance) {} + + jsi::Object getConstants(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::getConstants) == 1, + \\"Expected getConstants(...) to have 1 parameters\\"); + + return bridging::callFromJs( + rt, &T::getConstants, jsInvoker_, instance_); + } + void voidFunc(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::voidFunc) == 1, + \\"Expected voidFunc(...) to have 1 parameters\\"); + + return bridging::callFromJs( + rt, &T::voidFunc, jsInvoker_, instance_); + } + bool getBool(jsi::Runtime &rt, bool arg) override { + static_assert( + bridging::getParameterCount(&T::getBool) == 2, + \\"Expected getBool(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getBool, jsInvoker_, instance_, std::move(arg)); + } + double getNumber(jsi::Runtime &rt, double arg) override { + static_assert( + bridging::getParameterCount(&T::getNumber) == 2, + \\"Expected getNumber(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getNumber, jsInvoker_, instance_, std::move(arg)); + } + jsi::String getString(jsi::Runtime &rt, jsi::String arg) override { + static_assert( + bridging::getParameterCount(&T::getString) == 2, + \\"Expected getString(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getString, jsInvoker_, instance_, std::move(arg)); + } + jsi::Array getArray(jsi::Runtime &rt, jsi::Array arg) override { + static_assert( + bridging::getParameterCount(&T::getArray) == 2, + \\"Expected getArray(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getArray, jsInvoker_, instance_, std::move(arg)); + } + jsi::Object getObject(jsi::Runtime &rt, jsi::Object arg) override { + static_assert( + bridging::getParameterCount(&T::getObject) == 2, + \\"Expected getObject(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getObject, jsInvoker_, instance_, std::move(arg)); + } + jsi::Object getObjectShape(jsi::Runtime &rt, jsi::Object arg) override { + static_assert( + bridging::getParameterCount(&T::getObjectShape) == 2, + \\"Expected getObjectShape(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getObjectShape, jsInvoker_, instance_, std::move(arg)); + } + jsi::Object getAlias(jsi::Runtime &rt, jsi::Object arg) override { + static_assert( + bridging::getParameterCount(&T::getAlias) == 2, + \\"Expected getAlias(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getAlias, jsInvoker_, instance_, std::move(arg)); + } + double getRootTag(jsi::Runtime &rt, double arg) override { + static_assert( + bridging::getParameterCount(&T::getRootTag) == 2, + \\"Expected getRootTag(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getRootTag, jsInvoker_, instance_, std::move(arg)); + } + jsi::Object getValue(jsi::Runtime &rt, double x, jsi::String getValuegetValuegetValuegetValuegetValuey, jsi::Object z) override { + static_assert( + bridging::getParameterCount(&T::getValue) == 4, + \\"Expected getValue(...) to have 4 parameters\\"); + + return bridging::callFromJs( + rt, &T::getValue, jsInvoker_, instance_, std::move(x), std::move(getValuegetValuegetValuegetValuegetValuey), std::move(z)); + } + void getValueWithCallback(jsi::Runtime &rt, jsi::Function callback) override { + static_assert( + bridging::getParameterCount(&T::getValueWithCallback) == 2, + \\"Expected getValueWithCallback(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getValueWithCallback, jsInvoker_, instance_, std::move(callback)); + } + jsi::Value getValueWithPromise(jsi::Runtime &rt, bool error) override { + static_assert( + bridging::getParameterCount(&T::getValueWithPromise) == 2, + \\"Expected getValueWithPromise(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getValueWithPromise, jsInvoker_, instance_, std::move(error)); + } + + private: + T *instance_; + }; + + Delegate delegate_; +}; + +#pragma mark - SampleTurboModuleArraysBaseAnimal + +template +struct SampleTurboModuleArraysBaseAnimal { + P0 name; + bool operator==(const SampleTurboModuleArraysBaseAnimal &other) const { + return name == other.name; + } +}; + +template +struct SampleTurboModuleArraysBaseAnimalBridging { + static SampleTurboModuleArraysBaseAnimal fromJs( + jsi::Runtime &rt, + const jsi::Object &value, + const std::shared_ptr &jsInvoker) { + SampleTurboModuleArraysBaseAnimal result{ + bridging::fromJs(rt, value.getProperty(rt, \\"name\\"), jsInvoker)}; + return result; + } + +#ifdef DEBUG + static jsi::String nameToJs(jsi::Runtime &rt, P0 value) { + return bridging::toJs(rt, value); + } +#endif + + static jsi::Object toJs( + jsi::Runtime &rt, + const SampleTurboModuleArraysBaseAnimal &value, + const std::shared_ptr &jsInvoker) { + auto result = facebook::jsi::Object(rt); + result.setProperty(rt, \\"name\\", bridging::toJs(rt, value.name, jsInvoker)); + return result; + } + }; + +class JSI_EXPORT NativeSampleTurboModuleArraysCxxSpecJSI : public TurboModule { +protected: + NativeSampleTurboModuleArraysCxxSpecJSI(std::shared_ptr jsInvoker); + +public: + virtual jsi::Object getConstants(jsi::Runtime &rt) = 0; + virtual void voidFunc(jsi::Runtime &rt) = 0; + virtual jsi::Array getBool(jsi::Runtime &rt, jsi::Array id) = 0; + virtual jsi::Array getNumber(jsi::Runtime &rt, jsi::Array arg) = 0; + virtual jsi::Array getString(jsi::Runtime &rt, jsi::Array arg) = 0; + virtual jsi::Array getArray(jsi::Runtime &rt, jsi::Array arg) = 0; + virtual jsi::Array getObject(jsi::Runtime &rt, jsi::Array arg) = 0; + virtual jsi::Array getObjectShape(jsi::Runtime &rt, jsi::Array arg) = 0; + virtual jsi::Array getAlias(jsi::Runtime &rt, jsi::Array arg) = 0; + virtual jsi::Array getRootTag(jsi::Runtime &rt, jsi::Array arg) = 0; + virtual jsi::Array getValue(jsi::Runtime &rt, jsi::Array x, jsi::Array y, jsi::Array z) = 0; + virtual void getValueWithCallback(jsi::Runtime &rt, jsi::Function callback) = 0; + virtual jsi::Value getValueWithPromise(jsi::Runtime &rt, jsi::Array error) = 0; + +}; + +template +class JSI_EXPORT NativeSampleTurboModuleArraysCxxSpec : public TurboModule { +public: + jsi::Value get(jsi::Runtime &rt, const jsi::PropNameID &propName) override { + return delegate_.get(rt, propName); + } + +protected: + NativeSampleTurboModuleArraysCxxSpec(std::shared_ptr jsInvoker) + : TurboModule(\\"SampleTurboModuleArrays\\", jsInvoker), + delegate_(static_cast(this), jsInvoker) {} + +private: + class Delegate : public NativeSampleTurboModuleArraysCxxSpecJSI { + public: + Delegate(T *instance, std::shared_ptr jsInvoker) : + NativeSampleTurboModuleArraysCxxSpecJSI(std::move(jsInvoker)), instance_(instance) {} + + jsi::Object getConstants(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::getConstants) == 1, + \\"Expected getConstants(...) to have 1 parameters\\"); + + return bridging::callFromJs( + rt, &T::getConstants, jsInvoker_, instance_); + } + void voidFunc(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::voidFunc) == 1, + \\"Expected voidFunc(...) to have 1 parameters\\"); + + return bridging::callFromJs( + rt, &T::voidFunc, jsInvoker_, instance_); + } + jsi::Array getBool(jsi::Runtime &rt, jsi::Array id) override { + static_assert( + bridging::getParameterCount(&T::getBool) == 2, + \\"Expected getBool(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getBool, jsInvoker_, instance_, std::move(id)); + } + jsi::Array getNumber(jsi::Runtime &rt, jsi::Array arg) override { + static_assert( + bridging::getParameterCount(&T::getNumber) == 2, + \\"Expected getNumber(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getNumber, jsInvoker_, instance_, std::move(arg)); + } + jsi::Array getString(jsi::Runtime &rt, jsi::Array arg) override { + static_assert( + bridging::getParameterCount(&T::getString) == 2, + \\"Expected getString(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getString, jsInvoker_, instance_, std::move(arg)); + } + jsi::Array getArray(jsi::Runtime &rt, jsi::Array arg) override { + static_assert( + bridging::getParameterCount(&T::getArray) == 2, + \\"Expected getArray(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getArray, jsInvoker_, instance_, std::move(arg)); + } + jsi::Array getObject(jsi::Runtime &rt, jsi::Array arg) override { + static_assert( + bridging::getParameterCount(&T::getObject) == 2, + \\"Expected getObject(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getObject, jsInvoker_, instance_, std::move(arg)); + } + jsi::Array getObjectShape(jsi::Runtime &rt, jsi::Array arg) override { + static_assert( + bridging::getParameterCount(&T::getObjectShape) == 2, + \\"Expected getObjectShape(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getObjectShape, jsInvoker_, instance_, std::move(arg)); + } + jsi::Array getAlias(jsi::Runtime &rt, jsi::Array arg) override { + static_assert( + bridging::getParameterCount(&T::getAlias) == 2, + \\"Expected getAlias(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getAlias, jsInvoker_, instance_, std::move(arg)); + } + jsi::Array getRootTag(jsi::Runtime &rt, jsi::Array arg) override { + static_assert( + bridging::getParameterCount(&T::getRootTag) == 2, + \\"Expected getRootTag(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getRootTag, jsInvoker_, instance_, std::move(arg)); + } + jsi::Array getValue(jsi::Runtime &rt, jsi::Array x, jsi::Array y, jsi::Array z) override { + static_assert( + bridging::getParameterCount(&T::getValue) == 4, + \\"Expected getValue(...) to have 4 parameters\\"); + + return bridging::callFromJs( + rt, &T::getValue, jsInvoker_, instance_, std::move(x), std::move(y), std::move(z)); + } + void getValueWithCallback(jsi::Runtime &rt, jsi::Function callback) override { + static_assert( + bridging::getParameterCount(&T::getValueWithCallback) == 2, + \\"Expected getValueWithCallback(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getValueWithCallback, jsInvoker_, instance_, std::move(callback)); + } + jsi::Value getValueWithPromise(jsi::Runtime &rt, jsi::Array error) override { + static_assert( + bridging::getParameterCount(&T::getValueWithPromise) == 2, + \\"Expected getValueWithPromise(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getValueWithPromise, jsInvoker_, instance_, std::move(error)); + } + + private: + T *instance_; + }; + + Delegate delegate_; +}; + +#pragma mark - SampleTurboModuleNullableBaseAnimal + +template +struct SampleTurboModuleNullableBaseAnimal { + P0 name; + bool operator==(const SampleTurboModuleNullableBaseAnimal &other) const { + return name == other.name; + } +}; + +template +struct SampleTurboModuleNullableBaseAnimalBridging { + static SampleTurboModuleNullableBaseAnimal fromJs( + jsi::Runtime &rt, + const jsi::Object &value, + const std::shared_ptr &jsInvoker) { + SampleTurboModuleNullableBaseAnimal result{ + bridging::fromJs(rt, value.getProperty(rt, \\"name\\"), jsInvoker)}; + return result; + } + +#ifdef DEBUG + static std::optional nameToJs(jsi::Runtime &rt, P0 value) { + return bridging::toJs(rt, value); + } +#endif + + static jsi::Object toJs( + jsi::Runtime &rt, + const SampleTurboModuleNullableBaseAnimal &value, + const std::shared_ptr &jsInvoker) { + auto result = facebook::jsi::Object(rt); + result.setProperty(rt, \\"name\\", bridging::toJs(rt, value.name, jsInvoker)); + return result; + } + }; + +class JSI_EXPORT NativeSampleTurboModuleNullableCxxSpecJSI : public TurboModule { +protected: + NativeSampleTurboModuleNullableCxxSpecJSI(std::shared_ptr jsInvoker); + +public: + virtual jsi::Object getConstants(jsi::Runtime &rt) = 0; + virtual void voidFunc(jsi::Runtime &rt) = 0; + virtual std::optional getBool(jsi::Runtime &rt, std::optional arg) = 0; + virtual std::optional getNumber(jsi::Runtime &rt, std::optional arg) = 0; + virtual std::optional getString(jsi::Runtime &rt, std::optional arg) = 0; + virtual std::optional getArray(jsi::Runtime &rt, std::optional arg) = 0; + virtual std::optional getObject(jsi::Runtime &rt, std::optional arg) = 0; + virtual std::optional getObjectShape(jsi::Runtime &rt, std::optional arg) = 0; + virtual std::optional getAlias(jsi::Runtime &rt, std::optional arg) = 0; + virtual std::optional getRootTag(jsi::Runtime &rt, std::optional arg) = 0; + virtual std::optional getValue(jsi::Runtime &rt, std::optional x, std::optional y, std::optional z) = 0; + virtual void getValueWithCallback(jsi::Runtime &rt, jsi::Function callback) = 0; + virtual std::optional getValueWithPromise(jsi::Runtime &rt, std::optional error) = 0; + +}; + +template +class JSI_EXPORT NativeSampleTurboModuleNullableCxxSpec : public TurboModule { +public: + jsi::Value get(jsi::Runtime &rt, const jsi::PropNameID &propName) override { + return delegate_.get(rt, propName); + } + +protected: + NativeSampleTurboModuleNullableCxxSpec(std::shared_ptr jsInvoker) + : TurboModule(\\"SampleTurboModuleNullable\\", jsInvoker), + delegate_(static_cast(this), jsInvoker) {} + +private: + class Delegate : public NativeSampleTurboModuleNullableCxxSpecJSI { + public: + Delegate(T *instance, std::shared_ptr jsInvoker) : + NativeSampleTurboModuleNullableCxxSpecJSI(std::move(jsInvoker)), instance_(instance) {} + + jsi::Object getConstants(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::getConstants) == 1, + \\"Expected getConstants(...) to have 1 parameters\\"); + + return bridging::callFromJs( + rt, &T::getConstants, jsInvoker_, instance_); + } + void voidFunc(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::voidFunc) == 1, + \\"Expected voidFunc(...) to have 1 parameters\\"); + + return bridging::callFromJs( + rt, &T::voidFunc, jsInvoker_, instance_); + } + std::optional getBool(jsi::Runtime &rt, std::optional arg) override { + static_assert( + bridging::getParameterCount(&T::getBool) == 2, + \\"Expected getBool(...) to have 2 parameters\\"); + + return bridging::callFromJs>( + rt, &T::getBool, jsInvoker_, instance_, std::move(arg)); + } + std::optional getNumber(jsi::Runtime &rt, std::optional arg) override { + static_assert( + bridging::getParameterCount(&T::getNumber) == 2, + \\"Expected getNumber(...) to have 2 parameters\\"); + + return bridging::callFromJs>( + rt, &T::getNumber, jsInvoker_, instance_, std::move(arg)); + } + std::optional getString(jsi::Runtime &rt, std::optional arg) override { + static_assert( + bridging::getParameterCount(&T::getString) == 2, + \\"Expected getString(...) to have 2 parameters\\"); + + return bridging::callFromJs>( + rt, &T::getString, jsInvoker_, instance_, std::move(arg)); + } + std::optional getArray(jsi::Runtime &rt, std::optional arg) override { + static_assert( + bridging::getParameterCount(&T::getArray) == 2, + \\"Expected getArray(...) to have 2 parameters\\"); + + return bridging::callFromJs>( + rt, &T::getArray, jsInvoker_, instance_, std::move(arg)); + } + std::optional getObject(jsi::Runtime &rt, std::optional arg) override { + static_assert( + bridging::getParameterCount(&T::getObject) == 2, + \\"Expected getObject(...) to have 2 parameters\\"); + + return bridging::callFromJs>( + rt, &T::getObject, jsInvoker_, instance_, std::move(arg)); + } + std::optional getObjectShape(jsi::Runtime &rt, std::optional arg) override { + static_assert( + bridging::getParameterCount(&T::getObjectShape) == 2, + \\"Expected getObjectShape(...) to have 2 parameters\\"); + + return bridging::callFromJs>( + rt, &T::getObjectShape, jsInvoker_, instance_, std::move(arg)); + } + std::optional getAlias(jsi::Runtime &rt, std::optional arg) override { + static_assert( + bridging::getParameterCount(&T::getAlias) == 2, + \\"Expected getAlias(...) to have 2 parameters\\"); + + return bridging::callFromJs>( + rt, &T::getAlias, jsInvoker_, instance_, std::move(arg)); + } + std::optional getRootTag(jsi::Runtime &rt, std::optional arg) override { + static_assert( + bridging::getParameterCount(&T::getRootTag) == 2, + \\"Expected getRootTag(...) to have 2 parameters\\"); + + return bridging::callFromJs>( + rt, &T::getRootTag, jsInvoker_, instance_, std::move(arg)); + } + std::optional getValue(jsi::Runtime &rt, std::optional x, std::optional y, std::optional z) override { + static_assert( + bridging::getParameterCount(&T::getValue) == 4, + \\"Expected getValue(...) to have 4 parameters\\"); + + return bridging::callFromJs>( + rt, &T::getValue, jsInvoker_, instance_, std::move(x), std::move(y), std::move(z)); + } + void getValueWithCallback(jsi::Runtime &rt, jsi::Function callback) override { + static_assert( + bridging::getParameterCount(&T::getValueWithCallback) == 2, + \\"Expected getValueWithCallback(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getValueWithCallback, jsInvoker_, instance_, std::move(callback)); + } + std::optional getValueWithPromise(jsi::Runtime &rt, std::optional error) override { + static_assert( + bridging::getParameterCount(&T::getValueWithPromise) == 2, + \\"Expected getValueWithPromise(...) to have 2 parameters\\"); + + return bridging::callFromJs>( + rt, &T::getValueWithPromise, jsInvoker_, instance_, std::move(error)); + } + + private: + T *instance_; + }; + + Delegate delegate_; +}; + +#pragma mark - SampleTurboModuleNullableAndOptionalBaseAnimal + +template +struct SampleTurboModuleNullableAndOptionalBaseAnimal { + P0 name; + bool operator==(const SampleTurboModuleNullableAndOptionalBaseAnimal &other) const { + return name == other.name; + } +}; + +template +struct SampleTurboModuleNullableAndOptionalBaseAnimalBridging { + static SampleTurboModuleNullableAndOptionalBaseAnimal fromJs( + jsi::Runtime &rt, + const jsi::Object &value, + const std::shared_ptr &jsInvoker) { + SampleTurboModuleNullableAndOptionalBaseAnimal result{ + bridging::fromJs(rt, value.getProperty(rt, \\"name\\"), jsInvoker)}; + return result; + } + +#ifdef DEBUG + static std::optional nameToJs(jsi::Runtime &rt, P0 value) { + return bridging::toJs(rt, value); + } +#endif + + static jsi::Object toJs( + jsi::Runtime &rt, + const SampleTurboModuleNullableAndOptionalBaseAnimal &value, + const std::shared_ptr &jsInvoker) { + auto result = facebook::jsi::Object(rt); + if (value.name) { + result.setProperty(rt, \\"name\\", bridging::toJs(rt, value.name.value(), jsInvoker)); + } + return result; + } + }; + +class JSI_EXPORT NativeSampleTurboModuleNullableAndOptionalCxxSpecJSI : public TurboModule { +protected: + NativeSampleTurboModuleNullableAndOptionalCxxSpecJSI(std::shared_ptr jsInvoker); + +public: + virtual jsi::Object getConstants(jsi::Runtime &rt) = 0; + virtual void voidFunc(jsi::Runtime &rt) = 0; + virtual std::optional getBool(jsi::Runtime &rt, std::optional arg) = 0; + virtual std::optional getNumber(jsi::Runtime &rt, std::optional arg) = 0; + virtual std::optional getString(jsi::Runtime &rt, std::optional arg) = 0; + virtual std::optional getArray(jsi::Runtime &rt, std::optional arg) = 0; + virtual std::optional getObject(jsi::Runtime &rt, std::optional arg) = 0; + virtual jsi::Object getObjectShape(jsi::Runtime &rt, std::optional arg) = 0; + virtual std::optional getAlias(jsi::Runtime &rt, std::optional arg) = 0; + virtual std::optional getRootTag(jsi::Runtime &rt, std::optional arg) = 0; + virtual std::optional getValue(jsi::Runtime &rt, std::optional x, std::optional y, std::optional z) = 0; + virtual void getValueWithCallback(jsi::Runtime &rt, std::optional callback) = 0; + virtual std::optional getValueWithPromise(jsi::Runtime &rt, std::optional error) = 0; + +}; + +template +class JSI_EXPORT NativeSampleTurboModuleNullableAndOptionalCxxSpec : public TurboModule { +public: + jsi::Value get(jsi::Runtime &rt, const jsi::PropNameID &propName) override { + return delegate_.get(rt, propName); + } + +protected: + NativeSampleTurboModuleNullableAndOptionalCxxSpec(std::shared_ptr jsInvoker) + : TurboModule(\\"SampleTurboModuleNullableAndOptional\\", jsInvoker), + delegate_(static_cast(this), jsInvoker) {} + +private: + class Delegate : public NativeSampleTurboModuleNullableAndOptionalCxxSpecJSI { + public: + Delegate(T *instance, std::shared_ptr jsInvoker) : + NativeSampleTurboModuleNullableAndOptionalCxxSpecJSI(std::move(jsInvoker)), instance_(instance) {} + + jsi::Object getConstants(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::getConstants) == 1, + \\"Expected getConstants(...) to have 1 parameters\\"); + + return bridging::callFromJs( + rt, &T::getConstants, jsInvoker_, instance_); + } + void voidFunc(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::voidFunc) == 1, + \\"Expected voidFunc(...) to have 1 parameters\\"); + + return bridging::callFromJs( + rt, &T::voidFunc, jsInvoker_, instance_); + } + std::optional getBool(jsi::Runtime &rt, std::optional arg) override { + static_assert( + bridging::getParameterCount(&T::getBool) == 2, + \\"Expected getBool(...) to have 2 parameters\\"); + + return bridging::callFromJs>( + rt, &T::getBool, jsInvoker_, instance_, std::move(arg)); + } + std::optional getNumber(jsi::Runtime &rt, std::optional arg) override { + static_assert( + bridging::getParameterCount(&T::getNumber) == 2, + \\"Expected getNumber(...) to have 2 parameters\\"); + + return bridging::callFromJs>( + rt, &T::getNumber, jsInvoker_, instance_, std::move(arg)); + } + std::optional getString(jsi::Runtime &rt, std::optional arg) override { + static_assert( + bridging::getParameterCount(&T::getString) == 2, + \\"Expected getString(...) to have 2 parameters\\"); + + return bridging::callFromJs>( + rt, &T::getString, jsInvoker_, instance_, std::move(arg)); + } + std::optional getArray(jsi::Runtime &rt, std::optional arg) override { + static_assert( + bridging::getParameterCount(&T::getArray) == 2, + \\"Expected getArray(...) to have 2 parameters\\"); + + return bridging::callFromJs>( + rt, &T::getArray, jsInvoker_, instance_, std::move(arg)); + } + std::optional getObject(jsi::Runtime &rt, std::optional arg) override { + static_assert( + bridging::getParameterCount(&T::getObject) == 2, + \\"Expected getObject(...) to have 2 parameters\\"); + + return bridging::callFromJs>( + rt, &T::getObject, jsInvoker_, instance_, std::move(arg)); + } + jsi::Object getObjectShape(jsi::Runtime &rt, std::optional arg) override { + static_assert( + bridging::getParameterCount(&T::getObjectShape) == 2, + \\"Expected getObjectShape(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getObjectShape, jsInvoker_, instance_, std::move(arg)); + } + std::optional getAlias(jsi::Runtime &rt, std::optional arg) override { + static_assert( + bridging::getParameterCount(&T::getAlias) == 2, + \\"Expected getAlias(...) to have 2 parameters\\"); + + return bridging::callFromJs>( + rt, &T::getAlias, jsInvoker_, instance_, std::move(arg)); + } + std::optional getRootTag(jsi::Runtime &rt, std::optional arg) override { + static_assert( + bridging::getParameterCount(&T::getRootTag) == 2, + \\"Expected getRootTag(...) to have 2 parameters\\"); + + return bridging::callFromJs>( + rt, &T::getRootTag, jsInvoker_, instance_, std::move(arg)); + } + std::optional getValue(jsi::Runtime &rt, std::optional x, std::optional y, std::optional z) override { + static_assert( + bridging::getParameterCount(&T::getValue) == 4, + \\"Expected getValue(...) to have 4 parameters\\"); + + return bridging::callFromJs>( + rt, &T::getValue, jsInvoker_, instance_, std::move(x), std::move(y), std::move(z)); + } + void getValueWithCallback(jsi::Runtime &rt, std::optional callback) override { + static_assert( + bridging::getParameterCount(&T::getValueWithCallback) == 2, + \\"Expected getValueWithCallback(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getValueWithCallback, jsInvoker_, instance_, std::move(callback)); + } + std::optional getValueWithPromise(jsi::Runtime &rt, std::optional error) override { + static_assert( + bridging::getParameterCount(&T::getValueWithPromise) == 2, + \\"Expected getValueWithPromise(...) to have 2 parameters\\"); + + return bridging::callFromJs>( + rt, &T::getValueWithPromise, jsInvoker_, instance_, std::move(error)); + } + + private: + T *instance_; + }; + + Delegate delegate_; +}; + +#pragma mark - SampleTurboModuleOptionalBaseAnimal + +template +struct SampleTurboModuleOptionalBaseAnimal { + P0 name; + bool operator==(const SampleTurboModuleOptionalBaseAnimal &other) const { + return name == other.name; + } +}; + +template +struct SampleTurboModuleOptionalBaseAnimalBridging { + static SampleTurboModuleOptionalBaseAnimal fromJs( + jsi::Runtime &rt, + const jsi::Object &value, + const std::shared_ptr &jsInvoker) { + SampleTurboModuleOptionalBaseAnimal result{ + bridging::fromJs(rt, value.getProperty(rt, \\"name\\"), jsInvoker)}; + return result; + } + +#ifdef DEBUG + static jsi::String nameToJs(jsi::Runtime &rt, P0 value) { + return bridging::toJs(rt, value); + } +#endif + + static jsi::Object toJs( + jsi::Runtime &rt, + const SampleTurboModuleOptionalBaseAnimal &value, + const std::shared_ptr &jsInvoker) { + auto result = facebook::jsi::Object(rt); + if (value.name) { + result.setProperty(rt, \\"name\\", bridging::toJs(rt, value.name.value(), jsInvoker)); + } + return result; + } + }; + +class JSI_EXPORT NativeSampleTurboModuleOptionalCxxSpecJSI : public TurboModule { +protected: + NativeSampleTurboModuleOptionalCxxSpecJSI(std::shared_ptr jsInvoker); + +public: + virtual jsi::Object getConstants(jsi::Runtime &rt) = 0; + virtual void voidFunc(jsi::Runtime &rt) = 0; + virtual bool getBool(jsi::Runtime &rt, std::optional arg) = 0; + virtual double getNumber(jsi::Runtime &rt, std::optional arg) = 0; + virtual jsi::String getString(jsi::Runtime &rt, std::optional arg) = 0; + virtual jsi::Array getArray(jsi::Runtime &rt, std::optional arg) = 0; + virtual jsi::Object getObject(jsi::Runtime &rt, std::optional arg) = 0; + virtual jsi::Object getObjectShape(jsi::Runtime &rt, std::optional arg) = 0; + virtual jsi::Object getAlias(jsi::Runtime &rt, std::optional arg) = 0; + virtual double getRootTag(jsi::Runtime &rt, std::optional arg) = 0; + virtual jsi::Object getValue(jsi::Runtime &rt, std::optional x, std::optional y, std::optional z) = 0; + virtual void getValueWithCallback(jsi::Runtime &rt, std::optional callback) = 0; + virtual jsi::Value getValueWithPromise(jsi::Runtime &rt, std::optional error) = 0; + +}; + +template +class JSI_EXPORT NativeSampleTurboModuleOptionalCxxSpec : public TurboModule { +public: + jsi::Value get(jsi::Runtime &rt, const jsi::PropNameID &propName) override { + return delegate_.get(rt, propName); + } + +protected: + NativeSampleTurboModuleOptionalCxxSpec(std::shared_ptr jsInvoker) + : TurboModule(\\"SampleTurboModuleOptional\\", jsInvoker), + delegate_(static_cast(this), jsInvoker) {} + +private: + class Delegate : public NativeSampleTurboModuleOptionalCxxSpecJSI { + public: + Delegate(T *instance, std::shared_ptr jsInvoker) : + NativeSampleTurboModuleOptionalCxxSpecJSI(std::move(jsInvoker)), instance_(instance) {} + + jsi::Object getConstants(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::getConstants) == 1, + \\"Expected getConstants(...) to have 1 parameters\\"); + + return bridging::callFromJs( + rt, &T::getConstants, jsInvoker_, instance_); + } + void voidFunc(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::voidFunc) == 1, + \\"Expected voidFunc(...) to have 1 parameters\\"); + + return bridging::callFromJs( + rt, &T::voidFunc, jsInvoker_, instance_); + } + bool getBool(jsi::Runtime &rt, std::optional arg) override { + static_assert( + bridging::getParameterCount(&T::getBool) == 2, + \\"Expected getBool(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getBool, jsInvoker_, instance_, std::move(arg)); + } + double getNumber(jsi::Runtime &rt, std::optional arg) override { + static_assert( + bridging::getParameterCount(&T::getNumber) == 2, + \\"Expected getNumber(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getNumber, jsInvoker_, instance_, std::move(arg)); + } + jsi::String getString(jsi::Runtime &rt, std::optional arg) override { + static_assert( + bridging::getParameterCount(&T::getString) == 2, + \\"Expected getString(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getString, jsInvoker_, instance_, std::move(arg)); + } + jsi::Array getArray(jsi::Runtime &rt, std::optional arg) override { + static_assert( + bridging::getParameterCount(&T::getArray) == 2, + \\"Expected getArray(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getArray, jsInvoker_, instance_, std::move(arg)); + } + jsi::Object getObject(jsi::Runtime &rt, std::optional arg) override { + static_assert( + bridging::getParameterCount(&T::getObject) == 2, + \\"Expected getObject(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getObject, jsInvoker_, instance_, std::move(arg)); + } + jsi::Object getObjectShape(jsi::Runtime &rt, std::optional arg) override { + static_assert( + bridging::getParameterCount(&T::getObjectShape) == 2, + \\"Expected getObjectShape(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getObjectShape, jsInvoker_, instance_, std::move(arg)); + } + jsi::Object getAlias(jsi::Runtime &rt, std::optional arg) override { + static_assert( + bridging::getParameterCount(&T::getAlias) == 2, + \\"Expected getAlias(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getAlias, jsInvoker_, instance_, std::move(arg)); + } + double getRootTag(jsi::Runtime &rt, std::optional arg) override { + static_assert( + bridging::getParameterCount(&T::getRootTag) == 2, + \\"Expected getRootTag(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getRootTag, jsInvoker_, instance_, std::move(arg)); + } + jsi::Object getValue(jsi::Runtime &rt, std::optional x, std::optional y, std::optional z) override { + static_assert( + bridging::getParameterCount(&T::getValue) == 4, + \\"Expected getValue(...) to have 4 parameters\\"); + + return bridging::callFromJs( + rt, &T::getValue, jsInvoker_, instance_, std::move(x), std::move(y), std::move(z)); + } + void getValueWithCallback(jsi::Runtime &rt, std::optional callback) override { + static_assert( + bridging::getParameterCount(&T::getValueWithCallback) == 2, + \\"Expected getValueWithCallback(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getValueWithCallback, jsInvoker_, instance_, std::move(callback)); + } + jsi::Value getValueWithPromise(jsi::Runtime &rt, std::optional error) override { + static_assert( + bridging::getParameterCount(&T::getValueWithPromise) == 2, + \\"Expected getValueWithPromise(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getValueWithPromise, jsInvoker_, instance_, std::move(error)); + } + + private: + T *instance_; + }; + + Delegate delegate_; +}; + +class JSI_EXPORT NativeStringTurboModuleCxxSpecJSI : public TurboModule { +protected: + NativeStringTurboModuleCxxSpecJSI(std::shared_ptr jsInvoker); + +public: + virtual jsi::String getString(jsi::Runtime &rt, jsi::String arg) = 0; + virtual jsi::String getStringWithAlias(jsi::Runtime &rt, jsi::String arg) = 0; + +}; + +template +class JSI_EXPORT NativeStringTurboModuleCxxSpec : public TurboModule { +public: + jsi::Value get(jsi::Runtime &rt, const jsi::PropNameID &propName) override { + return delegate_.get(rt, propName); + } + +protected: + NativeStringTurboModuleCxxSpec(std::shared_ptr jsInvoker) + : TurboModule(\\"SampleTurboModule\\", jsInvoker), + delegate_(static_cast(this), jsInvoker) {} + +private: + class Delegate : public NativeStringTurboModuleCxxSpecJSI { + public: + Delegate(T *instance, std::shared_ptr jsInvoker) : + NativeStringTurboModuleCxxSpecJSI(std::move(jsInvoker)), instance_(instance) {} + + jsi::String getString(jsi::Runtime &rt, jsi::String arg) override { + static_assert( + bridging::getParameterCount(&T::getString) == 2, + \\"Expected getString(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getString, jsInvoker_, instance_, std::move(arg)); + } + jsi::String getStringWithAlias(jsi::Runtime &rt, jsi::String arg) override { + static_assert( + bridging::getParameterCount(&T::getStringWithAlias) == 2, + \\"Expected getStringWithAlias(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getStringWithAlias, jsInvoker_, instance_, std::move(arg)); + } + + private: + T *instance_; + }; + + Delegate delegate_; +}; + +} // namespace react +} // namespace facebook +" +`; diff --git a/packages/react-native-codegen/e2e/__tests__/modules/__snapshots__/GenerateModuleObjCpp-test.js.snap b/packages/react-native-codegen/e2e/__tests__/modules/__snapshots__/GenerateModuleObjCpp-test.js.snap index 5a2dd6a2343779..a1238aa502e17b 100644 --- a/packages/react-native-codegen/e2e/__tests__/modules/__snapshots__/GenerateModuleObjCpp-test.js.snap +++ b/packages/react-native-codegen/e2e/__tests__/modules/__snapshots__/GenerateModuleObjCpp-test.js.snap @@ -84,6 +84,64 @@ namespace facebook { }; } // namespace react } // namespace facebook +namespace JS { + namespace NativeEnumTurboModule { + struct StateType { + NSString *state() const; + + StateType(NSDictionary *const v) : _v(v) {} + private: + NSDictionary *_v; + }; + } +} + +@interface RCTCxxConvert (NativeEnumTurboModule_StateType) ++ (RCTManagedPointer *)JS_NativeEnumTurboModule_StateType:(id)json; +@end +namespace JS { + namespace NativeEnumTurboModule { + struct StateTypeWithEnums { + NSString *state() const; + NSString *regular() const; + NSString *str() const; + double num() const; + double fraction() const; + + StateTypeWithEnums(NSDictionary *const v) : _v(v) {} + private: + NSDictionary *_v; + }; + } +} + +@interface RCTCxxConvert (NativeEnumTurboModule_StateTypeWithEnums) ++ (RCTManagedPointer *)JS_NativeEnumTurboModule_StateTypeWithEnums:(id)json; +@end +@protocol NativeEnumTurboModuleSpec + +- (NSString *)getStatusRegular:(JS::NativeEnumTurboModule::StateType &)statusProp; +- (NSString *)getStatusStr:(JS::NativeEnumTurboModule::StateType &)statusProp; +- (NSNumber *)getStatusNum:(JS::NativeEnumTurboModule::StateType &)statusProp; +- (NSNumber *)getStatusFraction:(JS::NativeEnumTurboModule::StateType &)statusProp; +- (NSDictionary *)getStateType:(NSString *)a + b:(NSString *)b + c:(double)c + d:(double)d; +- (NSDictionary *)getStateTypeWithEnums:(JS::NativeEnumTurboModule::StateTypeWithEnums &)paramOfTypeWithEnums; + +@end +namespace facebook { + namespace react { + /** + * ObjC++ class for module 'NativeEnumTurboModule' + */ + class JSI_EXPORT NativeEnumTurboModuleSpecJSI : public ObjCTurboModule { + public: + NativeEnumTurboModuleSpecJSI(const ObjCTurboModule::InitParams ¶ms); + }; + } // namespace react +} // namespace facebook @protocol NativeNullableTurboModuleSpec @@ -999,6 +1057,36 @@ namespace facebook { +inline NSString *JS::NativeEnumTurboModule::StateType::state() const +{ + id const p = _v[@\\"state\\"]; + return RCTBridgingToString(p); +} +inline NSString *JS::NativeEnumTurboModule::StateTypeWithEnums::state() const +{ + id const p = _v[@\\"state\\"]; + return RCTBridgingToString(p); +} +inline NSString *JS::NativeEnumTurboModule::StateTypeWithEnums::regular() const +{ + id const p = _v[@\\"regular\\"]; + return RCTBridgingToString(p); +} +inline NSString *JS::NativeEnumTurboModule::StateTypeWithEnums::str() const +{ + id const p = _v[@\\"str\\"]; + return RCTBridgingToString(p); +} +inline double JS::NativeEnumTurboModule::StateTypeWithEnums::num() const +{ + id const p = _v[@\\"num\\"]; + return RCTBridgingToDouble(p); +} +inline double JS::NativeEnumTurboModule::StateTypeWithEnums::fraction() const +{ + id const p = _v[@\\"fraction\\"]; + return RCTBridgingToDouble(p); +} inline bool JS::NativeObjectTurboModule::SpecDifficultObjectAE::D() const @@ -1374,6 +1462,64 @@ namespace facebook { }; } // namespace react } // namespace facebook +namespace JS { + namespace NativeEnumTurboModule { + struct StateType { + NSString *state() const; + + StateType(NSDictionary *const v) : _v(v) {} + private: + NSDictionary *_v; + }; + } +} + +@interface RCTCxxConvert (NativeEnumTurboModule_StateType) ++ (RCTManagedPointer *)JS_NativeEnumTurboModule_StateType:(id)json; +@end +namespace JS { + namespace NativeEnumTurboModule { + struct StateTypeWithEnums { + NSString *state() const; + NSString *regular() const; + NSString *str() const; + double num() const; + double fraction() const; + + StateTypeWithEnums(NSDictionary *const v) : _v(v) {} + private: + NSDictionary *_v; + }; + } +} + +@interface RCTCxxConvert (NativeEnumTurboModule_StateTypeWithEnums) ++ (RCTManagedPointer *)JS_NativeEnumTurboModule_StateTypeWithEnums:(id)json; +@end +@protocol NativeEnumTurboModuleSpec + +- (NSString *)getStatusRegular:(JS::NativeEnumTurboModule::StateType &)statusProp; +- (NSString *)getStatusStr:(JS::NativeEnumTurboModule::StateType &)statusProp; +- (NSNumber *)getStatusNum:(JS::NativeEnumTurboModule::StateType &)statusProp; +- (NSNumber *)getStatusFraction:(JS::NativeEnumTurboModule::StateType &)statusProp; +- (NSDictionary *)getStateType:(NSString *)a + b:(NSString *)b + c:(double)c + d:(double)d; +- (NSDictionary *)getStateTypeWithEnums:(JS::NativeEnumTurboModule::StateTypeWithEnums &)paramOfTypeWithEnums; + +@end +namespace facebook { + namespace react { + /** + * ObjC++ class for module 'NativeEnumTurboModule' + */ + class JSI_EXPORT NativeEnumTurboModuleSpecJSI : public ObjCTurboModule { + public: + NativeEnumTurboModuleSpecJSI(const ObjCTurboModule::InitParams ¶ms); + }; + } // namespace react +} // namespace facebook @protocol NativeNullableTurboModuleSpec @@ -2289,6 +2435,36 @@ namespace facebook { +inline NSString *JS::NativeEnumTurboModule::StateType::state() const +{ + id const p = _v[@\\"state\\"]; + return RCTBridgingToString(p); +} +inline NSString *JS::NativeEnumTurboModule::StateTypeWithEnums::state() const +{ + id const p = _v[@\\"state\\"]; + return RCTBridgingToString(p); +} +inline NSString *JS::NativeEnumTurboModule::StateTypeWithEnums::regular() const +{ + id const p = _v[@\\"regular\\"]; + return RCTBridgingToString(p); +} +inline NSString *JS::NativeEnumTurboModule::StateTypeWithEnums::str() const +{ + id const p = _v[@\\"str\\"]; + return RCTBridgingToString(p); +} +inline double JS::NativeEnumTurboModule::StateTypeWithEnums::num() const +{ + id const p = _v[@\\"num\\"]; + return RCTBridgingToDouble(p); +} +inline double JS::NativeEnumTurboModule::StateTypeWithEnums::fraction() const +{ + id const p = _v[@\\"fraction\\"]; + return RCTBridgingToDouble(p); +} inline bool JS::NativeObjectTurboModule::SpecDifficultObjectAE::D() const @@ -2671,6 +2847,68 @@ namespace facebook { } } // namespace react } // namespace facebook +@implementation RCTCxxConvert (NativeEnumTurboModule_StateType) ++ (RCTManagedPointer *)JS_NativeEnumTurboModule_StateType:(id)json +{ + return facebook::react::managedPointer(json); +} +@end +@implementation RCTCxxConvert (NativeEnumTurboModule_StateTypeWithEnums) ++ (RCTManagedPointer *)JS_NativeEnumTurboModule_StateTypeWithEnums:(id)json +{ + return facebook::react::managedPointer(json); +} +@end +namespace facebook { + namespace react { + + static facebook::jsi::Value __hostFunction_NativeEnumTurboModuleSpecJSI_getStatusRegular(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, StringKind, \\"getStatusRegular\\", @selector(getStatusRegular:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeEnumTurboModuleSpecJSI_getStatusStr(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, StringKind, \\"getStatusStr\\", @selector(getStatusStr:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeEnumTurboModuleSpecJSI_getStatusNum(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, NumberKind, \\"getStatusNum\\", @selector(getStatusNum:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeEnumTurboModuleSpecJSI_getStatusFraction(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, NumberKind, \\"getStatusFraction\\", @selector(getStatusFraction:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeEnumTurboModuleSpecJSI_getStateType(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, ObjectKind, \\"getStateType\\", @selector(getStateType:b:c:d:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeEnumTurboModuleSpecJSI_getStateTypeWithEnums(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, ObjectKind, \\"getStateTypeWithEnums\\", @selector(getStateTypeWithEnums:), args, count); + } + + NativeEnumTurboModuleSpecJSI::NativeEnumTurboModuleSpecJSI(const ObjCTurboModule::InitParams ¶ms) + : ObjCTurboModule(params) { + + methodMap_[\\"getStatusRegular\\"] = MethodMetadata {1, __hostFunction_NativeEnumTurboModuleSpecJSI_getStatusRegular}; + setMethodArgConversionSelector(@\\"getStatusRegular\\", 0, @\\"JS_NativeEnumTurboModule_StateType:\\"); + + methodMap_[\\"getStatusStr\\"] = MethodMetadata {1, __hostFunction_NativeEnumTurboModuleSpecJSI_getStatusStr}; + setMethodArgConversionSelector(@\\"getStatusStr\\", 0, @\\"JS_NativeEnumTurboModule_StateType:\\"); + + methodMap_[\\"getStatusNum\\"] = MethodMetadata {1, __hostFunction_NativeEnumTurboModuleSpecJSI_getStatusNum}; + setMethodArgConversionSelector(@\\"getStatusNum\\", 0, @\\"JS_NativeEnumTurboModule_StateType:\\"); + + methodMap_[\\"getStatusFraction\\"] = MethodMetadata {1, __hostFunction_NativeEnumTurboModuleSpecJSI_getStatusFraction}; + setMethodArgConversionSelector(@\\"getStatusFraction\\", 0, @\\"JS_NativeEnumTurboModule_StateType:\\"); + + methodMap_[\\"getStateType\\"] = MethodMetadata {4, __hostFunction_NativeEnumTurboModuleSpecJSI_getStateType}; + + + methodMap_[\\"getStateTypeWithEnums\\"] = MethodMetadata {1, __hostFunction_NativeEnumTurboModuleSpecJSI_getStateTypeWithEnums}; + setMethodArgConversionSelector(@\\"getStateTypeWithEnums\\", 0, @\\"JS_NativeEnumTurboModule_StateTypeWithEnums:\\"); + } + } // namespace react +} // namespace facebook namespace facebook { namespace react { diff --git a/packages/react-native-codegen/src/CodegenSchema.js b/packages/react-native-codegen/src/CodegenSchema.js index 8033695ba65513..17497531ed0803 100644 --- a/packages/react-native-codegen/src/CodegenSchema.js +++ b/packages/react-native-codegen/src/CodegenSchema.js @@ -53,6 +53,9 @@ export type VoidTypeAnnotation = $ReadOnly<{ export type ObjectTypeAnnotation<+T> = $ReadOnly<{ type: 'ObjectTypeAnnotation', properties: $ReadOnlyArray>, + + // metadata for objects that generated from interfaces + baseTypes?: $ReadOnlyArray, }>; type FunctionTypeAnnotation<+P, +R> = $ReadOnly<{ @@ -219,7 +222,8 @@ export type NullableTypeAnnotation<+T: NativeModuleTypeAnnotation> = $ReadOnly<{ export type NativeModuleSchema = $ReadOnly<{ type: 'NativeModule', - aliases: NativeModuleAliasMap, + aliasMap: NativeModuleAliasMap, + enumMap: NativeModuleEnumMap, spec: NativeModuleSpec, moduleName: string, // Use for modules that are not used on other platforms. @@ -236,6 +240,10 @@ export type NativeModulePropertyShape = NamedShape< Nullable, >; +export type NativeModuleEnumMap = $ReadOnly<{ + [enumName: string]: NativeModuleEnumDeclarationWithMembers, +}>; + export type NativeModuleAliasMap = $ReadOnly<{ [aliasName: string]: NativeModuleObjectTypeAnnotation, }>; @@ -284,11 +292,30 @@ export type NativeModuleBooleanTypeAnnotation = $ReadOnly<{ type: 'BooleanTypeAnnotation', }>; +export type NativeModuleEnumMembers = $ReadOnlyArray< + $ReadOnly<{ + name: string, + value: string, + }>, +>; + +export type NativeModuleEnumMemberType = + | 'NumberTypeAnnotation' + | 'StringTypeAnnotation'; + export type NativeModuleEnumDeclaration = $ReadOnly<{ + name: string, type: 'EnumDeclaration', - memberType: 'NumberTypeAnnotation' | 'StringTypeAnnotation', + memberType: NativeModuleEnumMemberType, }>; +export type NativeModuleEnumDeclarationWithMembers = { + name: string, + type: 'EnumDeclarationWithMembers', + memberType: NativeModuleEnumMemberType, + members: NativeModuleEnumMembers, +}; + export type NativeModuleGenericObjectTypeAnnotation = $ReadOnly<{ type: 'GenericObjectTypeAnnotation', }>; diff --git a/packages/react-native-codegen/src/generators/__test_fixtures__/fixtures.js b/packages/react-native-codegen/src/generators/__test_fixtures__/fixtures.js index 8a6963d001a6f3..8678249f5a8207 100644 --- a/packages/react-native-codegen/src/generators/__test_fixtures__/fixtures.js +++ b/packages/react-native-codegen/src/generators/__test_fixtures__/fixtures.js @@ -41,7 +41,8 @@ const SCHEMA_WITH_TM_AND_FC: SchemaType = { }, NativeCalculator: { type: 'NativeModule', - aliases: {}, + aliasMap: {}, + enumMap: {}, spec: { properties: [ { diff --git a/packages/react-native-codegen/src/generators/modules/GenerateModuleCpp.js b/packages/react-native-codegen/src/generators/modules/GenerateModuleCpp.js index ec42fa6ecacd7c..5b366e953530ae 100644 --- a/packages/react-native-codegen/src/generators/modules/GenerateModuleCpp.js +++ b/packages/react-native-codegen/src/generators/modules/GenerateModuleCpp.js @@ -238,11 +238,11 @@ module.exports = { .map((hasteModuleName: string) => { const nativeModule = nativeModules[hasteModuleName]; const { - aliases, + aliasMap, spec: {properties}, moduleName, } = nativeModule; - const resolveAlias = createAliasResolver(aliases); + const resolveAlias = createAliasResolver(aliasMap); const hostFunctions = properties.map(property => serializePropertyIntoHostFunction( hasteModuleName, diff --git a/packages/react-native-codegen/src/generators/modules/GenerateModuleH.js b/packages/react-native-codegen/src/generators/modules/GenerateModuleH.js index 7c3e6e44b26205..a3156c4d7e49c9 100644 --- a/packages/react-native-codegen/src/generators/modules/GenerateModuleH.js +++ b/packages/react-native-codegen/src/generators/modules/GenerateModuleH.js @@ -341,12 +341,12 @@ module.exports = { const modules = Object.keys(nativeModules).flatMap(hasteModuleName => { const { - aliases, + aliasMap, spec: {properties}, moduleName, } = nativeModules[hasteModuleName]; - const resolveAlias = createAliasResolver(aliases); - const structs = createStructs(moduleName, aliases, resolveAlias); + const resolveAlias = createAliasResolver(aliasMap); + const structs = createStructs(moduleName, aliasMap, resolveAlias); return [ ModuleClassDeclarationTemplate({ diff --git a/packages/react-native-codegen/src/generators/modules/GenerateModuleJavaSpec.js b/packages/react-native-codegen/src/generators/modules/GenerateModuleJavaSpec.js index 7be905514a699b..8497bb68a84111 100644 --- a/packages/react-native-codegen/src/generators/modules/GenerateModuleJavaSpec.js +++ b/packages/react-native-codegen/src/generators/modules/GenerateModuleJavaSpec.js @@ -184,7 +184,7 @@ function translateFunctionParamToJavaType( imports.add('com.facebook.react.bridge.Callback'); return wrapNullable('Callback'); default: - (realTypeAnnotation.type: 'EnumDeclaration' | 'MixedTypeAnnotation'); + (realTypeAnnotation.type: 'MixedTypeAnnotation'); throw new Error(createErrorMessage(realTypeAnnotation.type)); } } @@ -272,7 +272,7 @@ function translateFunctionReturnTypeToJavaType( imports.add('com.facebook.react.bridge.WritableArray'); return wrapNullable('WritableArray'); default: - (realTypeAnnotation.type: 'EnumDeclaration' | 'MixedTypeAnnotation'); + (realTypeAnnotation.type: 'MixedTypeAnnotation'); throw new Error(createErrorMessage(realTypeAnnotation.type)); } } @@ -346,7 +346,7 @@ function getFalsyReturnStatementFromReturnType( case 'ArrayTypeAnnotation': return 'return null;'; default: - (realTypeAnnotation.type: 'EnumDeclaration' | 'MixedTypeAnnotation'); + (realTypeAnnotation.type: 'MixedTypeAnnotation'); throw new Error(createErrorMessage(realTypeAnnotation.type)); } } @@ -447,7 +447,7 @@ module.exports = { Object.keys(nativeModules).forEach(hasteModuleName => { const { - aliases, + aliasMap, excludedPlatforms, moduleName, spec: {properties}, @@ -455,7 +455,7 @@ module.exports = { if (excludedPlatforms != null && excludedPlatforms.includes('android')) { return; } - const resolveAlias = createAliasResolver(aliases); + const resolveAlias = createAliasResolver(aliasMap); const className = `${hasteModuleName}Spec`; const imports: Set = new Set([ diff --git a/packages/react-native-codegen/src/generators/modules/GenerateModuleJniCpp.js b/packages/react-native-codegen/src/generators/modules/GenerateModuleJniCpp.js index fb62617998dd36..ad23221bc4ce56 100644 --- a/packages/react-native-codegen/src/generators/modules/GenerateModuleJniCpp.js +++ b/packages/react-native-codegen/src/generators/modules/GenerateModuleJniCpp.js @@ -193,7 +193,7 @@ function translateReturnTypeToKind( case 'ArrayTypeAnnotation': return 'ArrayKind'; default: - (realTypeAnnotation.type: 'EnumDeclaration' | 'MixedTypeAnnotation'); + (realTypeAnnotation.type: 'MixedTypeAnnotation'); throw new Error( `Unknown prop type for returning value, found: ${realTypeAnnotation.type}"`, ); @@ -272,7 +272,7 @@ function translateParamTypeToJniType( case 'FunctionTypeAnnotation': return 'Lcom/facebook/react/bridge/Callback;'; default: - (realTypeAnnotation.type: 'EnumDeclaration' | 'MixedTypeAnnotation'); + (realTypeAnnotation.type: 'MixedTypeAnnotation'); throw new Error( `Unknown prop type for method arg, found: ${realTypeAnnotation.type}"`, ); @@ -348,7 +348,7 @@ function translateReturnTypeToJniType( case 'ArrayTypeAnnotation': return 'Lcom/facebook/react/bridge/WritableArray;'; default: - (realTypeAnnotation.type: 'EnumDeclaration' | 'MixedTypeAnnotation'); + (realTypeAnnotation.type: 'MixedTypeAnnotation'); throw new Error( `Unknown prop type for method return type, found: ${realTypeAnnotation.type}"`, ); @@ -438,10 +438,10 @@ module.exports = { .sort() .map(hasteModuleName => { const { - aliases, + aliasMap, spec: {properties}, } = nativeModules[hasteModuleName]; - const resolveAlias = createAliasResolver(aliases); + const resolveAlias = createAliasResolver(aliasMap); const translatedMethods = properties .map(property => diff --git a/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/index.js b/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/index.js index 8f8da790b90407..9524327b87137e 100644 --- a/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/index.js +++ b/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/index.js @@ -132,14 +132,14 @@ module.exports = { const hasteModuleNames: Array = Object.keys(nativeModules).sort(); for (const hasteModuleName of hasteModuleNames) { const { - aliases, + aliasMap, excludedPlatforms, spec: {properties}, } = nativeModules[hasteModuleName]; if (excludedPlatforms != null && excludedPlatforms.includes('iOS')) { continue; } - const resolveAlias = createAliasResolver(aliases); + const resolveAlias = createAliasResolver(aliasMap); const structCollector = new StructCollector(); const methodSerializations: Array = []; diff --git a/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/serializeMethod.js b/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/serializeMethod.js index 2894de5ccf262d..32a13879c9443d 100644 --- a/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/serializeMethod.js +++ b/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/serializeMethod.js @@ -375,7 +375,7 @@ function getReturnObjCType( case 'GenericObjectTypeAnnotation': return wrapIntoNullableIfNeeded('NSDictionary *'); default: - (typeAnnotation.type: 'EnumDeclaration' | 'MixedTypeAnnotation'); + (typeAnnotation.type: 'MixedTypeAnnotation'); throw new Error( `Unsupported return type for ${methodName}. Found: ${typeAnnotation.type}`, ); @@ -439,7 +439,7 @@ function getReturnJSType( ); } default: - (typeAnnotation.type: 'EnumDeclaration' | 'MixedTypeAnnotation'); + (typeAnnotation.type: 'MixedTypeAnnotation'); throw new Error( `Unsupported return type for ${methodName}. Found: ${typeAnnotation.type}`, ); diff --git a/packages/react-native-codegen/src/generators/modules/__test_fixtures__/fixtures.js b/packages/react-native-codegen/src/generators/modules/__test_fixtures__/fixtures.js index a0cd29d601e309..5764facb3bc32e 100644 --- a/packages/react-native-codegen/src/generators/modules/__test_fixtures__/fixtures.js +++ b/packages/react-native-codegen/src/generators/modules/__test_fixtures__/fixtures.js @@ -16,7 +16,8 @@ const EMPTY_NATIVE_MODULES: SchemaType = { modules: { NativeSampleTurboModule: { type: 'NativeModule', - aliases: {}, + aliasMap: {}, + enumMap: {}, spec: { properties: [], }, @@ -29,7 +30,8 @@ const SIMPLE_NATIVE_MODULES: SchemaType = { modules: { NativeSampleTurboModule: { type: 'NativeModule', - aliases: {}, + aliasMap: {}, + enumMap: {}, spec: { properties: [ { @@ -341,7 +343,8 @@ const TWO_MODULES_DIFFERENT_FILES: SchemaType = { modules: { NativeSampleTurboModule: { type: 'NativeModule', - aliases: {}, + aliasMap: {}, + enumMap: {}, spec: { properties: [ { @@ -361,7 +364,8 @@ const TWO_MODULES_DIFFERENT_FILES: SchemaType = { }, NativeSampleTurboModule2: { type: 'NativeModule', - aliases: {}, + aliasMap: {}, + enumMap: {}, spec: { properties: [ { @@ -398,7 +402,8 @@ const COMPLEX_OBJECTS: SchemaType = { modules: { NativeSampleTurboModule: { type: 'NativeModule', - aliases: {}, + aliasMap: {}, + enumMap: {}, spec: { properties: [ { @@ -764,7 +769,7 @@ const NATIVE_MODULES_WITH_TYPE_ALIASES: SchemaType = { modules: { AliasTurboModule: { type: 'NativeModule', - aliases: { + aliasMap: { Options: { type: 'ObjectTypeAnnotation', properties: [ @@ -854,6 +859,7 @@ const NATIVE_MODULES_WITH_TYPE_ALIASES: SchemaType = { ], }, }, + enumMap: {}, spec: { properties: [ { @@ -899,7 +905,7 @@ const REAL_MODULE_EXAMPLE: SchemaType = { modules: { NativeCameraRollManager: { type: 'NativeModule', - aliases: { + aliasMap: { PhotoIdentifierImage: { type: 'ObjectTypeAnnotation', properties: [ @@ -1138,6 +1144,7 @@ const REAL_MODULE_EXAMPLE: SchemaType = { ], }, }, + enumMap: {}, spec: { properties: [ { @@ -1226,7 +1233,7 @@ const REAL_MODULE_EXAMPLE: SchemaType = { }, NativeExceptionsManager: { type: 'NativeModule', - aliases: { + aliasMap: { StackFrame: { properties: [ { @@ -1333,6 +1340,7 @@ const REAL_MODULE_EXAMPLE: SchemaType = { type: 'ObjectTypeAnnotation', }, }, + enumMap: {}, spec: { properties: [ { @@ -1494,7 +1502,7 @@ const CXX_ONLY_NATIVE_MODULES: SchemaType = { modules: { NativeSampleTurboModule: { type: 'NativeModule', - aliases: { + aliasMap: { ObjectAlias: { type: 'ObjectTypeAnnotation', properties: [ @@ -1508,6 +1516,7 @@ const CXX_ONLY_NATIVE_MODULES: SchemaType = { ], }, }, + enumMap: {}, spec: { properties: [ { @@ -1648,7 +1657,8 @@ const SAMPLE_WITH_UPPERCASE_NAME: SchemaType = { modules: { NativeSampleTurboModule: { type: 'NativeModule', - aliases: {}, + enumMap: {}, + aliasMap: {}, spec: { properties: [], }, diff --git a/packages/react-native-codegen/src/parsers/__tests__/parsers-commons-test.js b/packages/react-native-codegen/src/parsers/__tests__/parsers-commons-test.js index 74db8652b9ec0e..95ef4306ebee73 100644 --- a/packages/react-native-codegen/src/parsers/__tests__/parsers-commons-test.js +++ b/packages/react-native-codegen/src/parsers/__tests__/parsers-commons-test.js @@ -277,6 +277,7 @@ describe('parseObjectProperty', () => { const moduleName = 'testModuleName'; const types = {['wrongName']: 'wrongType'}; const aliasMap = {}; + const enumMap = {}; const tryParse = () => null; const cxxOnly = false; const nullable = true; @@ -305,6 +306,7 @@ describe('parseObjectProperty', () => { moduleName, types, aliasMap, + enumMap, tryParse, cxxOnly, nullable, @@ -338,6 +340,7 @@ describe('parseObjectProperty', () => { moduleName, types, aliasMap, + enumMap, tryParse, cxxOnly, nullable, @@ -374,7 +377,8 @@ describe('buildSchemaFromConfigType', () => { const moduleSchemaMock = { type: 'NativeModule', - aliases: {}, + aliasMap: {}, + enumMap: {}, spec: {properties: []}, moduleName: '', }; @@ -657,13 +661,13 @@ describe('buildSchema', () => { const contents = ` import type {ViewProps} from 'ViewPropTypes'; import type {HostComponent} from 'react-native'; - + const codegenNativeComponent = require('codegenNativeComponent'); - + export type ModuleProps = $ReadOnly<{| ...ViewProps, |}>; - + export default (codegenNativeComponent( 'Module', ): HostComponent); @@ -712,11 +716,11 @@ describe('buildSchema', () => { const contents = ` import type {TurboModule} from 'react-native/Libraries/TurboModule/RCTExport'; import * as TurboModuleRegistry from 'react-native/Libraries/TurboModule/TurboModuleRegistry'; - + export interface Spec extends TurboModule { +getArray: (a: Array) => Array; } - + export default (TurboModuleRegistry.getEnforcing( 'SampleTurboModule', ): Spec); @@ -742,7 +746,8 @@ describe('buildSchema', () => { modules: { fileName: { type: 'NativeModule', - aliases: {}, + aliasMap: {}, + enumMap: {}, spec: { properties: [ { diff --git a/packages/react-native-codegen/src/parsers/__tests__/parsers-primitives-test.js b/packages/react-native-codegen/src/parsers/__tests__/parsers-primitives-test.js index 53a03bafec54d3..66b7e3af66ce15 100644 --- a/packages/react-native-codegen/src/parsers/__tests__/parsers-primitives-test.js +++ b/packages/react-native-codegen/src/parsers/__tests__/parsers-primitives-test.js @@ -20,8 +20,8 @@ const { emitFloat, emitNumber, emitInt32, + emitGenericObject, emitObject, - emitPartial, emitPromise, emitRootTag, emitVoid, @@ -29,6 +29,7 @@ const { emitStringish, emitMixed, typeAliasResolution, + typeEnumResolution, } = require('../parsers-primitives.js'); const {MockedParser} = require('../parserMock'); const {emitUnion} = require('../parsers-primitives'); @@ -264,14 +265,14 @@ describe('typeAliasResolution', () => { ], }; - describe('when typeAliasResolutionStatus is successful', () => { - const typeAliasResolutionStatus = {successful: true, aliasName: 'Foo'}; + describe('when typeResolution is successful', () => { + const typeResolution = {successful: true, type: 'alias', name: 'Foo'}; describe('when nullable is true', () => { it('returns nullable TypeAliasTypeAnnotation and map it in aliasMap', () => { const aliasMap = {}; const result = typeAliasResolution( - typeAliasResolutionStatus, + typeResolution, objectTypeAnnotation, aliasMap, true, @@ -292,7 +293,7 @@ describe('typeAliasResolution', () => { it('returns non nullable TypeAliasTypeAnnotation and map it in aliasMap', () => { const aliasMap = {}; const result = typeAliasResolution( - typeAliasResolutionStatus, + typeResolution, objectTypeAnnotation, aliasMap, false, @@ -307,14 +308,14 @@ describe('typeAliasResolution', () => { }); }); - describe('when typeAliasResolutionStatus is not successful', () => { - const typeAliasResolutionStatus = {successful: false}; + describe('when typeResolution is not successful', () => { + const typeResolution = {successful: false}; describe('when nullable is true', () => { it('returns nullable ObjectTypeAnnotation', () => { const aliasMap = {}; const result = typeAliasResolution( - typeAliasResolutionStatus, + typeResolution, objectTypeAnnotation, aliasMap, true, @@ -332,7 +333,7 @@ describe('typeAliasResolution', () => { it('returns non nullable ObjectTypeAnnotation', () => { const aliasMap = {}; const result = typeAliasResolution( - typeAliasResolutionStatus, + typeResolution, objectTypeAnnotation, aliasMap, false, @@ -345,6 +346,98 @@ describe('typeAliasResolution', () => { }); }); +describe('typeEnumResolution', () => { + describe('when typeResolution is successful', () => { + describe('when nullable is true', () => { + it('returns nullable EnumDeclaration and map it in enumMap', () => { + const enumMap = {}; + const mockTypeAnnotation = {type: 'StringTypeAnnotation'}; + + const result = typeEnumResolution( + mockTypeAnnotation, + {successful: true, type: 'enum', name: 'Foo'}, + true /* nullable */, + 'SomeModule' /* name */, + 'Flow', + enumMap, + parser, + ); + + expect(enumMap).toEqual({ + Foo: { + type: 'EnumDeclarationWithMembers', + name: 'Foo', + memberType: 'StringTypeAnnotation', + members: [ + { + name: 'Hello', + value: 'hello', + }, + { + name: 'Goodbye', + value: 'goodbye', + }, + ], + }, + }); + + expect(result).toEqual({ + type: 'NullableTypeAnnotation', + typeAnnotation: { + name: 'Foo', + type: 'EnumDeclaration', + memberType: 'StringTypeAnnotation', + }, + }); + }); + }); + + describe('when nullable is false', () => { + it('returns non nullable TypeAliasTypeAnnotation and map it in aliasMap', () => { + const enumMap = {}; + const mockTypeAnnotation = {type: 'NumberTypeAnnotation'}; + + const result = typeEnumResolution( + mockTypeAnnotation, + {successful: true, type: 'enum', name: 'Foo'}, + true /* nullable */, + 'SomeModule' /* name */, + 'Flow', + enumMap, + parser, + ); + + expect(enumMap).toEqual({ + Foo: { + type: 'EnumDeclarationWithMembers', + name: 'Foo', + memberType: 'NumberTypeAnnotation', + members: [ + { + name: 'On', + value: '1', + }, + { + name: 'Off', + value: '0', + }, + ], + }, + }); + + expect(result).toEqual({ + type: 'NullableTypeAnnotation', + typeAnnotation: { + name: 'Foo', + type: 'EnumDeclaration', + memberType: 'NumberTypeAnnotation', + }, + }); + }); + }); + }); +}); + describe('emitPromise', () => { const moduleName = 'testModuleName'; @@ -362,6 +455,8 @@ describe('emitPromise', () => { {}, /* aliasMap: {...NativeModuleAliasMap} */ {}, + /* enumMap: {...NativeModuleEnumMap} */ + {}, /* tryParse: ParserErrorCapturer */ // $FlowFixMe[missing-local-annot] function (_: () => T) { @@ -431,10 +526,10 @@ describe('emitPromise', () => { }); }); -describe('emitObject', () => { +describe('emitGenericObject', () => { describe('when nullable is true', () => { it('returns nullable type annotation', () => { - const result = emitObject(true); + const result = emitGenericObject(true); const expected = { type: 'NullableTypeAnnotation', typeAnnotation: { @@ -447,7 +542,7 @@ describe('emitObject', () => { }); describe('when nullable is false', () => { it('returns non nullable type annotation', () => { - const result = emitObject(false); + const result = emitGenericObject(false); const expected = { type: 'GenericObjectTypeAnnotation', }; @@ -457,7 +552,7 @@ describe('emitObject', () => { }); }); -describe('emitPartial', () => { +describe('emitObject', () => { describe('when nullable is true', () => { it('returns nullable type annotation', () => { const props = [ @@ -477,7 +572,7 @@ describe('emitPartial', () => { }, ]; - const result = emitPartial(true, props); + const result = emitObject(true, props); const expected = { type: 'NullableTypeAnnotation', @@ -509,7 +604,7 @@ describe('emitPartial', () => { }, ]; - const result = emitPartial(false, props); + const result = emitObject(false, props); const expected = { type: 'ObjectTypeAnnotation', @@ -991,6 +1086,8 @@ describe('emitArrayType', () => { {}, /* aliasMap: {...NativeModuleAliasMap} */ {}, + /* enumMap: {...NativeModuleEnumMap} */ + {}, /* cxxOnly: boolean */ false, nullable, diff --git a/packages/react-native-codegen/src/parsers/consistency/__tests__/checkModuleSnaps-test.js b/packages/react-native-codegen/src/parsers/consistency/__tests__/checkModuleSnaps-test.js index e90d3d22d30c0e..1e1fe3909c103f 100644 --- a/packages/react-native-codegen/src/parsers/consistency/__tests__/checkModuleSnaps-test.js +++ b/packages/react-native-codegen/src/parsers/consistency/__tests__/checkModuleSnaps-test.js @@ -22,6 +22,7 @@ const tsExtraCases = [ 'NATIVE_MODULE_WITH_ARRAY2_WITH_UNION_AND_TOUPLE', 'NATIVE_MODULE_WITH_BASIC_ARRAY2', 'NATIVE_MODULE_WITH_COMPLEX_ARRAY2', + 'NATIVE_MODULE_WITH_INTERSECTION_TYPES', 'NATIVE_MODULE_WITH_NESTED_INTERFACES', ]; const ignoredCases = []; diff --git a/packages/react-native-codegen/src/parsers/flow/modules/__test_fixtures__/failures.js b/packages/react-native-codegen/src/parsers/flow/modules/__test_fixtures__/failures.js index 8024079b0fb683..8734095f43f2d4 100644 --- a/packages/react-native-codegen/src/parsers/flow/modules/__test_fixtures__/failures.js +++ b/packages/react-native-codegen/src/parsers/flow/modules/__test_fixtures__/failures.js @@ -211,6 +211,60 @@ export interface Spec2 extends TurboModule { `; +const EMPTY_ENUM_NATIVE_MODULE = ` +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow strict-local + * @format + */ + +'use strict'; + +import type {TurboModule} from '../RCTExport'; +import * as TurboModuleRegistry from '../TurboModuleRegistry'; + +export enum SomeEnum { +} + +export interface Spec extends TurboModule { + +getEnums: (a: SomeEnum) => string; +} + +export default TurboModuleRegistry.getEnforcing('EmptyEnumNativeModule'); +`; + +const MIXED_VALUES_ENUM_NATIVE_MODULE = ` +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow strict-local + * @format + */ + +'use strict'; + +import type {TurboModule} from '../RCTExport'; +import * as TurboModuleRegistry from '../TurboModuleRegistry'; + +export enum SomeEnum { + NUM = 1, + STR = 'str', +} + +export interface Spec extends TurboModule { + +getEnums: (a: SomeEnum) => string; +} + +export default TurboModuleRegistry.getEnforcing('MixedValuesEnumNativeModule'); +`; + module.exports = { NATIVE_MODULES_WITH_READ_ONLY_OBJECT_NO_TYPE_FOR_CONTENT, NATIVE_MODULES_WITH_UNNAMED_PARAMS, @@ -220,4 +274,6 @@ module.exports = { TWO_NATIVE_MODULES_EXPORTED_WITH_DEFAULT, NATIVE_MODULES_WITH_NOT_ONLY_METHODS, TWO_NATIVE_EXTENDING_TURBO_MODULE, + EMPTY_ENUM_NATIVE_MODULE, + MIXED_VALUES_ENUM_NATIVE_MODULE, }; diff --git a/packages/react-native-codegen/src/parsers/flow/modules/__tests__/__snapshots__/module-parser-snapshot-test.js.snap b/packages/react-native-codegen/src/parsers/flow/modules/__tests__/__snapshots__/module-parser-snapshot-test.js.snap index 390e3be33c30fd..6de97cbbc6b47a 100644 --- a/packages/react-native-codegen/src/parsers/flow/modules/__tests__/__snapshots__/module-parser-snapshot-test.js.snap +++ b/packages/react-native-codegen/src/parsers/flow/modules/__tests__/__snapshots__/module-parser-snapshot-test.js.snap @@ -1,5 +1,9 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`RN Codegen Flow Parser Fails with error message EMPTY_ENUM_NATIVE_MODULE 1`] = `"Module NativeSampleTurboModule: Failed parsing the enum SomeEnum in NativeSampleTurboModule with the error: Enums should have at least one member and member values can not be mixed- they all must be either blank, number, or string values."`; + +exports[`RN Codegen Flow Parser Fails with error message MIXED_VALUES_ENUM_NATIVE_MODULE 1`] = `"Module NativeSampleTurboModule: Failed parsing the enum SomeEnum in NativeSampleTurboModule with the error: Enums should have at least one member and member values can not be mixed- they all must be either blank, number, or string values."`; + exports[`RN Codegen Flow Parser Fails with error message NATIVE_MODULES_WITH_ARRAY_WITH_NO_TYPE_FOR_CONTENT 1`] = `"Module NativeSampleTurboModule: Generic 'Array' must have type parameters."`; exports[`RN Codegen Flow Parser Fails with error message NATIVE_MODULES_WITH_ARRAY_WITH_NO_TYPE_FOR_CONTENT_AS_PARAM 1`] = `"Module NativeSampleTurboModule: Generic 'Array' must have type parameters."`; @@ -21,7 +25,8 @@ exports[`RN Codegen Flow Parser can generate fixture ANDROID_ONLY_NATIVE_MODULE 'modules': { 'NativeSampleTurboModule': { 'type': 'NativeModule', - 'aliases': {}, + 'aliasMap': {}, + 'enumMap': {}, 'spec': { 'properties': [] }, @@ -39,7 +44,73 @@ exports[`RN Codegen Flow Parser can generate fixture CXX_ONLY_NATIVE_MODULE 1`] 'modules': { 'NativeSampleTurboModule': { 'type': 'NativeModule', - 'aliases': {}, + 'aliasMap': {}, + 'enumMap': { + 'Quality': { + 'name': 'Quality', + 'type': 'EnumDeclarationWithMembers', + 'memberType': 'StringTypeAnnotation', + 'members': [ + { + 'name': 'SD', + 'value': 'SD' + }, + { + 'name': 'HD', + 'value': 'HD' + } + ] + }, + 'Resolution': { + 'name': 'Resolution', + 'type': 'EnumDeclarationWithMembers', + 'memberType': 'NumberTypeAnnotation', + 'members': [ + { + 'name': 'Low', + 'value': 720 + }, + { + 'name': 'High', + 'value': 1080 + } + ] + }, + 'Floppy': { + 'name': 'Floppy', + 'type': 'EnumDeclarationWithMembers', + 'memberType': 'NumberTypeAnnotation', + 'members': [ + { + 'name': 'LowDensity', + 'value': 0.72 + }, + { + 'name': 'HighDensity', + 'value': 1.44 + } + ] + }, + 'StringOptions': { + 'name': 'StringOptions', + 'type': 'EnumDeclarationWithMembers', + 'memberType': 'StringTypeAnnotation', + 'members': [ + { + 'name': 'One', + 'value': 'one' + }, + { + 'name': 'Two', + 'value': 'two' + }, + { + 'name': 'Three', + 'value': 'three' + } + ] + } + }, 'spec': { 'properties': [ { @@ -89,6 +160,7 @@ exports[`RN Codegen Flow Parser can generate fixture CXX_ONLY_NATIVE_MODULE 1`] 'name': 'quality', 'optional': false, 'typeAnnotation': { + 'name': 'Quality', 'type': 'EnumDeclaration', 'memberType': 'StringTypeAnnotation' } @@ -97,6 +169,7 @@ exports[`RN Codegen Flow Parser can generate fixture CXX_ONLY_NATIVE_MODULE 1`] 'name': 'resolution', 'optional': true, 'typeAnnotation': { + 'name': 'Resolution', 'type': 'EnumDeclaration', 'memberType': 'NumberTypeAnnotation' } @@ -105,6 +178,7 @@ exports[`RN Codegen Flow Parser can generate fixture CXX_ONLY_NATIVE_MODULE 1`] 'name': 'floppy', 'optional': false, 'typeAnnotation': { + 'name': 'Floppy', 'type': 'EnumDeclaration', 'memberType': 'NumberTypeAnnotation' } @@ -113,6 +187,7 @@ exports[`RN Codegen Flow Parser can generate fixture CXX_ONLY_NATIVE_MODULE 1`] 'name': 'stringOptions', 'optional': false, 'typeAnnotation': { + 'name': 'StringOptions', 'type': 'EnumDeclaration', 'memberType': 'StringTypeAnnotation' } @@ -220,7 +295,8 @@ exports[`RN Codegen Flow Parser can generate fixture EMPTY_NATIVE_MODULE 1`] = ` 'modules': { 'NativeSampleTurboModule': { 'type': 'NativeModule', - 'aliases': {}, + 'aliasMap': {}, + 'enumMap': {}, 'spec': { 'properties': [] }, @@ -235,7 +311,73 @@ exports[`RN Codegen Flow Parser can generate fixture IOS_ONLY_NATIVE_MODULE 1`] 'modules': { 'NativeSampleTurboModule': { 'type': 'NativeModule', - 'aliases': {}, + 'aliasMap': {}, + 'enumMap': { + 'Quality': { + 'name': 'Quality', + 'type': 'EnumDeclarationWithMembers', + 'memberType': 'StringTypeAnnotation', + 'members': [ + { + 'name': 'SD', + 'value': 'SD' + }, + { + 'name': 'HD', + 'value': 'HD' + } + ] + }, + 'Resolution': { + 'name': 'Resolution', + 'type': 'EnumDeclarationWithMembers', + 'memberType': 'NumberTypeAnnotation', + 'members': [ + { + 'name': 'Low', + 'value': 720 + }, + { + 'name': 'High', + 'value': 1080 + } + ] + }, + 'Floppy': { + 'name': 'Floppy', + 'type': 'EnumDeclarationWithMembers', + 'memberType': 'NumberTypeAnnotation', + 'members': [ + { + 'name': 'LowDensity', + 'value': 0.72 + }, + { + 'name': 'HighDensity', + 'value': 1.44 + } + ] + }, + 'StringOptions': { + 'name': 'StringOptions', + 'type': 'EnumDeclarationWithMembers', + 'memberType': 'StringTypeAnnotation', + 'members': [ + { + 'name': 'One', + 'value': 'one' + }, + { + 'name': 'Two', + 'value': 'two' + }, + { + 'name': 'Three', + 'value': 'three' + } + ] + } + }, 'spec': { 'properties': [ { @@ -251,6 +393,7 @@ exports[`RN Codegen Flow Parser can generate fixture IOS_ONLY_NATIVE_MODULE 1`] 'name': 'quality', 'optional': false, 'typeAnnotation': { + 'name': 'Quality', 'type': 'EnumDeclaration', 'memberType': 'StringTypeAnnotation' } @@ -259,6 +402,7 @@ exports[`RN Codegen Flow Parser can generate fixture IOS_ONLY_NATIVE_MODULE 1`] 'name': 'resolution', 'optional': true, 'typeAnnotation': { + 'name': 'Resolution', 'type': 'EnumDeclaration', 'memberType': 'NumberTypeAnnotation' } @@ -267,6 +411,7 @@ exports[`RN Codegen Flow Parser can generate fixture IOS_ONLY_NATIVE_MODULE 1`] 'name': 'floppy', 'optional': false, 'typeAnnotation': { + 'name': 'Floppy', 'type': 'EnumDeclaration', 'memberType': 'NumberTypeAnnotation' } @@ -275,6 +420,7 @@ exports[`RN Codegen Flow Parser can generate fixture IOS_ONLY_NATIVE_MODULE 1`] 'name': 'stringOptions', 'optional': false, 'typeAnnotation': { + 'name': 'StringOptions', 'type': 'EnumDeclaration', 'memberType': 'StringTypeAnnotation' } @@ -298,7 +444,7 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_ALIASES 'modules': { 'NativeSampleTurboModule': { 'type': 'NativeModule', - 'aliases': { + 'aliasMap': { 'ObjectAlias': { 'type': 'ObjectTypeAnnotation', 'properties': [ @@ -333,6 +479,7 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_ALIASES ] } }, + 'enumMap': {}, 'spec': { 'properties': [ { @@ -495,7 +642,8 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_ARRAY_WI 'modules': { 'NativeSampleTurboModule': { 'type': 'NativeModule', - 'aliases': {}, + 'aliasMap': {}, + 'enumMap': {}, 'spec': { 'properties': [ { @@ -536,7 +684,8 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_ARRAY_WI 'modules': { 'NativeSampleTurboModule': { 'type': 'NativeModule', - 'aliases': {}, + 'aliasMap': {}, + 'enumMap': {}, 'spec': { 'properties': [ { @@ -571,7 +720,8 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_BASIC_AR 'modules': { 'NativeSampleTurboModule': { 'type': 'NativeModule', - 'aliases': {}, + 'aliasMap': {}, + 'enumMap': {}, 'spec': { 'properties': [ { @@ -637,7 +787,8 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_BASIC_PA 'modules': { 'NativeSampleTurboModule': { 'type': 'NativeModule', - 'aliases': {}, + 'aliasMap': {}, + 'enumMap': {}, 'spec': { 'properties': [ { @@ -729,7 +880,8 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_CALLBACK 'modules': { 'NativeSampleTurboModule': { 'type': 'NativeModule', - 'aliases': {}, + 'aliasMap': {}, + 'enumMap': {}, 'spec': { 'properties': [ { @@ -789,7 +941,8 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_COMPLEX_ 'modules': { 'NativeSampleTurboModule': { 'type': 'NativeModule', - 'aliases': {}, + 'aliasMap': {}, + 'enumMap': {}, 'spec': { 'properties': [ { @@ -848,7 +1001,8 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_COMPLEX_ 'modules': { 'NativeSampleTurboModule': { 'type': 'NativeModule', - 'aliases': {}, + 'aliasMap': {}, + 'enumMap': {}, 'spec': { 'properties': [ { @@ -1060,7 +1214,8 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_COMPLEX_ 'modules': { 'NativeSampleTurboModule': { 'type': 'NativeModule', - 'aliases': {}, + 'aliasMap': {}, + 'enumMap': {}, 'spec': { 'properties': [ { @@ -1164,7 +1319,8 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_FLOAT_AN 'modules': { 'NativeSampleTurboModule': { 'type': 'NativeModule', - 'aliases': {}, + 'aliasMap': {}, + 'enumMap': {}, 'spec': { 'properties': [ { @@ -1218,7 +1374,7 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_NESTED_A 'modules': { 'NativeSampleTurboModule': { 'type': 'NativeModule', - 'aliases': { + 'aliasMap': { 'Bar': { 'type': 'ObjectTypeAnnotation', 'properties': [ @@ -1253,6 +1409,7 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_NESTED_A ] } }, + 'enumMap': {}, 'spec': { 'properties': [ { @@ -1309,7 +1466,8 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_NULLABLE 'modules': { 'NativeSampleTurboModule': { 'type': 'NativeModule', - 'aliases': {}, + 'aliasMap': {}, + 'enumMap': {}, 'spec': { 'properties': [ { @@ -1347,7 +1505,7 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_OBJECT_W 'modules': { 'NativeSampleTurboModule': { 'type': 'NativeModule', - 'aliases': { + 'aliasMap': { 'DisplayMetricsAndroid': { 'type': 'ObjectTypeAnnotation', 'properties': [ @@ -1361,6 +1519,7 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_OBJECT_W ] } }, + 'enumMap': {}, 'spec': { 'properties': [ { @@ -1436,7 +1595,7 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_PARTIALS 'modules': { 'NativeSampleTurboModule': { 'type': 'NativeModule', - 'aliases': { + 'aliasMap': { 'SomeObj': { 'type': 'ObjectTypeAnnotation', 'properties': [ @@ -1457,6 +1616,7 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_PARTIALS ] } }, + 'enumMap': {}, 'spec': { 'properties': [ { @@ -1547,7 +1707,7 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_PARTIALS 'modules': { 'NativeSampleTurboModule': { 'type': 'NativeModule', - 'aliases': { + 'aliasMap': { 'SomeObj': { 'type': 'ObjectTypeAnnotation', 'properties': [ @@ -1568,6 +1728,7 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_PARTIALS ] } }, + 'enumMap': {}, 'spec': { 'properties': [ { @@ -1642,7 +1803,7 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_PROMISE 'modules': { 'NativeSampleTurboModule': { 'type': 'NativeModule', - 'aliases': { + 'aliasMap': { 'SomeObj': { 'type': 'ObjectTypeAnnotation', 'properties': [ @@ -1656,6 +1817,7 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_PROMISE ] } }, + 'enumMap': {}, 'spec': { 'properties': [ { @@ -1714,7 +1876,8 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_ROOT_TAG 'modules': { 'NativeSampleTurboModule': { 'type': 'NativeModule', - 'aliases': {}, + 'aliasMap': {}, + 'enumMap': {}, 'spec': { 'properties': [ { @@ -1751,7 +1914,8 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_SIMPLE_O 'modules': { 'NativeSampleTurboModule': { 'type': 'NativeModule', - 'aliases': {}, + 'aliasMap': {}, + 'enumMap': {}, 'spec': { 'properties': [ { @@ -1786,7 +1950,8 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_UNION 1` 'modules': { 'NativeSampleTurboModule': { 'type': 'NativeModule', - 'aliases': {}, + 'aliasMap': {}, + 'enumMap': {}, 'spec': { 'properties': [ { @@ -1847,7 +2012,8 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_UNSAFE_O 'modules': { 'NativeSampleTurboModule': { 'type': 'NativeModule', - 'aliases': {}, + 'aliasMap': {}, + 'enumMap': {}, 'spec': { 'properties': [ { @@ -1882,7 +2048,7 @@ exports[`RN Codegen Flow Parser can generate fixture PROMISE_WITH_COMMONLY_USED_ 'modules': { 'NativeSampleTurboModule': { 'type': 'NativeModule', - 'aliases': { + 'aliasMap': { 'CustomObject': { 'type': 'ObjectTypeAnnotation', 'properties': [ @@ -1921,6 +2087,7 @@ exports[`RN Codegen Flow Parser can generate fixture PROMISE_WITH_COMMONLY_USED_ ] } }, + 'enumMap': {}, 'spec': { 'properties': [ { diff --git a/packages/react-native-codegen/src/parsers/flow/modules/__tests__/module-parser-e2e-test.js b/packages/react-native-codegen/src/parsers/flow/modules/__tests__/module-parser-e2e-test.js index 07f1ad56afc73e..6cda41648a0013 100644 --- a/packages/react-native-codegen/src/parsers/flow/modules/__tests__/module-parser-e2e-test.js +++ b/packages/react-native-codegen/src/parsers/flow/modules/__tests__/module-parser-e2e-test.js @@ -60,7 +60,7 @@ type AnimalPointer = Animal; `; function expectAnimalTypeAliasToExist(module: NativeModuleSchema) { - const animalAlias = module.aliases.Animal; + const animalAlias = module.aliasMap.Animal; expect(animalAlias).not.toBe(null); invariant(animalAlias != null, ''); diff --git a/packages/react-native-codegen/src/parsers/flow/modules/index.js b/packages/react-native-codegen/src/parsers/flow/modules/index.js index eff16b613d8a07..6fa83c5bf96f79 100644 --- a/packages/react-native-codegen/src/parsers/flow/modules/index.js +++ b/packages/react-native-codegen/src/parsers/flow/modules/index.js @@ -13,6 +13,7 @@ import type { NamedShape, NativeModuleAliasMap, + NativeModuleEnumMap, NativeModuleBaseTypeAnnotation, NativeModuleTypeAnnotation, NativeModulePropertyShape, @@ -30,7 +31,6 @@ const { wrapNullable, assertGenericTypeAnnotationHasExactlyOneTypeParameter, parseObjectProperty, - translateDefault, buildPropertySchema, } = require('../../parsers-commons'); const { @@ -41,8 +41,8 @@ const { emitFunction, emitNumber, emitInt32, + emitGenericObject, emitObject, - emitPartial, emitPromise, emitRootTag, emitVoid, @@ -51,12 +51,13 @@ const { emitMixed, emitUnion, typeAliasResolution, - translateArrayTypeAnnotation, + typeEnumResolution, } = require('../../parsers-primitives'); const { UnsupportedTypeAnnotationParserError, IncorrectModuleRegistryCallArgumentTypeParserError, + UnsupportedGenericParserError, } = require('../../errors'); const { @@ -80,11 +81,12 @@ function translateTypeAnnotation( flowTypeAnnotation: $FlowFixMe, types: TypeDeclarationMap, aliasMap: {...NativeModuleAliasMap}, + enumMap: {...NativeModuleEnumMap}, tryParse: ParserErrorCapturer, cxxOnly: boolean, parser: Parser, ): Nullable { - const {nullable, typeAnnotation, typeAliasResolutionStatus} = + const {nullable, typeAnnotation, typeResolutionStatus} = resolveTypeAnnotation(flowTypeAnnotation, types); switch (typeAnnotation.type) { @@ -101,6 +103,7 @@ function translateTypeAnnotation( nullable, types, aliasMap, + enumMap, tryParse, cxxOnly, translateTypeAnnotation, @@ -114,6 +117,7 @@ function translateTypeAnnotation( parser, types, aliasMap, + enumMap, cxxOnly, nullable, translateTypeAnnotation, @@ -132,6 +136,7 @@ function translateTypeAnnotation( typeAnnotation.typeParameters.params[0], types, aliasMap, + enumMap, tryParse, cxxOnly, parser, @@ -154,7 +159,7 @@ function translateTypeAnnotation( } case 'UnsafeObject': case 'Object': { - return emitObject(nullable); + return emitGenericObject(nullable); } case '$Partial': { if (typeAnnotation.typeParameters.params.length !== 1) { @@ -181,6 +186,7 @@ function translateTypeAnnotation( prop.value, types, aliasMap, + enumMap, tryParse, cxxOnly, parser, @@ -188,14 +194,12 @@ function translateTypeAnnotation( }; }); - return emitPartial(nullable, properties); + return emitObject(nullable, properties); } default: { - return translateDefault( + throw new UnsupportedGenericParserError( hasteModuleName, typeAnnotation, - types, - nullable, parser, ); } @@ -216,12 +220,13 @@ function translateTypeAnnotation( propertyType, types, aliasMap, + enumMap, tryParse, cxxOnly, parser, ); // no need to do further checking - return emitObject(nullable); + return emitGenericObject(nullable); } } @@ -240,6 +245,7 @@ function translateTypeAnnotation( hasteModuleName, types, aliasMap, + enumMap, tryParse, cxxOnly, nullable, @@ -253,7 +259,7 @@ function translateTypeAnnotation( }; return typeAliasResolution( - typeAliasResolutionStatus, + typeResolutionStatus, objectTypeAnnotation, aliasMap, nullable, @@ -278,6 +284,7 @@ function translateTypeAnnotation( typeAnnotation, types, aliasMap, + enumMap, tryParse, cxxOnly, translateTypeAnnotation, @@ -298,9 +305,21 @@ function translateTypeAnnotation( if (cxxOnly) { return emitMixed(nullable); } else { - return emitObject(nullable); + return emitGenericObject(nullable); } } + case 'EnumStringBody': + case 'EnumNumberBody': { + return typeEnumResolution( + typeAnnotation, + typeResolutionStatus, + nullable, + hasteModuleName, + language, + enumMap, + parser, + ); + } default: { throw new UnsupportedTypeAnnotationParserError( hasteModuleName, @@ -430,16 +449,20 @@ function buildModuleSchema( .filter(property => property.type === 'ObjectTypeProperty') .map(property => { const aliasMap: {...NativeModuleAliasMap} = {}; + const enumMap: {...NativeModuleEnumMap} = {}; return tryParse(() => ({ aliasMap: aliasMap, + enumMap: enumMap, propertyShape: buildPropertySchema( hasteModuleName, property, types, aliasMap, + enumMap, tryParse, cxxOnly, resolveTypeAnnotation, @@ -450,9 +473,13 @@ function buildModuleSchema( }) .filter(Boolean) .reduce( - (moduleSchema: NativeModuleSchema, {aliasMap, propertyShape}) => ({ + ( + moduleSchema: NativeModuleSchema, + {aliasMap, enumMap, propertyShape}, + ) => ({ type: 'NativeModule', - aliases: {...moduleSchema.aliases, ...aliasMap}, + aliasMap: {...moduleSchema.aliasMap, ...aliasMap}, + enumMap: {...moduleSchema.enumMap, ...enumMap}, spec: { properties: [...moduleSchema.spec.properties, propertyShape], }, @@ -461,7 +488,8 @@ function buildModuleSchema( }), { type: 'NativeModule', - aliases: {}, + aliasMap: {}, + enumMap: {}, spec: {properties: []}, moduleName, excludedPlatforms: diff --git a/packages/react-native-codegen/src/parsers/flow/parser.js b/packages/react-native-codegen/src/parsers/flow/parser.js index 561ae77a3f19fd..bdcaf3b9eca91a 100644 --- a/packages/react-native-codegen/src/parsers/flow/parser.js +++ b/packages/react-native-codegen/src/parsers/flow/parser.js @@ -16,6 +16,8 @@ import type { NamedShape, Nullable, NativeModuleParamTypeAnnotation, + NativeModuleEnumMemberType, + NativeModuleEnumMembers, } from '../../CodegenSchema'; import type {ParserType} from '../errors'; import type {Parser} from '../parser'; @@ -54,16 +56,6 @@ class FlowParser implements Parser { return property.key.name; } - getMaybeEnumMemberType(maybeEnumDeclaration: $FlowFixMe): string { - return maybeEnumDeclaration.body.type - .replace('EnumNumberBody', 'NumberTypeAnnotation') - .replace('EnumStringBody', 'StringTypeAnnotation'); - } - - isEnumDeclaration(maybeEnumDeclaration: $FlowFixMe): boolean { - return maybeEnumDeclaration.type === 'EnumDeclaration'; - } - language(): ParserType { return 'Flow'; } @@ -148,6 +140,62 @@ class FlowParser implements Parser { ): $FlowFixMe { return functionTypeAnnotation.returnType; } + + parseEnumMembersType(typeAnnotation: $FlowFixMe): NativeModuleEnumMemberType { + const enumMembersType: ?NativeModuleEnumMemberType = + typeAnnotation.type === 'EnumStringBody' + ? 'StringTypeAnnotation' + : typeAnnotation.type === 'EnumNumberBody' + ? 'NumberTypeAnnotation' + : null; + if (!enumMembersType) { + throw new Error( + `Unknown enum type annotation type. Got: ${typeAnnotation.type}. Expected: EnumStringBody or EnumNumberBody.`, + ); + } + return enumMembersType; + } + + validateEnumMembersSupported( + typeAnnotation: $FlowFixMe, + enumMembersType: NativeModuleEnumMemberType, + ): void { + if (!typeAnnotation.members || typeAnnotation.members.length === 0) { + // passing mixed members to flow would result in a flow error + // if the tool is launched ignoring that error, the enum would appear like not having enums + throw new Error( + 'Enums should have at least one member and member values can not be mixed- they all must be either blank, number, or string values.', + ); + } + + typeAnnotation.members.forEach(member => { + if ( + enumMembersType === 'StringTypeAnnotation' && + (!member.init || typeof member.init.value === 'string') + ) { + return; + } + + if ( + enumMembersType === 'NumberTypeAnnotation' && + member.init && + typeof member.init.value === 'number' + ) { + return; + } + + throw new Error( + 'Enums can not be mixed- they all must be either blank, number, or string values.', + ); + }); + } + + parseEnumMembers(typeAnnotation: $FlowFixMe): NativeModuleEnumMembers { + return typeAnnotation.members.map(member => ({ + name: member.id.name, + value: member.init?.value ?? member.id.name, + })); + } } module.exports = { diff --git a/packages/react-native-codegen/src/parsers/flow/utils.js b/packages/react-native-codegen/src/parsers/flow/utils.js index f172d8ec4c8283..d8939913389f0f 100644 --- a/packages/react-native-codegen/src/parsers/flow/utils.js +++ b/packages/react-native-codegen/src/parsers/flow/utils.js @@ -10,7 +10,7 @@ 'use strict'; -import type {TypeAliasResolutionStatus, TypeDeclarationMap} from '../utils'; +import type {TypeResolutionStatus, TypeDeclarationMap} from '../utils'; /** * This FlowFixMe is supposed to refer to an InterfaceDeclaration or TypeAlias @@ -61,7 +61,7 @@ function resolveTypeAnnotation( ): { nullable: boolean, typeAnnotation: $FlowFixMe, - typeAliasResolutionStatus: TypeAliasResolutionStatus, + typeResolutionStatus: TypeResolutionStatus, } { invariant( typeAnnotation != null, @@ -70,7 +70,7 @@ function resolveTypeAnnotation( let node = typeAnnotation; let nullable = false; - let typeAliasResolutionStatus: TypeAliasResolutionStatus = { + let typeResolutionStatus: TypeResolutionStatus = { successful: false, }; @@ -78,34 +78,49 @@ function resolveTypeAnnotation( if (node.type === 'NullableTypeAnnotation') { nullable = true; node = node.typeAnnotation; - } else if (node.type === 'GenericTypeAnnotation') { - typeAliasResolutionStatus = { - successful: true, - aliasName: node.id.name, - }; - const resolvedTypeAnnotation = types[node.id.name]; - if ( - resolvedTypeAnnotation == null || - resolvedTypeAnnotation.type === 'EnumDeclaration' - ) { - break; - } + continue; + } - invariant( - resolvedTypeAnnotation.type === 'TypeAlias', - `GenericTypeAnnotation '${node.id.name}' must resolve to a TypeAlias. Instead, it resolved to a '${resolvedTypeAnnotation.type}'`, - ); + if (node.type !== 'GenericTypeAnnotation') { + break; + } - node = resolvedTypeAnnotation.right; - } else { + const resolvedTypeAnnotation = types[node.id.name]; + if (resolvedTypeAnnotation == null) { break; } + + switch (resolvedTypeAnnotation.type) { + case 'TypeAlias': { + typeResolutionStatus = { + successful: true, + type: 'alias', + name: node.id.name, + }; + node = resolvedTypeAnnotation.right; + break; + } + case 'EnumDeclaration': { + typeResolutionStatus = { + successful: true, + type: 'enum', + name: node.id.name, + }; + node = resolvedTypeAnnotation.body; + break; + } + default: { + throw new TypeError( + `A non GenericTypeAnnotation must be a type declaration ('TypeAlias') or enum ('EnumDeclaration'). Instead, got the unsupported ${resolvedTypeAnnotation.type}.`, + ); + } + } } return { nullable: nullable, typeAnnotation: node, - typeAliasResolutionStatus, + typeResolutionStatus, }; } diff --git a/packages/react-native-codegen/src/parsers/parser.js b/packages/react-native-codegen/src/parsers/parser.js index 9f73635e6eae65..52755f81fcbd96 100644 --- a/packages/react-native-codegen/src/parsers/parser.js +++ b/packages/react-native-codegen/src/parsers/parser.js @@ -16,6 +16,8 @@ import type { NamedShape, Nullable, NativeModuleParamTypeAnnotation, + NativeModuleEnumMemberType, + NativeModuleEnumMembers, } from '../CodegenSchema'; import type {ParserType} from './errors'; @@ -41,18 +43,6 @@ export interface Parser { * @throws if property does not contain a property declaration. */ getKeyName(property: $FlowFixMe, hasteModuleName: string): string; - /** - * Given a type declaration, it possibly returns the name of the Enum type. - * @parameter maybeEnumDeclaration: an object possibly containing an Enum declaration. - * @returns: the name of the Enum type. - */ - getMaybeEnumMemberType(maybeEnumDeclaration: $FlowFixMe): string; - /** - * Given a type declaration, it returns a boolean specifying if is an Enum declaration. - * @parameter maybeEnumDeclaration: an object possibly containing an Enum declaration. - * @returns: a boolean specifying if is an Enum declaration. - */ - isEnumDeclaration(maybeEnumDeclaration: $FlowFixMe): boolean; /** * @returns: the Parser language. */ @@ -144,4 +134,22 @@ export interface Parser { getFunctionTypeAnnotationReturnType( functionTypeAnnotation: $FlowFixMe, ): $FlowFixMe; + + /** + * Calculates an enum's members type + */ + parseEnumMembersType(typeAnnotation: $FlowFixMe): NativeModuleEnumMemberType; + + /** + * Throws if enum mebers are not supported + */ + validateEnumMembersSupported( + typeAnnotation: $FlowFixMe, + enumMembersType: NativeModuleEnumMemberType, + ): void; + + /** + * Calculates enum's members + */ + parseEnumMembers(typeAnnotation: $FlowFixMe): NativeModuleEnumMembers; } diff --git a/packages/react-native-codegen/src/parsers/parserMock.js b/packages/react-native-codegen/src/parsers/parserMock.js index c3caff7aaacd79..475920a0983825 100644 --- a/packages/react-native-codegen/src/parsers/parserMock.js +++ b/packages/react-native-codegen/src/parsers/parserMock.js @@ -18,6 +18,8 @@ import type { NamedShape, Nullable, NativeModuleParamTypeAnnotation, + NativeModuleEnumMemberType, + NativeModuleEnumMembers, } from '../CodegenSchema'; // $FlowFixMe[untyped-import] there's no flowtype flow-parser @@ -61,16 +63,6 @@ export class MockedParser implements Parser { return property.key.name; } - getMaybeEnumMemberType(maybeEnumDeclaration: $FlowFixMe): string { - return maybeEnumDeclaration.body.type - .replace('EnumNumberBody', 'NumberTypeAnnotation') - .replace('EnumStringBody', 'StringTypeAnnotation'); - } - - isEnumDeclaration(maybeEnumDeclaration: $FlowFixMe): boolean { - return maybeEnumDeclaration.type === 'EnumDeclaration'; - } - language(): ParserType { return 'Flow'; } @@ -132,4 +124,39 @@ export class MockedParser implements Parser { ): $FlowFixMe { return functionTypeAnnotation.returnType; } + + parseEnumMembersType(typeAnnotation: $FlowFixMe): NativeModuleEnumMemberType { + return typeAnnotation.type; + } + + validateEnumMembersSupported( + typeAnnotation: $FlowFixMe, + enumMembersType: NativeModuleEnumMemberType, + ): void { + return; + } + + parseEnumMembers(typeAnnotation: $FlowFixMe): NativeModuleEnumMembers { + return typeAnnotation.type === 'StringTypeAnnotation' + ? [ + { + name: 'Hello', + value: 'hello', + }, + { + name: 'Goodbye', + value: 'goodbye', + }, + ] + : [ + { + name: 'On', + value: '1', + }, + { + name: 'Off', + value: '0', + }, + ]; + } } diff --git a/packages/react-native-codegen/src/parsers/parsers-commons.js b/packages/react-native-codegen/src/parsers/parsers-commons.js index 9f0310107b833a..2509d384da96e8 100644 --- a/packages/react-native-codegen/src/parsers/parsers-commons.js +++ b/packages/react-native-codegen/src/parsers/parsers-commons.js @@ -15,7 +15,6 @@ import type { NamedShape, NativeModuleAliasMap, NativeModuleBaseTypeAnnotation, - NativeModuleEnumDeclaration, NativeModuleSchema, NativeModuleTypeAnnotation, NativeModuleFunctionTypeAnnotation, @@ -45,12 +44,11 @@ const { const { MissingTypeParameterGenericParserError, MoreThanOneTypeParameterGenericParserError, - UnsupportedEnumDeclarationParserError, - UnsupportedGenericParserError, UnnamedFunctionParamParserError, } = require('./errors'); const invariant = require('invariant'); +import type {NativeModuleEnumMap} from '../CodegenSchema'; function wrapModuleSchema( nativeModuleSchema: NativeModuleSchema, @@ -135,6 +133,7 @@ function parseObjectProperty( hasteModuleName: string, types: TypeDeclarationMap, aliasMap: {...NativeModuleAliasMap}, + enumMap: {...NativeModuleEnumMap}, tryParse: ParserErrorCapturer, cxxOnly: boolean, nullable: boolean, @@ -157,6 +156,7 @@ function parseObjectProperty( languageTypeAnnotation, types, aliasMap, + enumMap, tryParse, cxxOnly, parser, @@ -183,43 +183,6 @@ function parseObjectProperty( }; } -function translateDefault( - hasteModuleName: string, - typeAnnotation: $FlowFixMe, - types: TypeDeclarationMap, - nullable: boolean, - parser: Parser, -): Nullable { - const maybeEnumDeclaration = - types[parser.nameForGenericTypeAnnotation(typeAnnotation)]; - - if (maybeEnumDeclaration && parser.isEnumDeclaration(maybeEnumDeclaration)) { - const memberType = parser.getMaybeEnumMemberType(maybeEnumDeclaration); - - if ( - memberType === 'NumberTypeAnnotation' || - memberType === 'StringTypeAnnotation' - ) { - return wrapNullable(nullable, { - type: 'EnumDeclaration', - memberType: memberType, - }); - } else { - throw new UnsupportedEnumDeclarationParserError( - hasteModuleName, - typeAnnotation, - memberType, - ); - } - } - - throw new UnsupportedGenericParserError( - hasteModuleName, - typeAnnotation, - parser, - ); -} - function translateFunctionTypeAnnotation( hasteModuleName: string, // TODO(T108222691): Use flow-types for @babel/parser @@ -227,6 +190,7 @@ function translateFunctionTypeAnnotation( functionTypeAnnotation: $FlowFixMe, types: TypeDeclarationMap, aliasMap: {...NativeModuleAliasMap}, + enumMap: {...NativeModuleEnumMap}, tryParse: ParserErrorCapturer, cxxOnly: boolean, translateTypeAnnotation: $FlowFixMe, @@ -252,6 +216,7 @@ function translateFunctionTypeAnnotation( parser.getParameterTypeAnnotation(param), types, aliasMap, + enumMap, tryParse, cxxOnly, parser, @@ -292,6 +257,7 @@ function translateFunctionTypeAnnotation( parser.getFunctionTypeAnnotationReturnType(functionTypeAnnotation), types, aliasMap, + enumMap, tryParse, cxxOnly, parser, @@ -326,6 +292,7 @@ function buildPropertySchema( property: $FlowFixMe, types: TypeDeclarationMap, aliasMap: {...NativeModuleAliasMap}, + enumMap: {...NativeModuleEnumMap}, tryParse: ParserErrorCapturer, cxxOnly: boolean, resolveTypeAnnotation: $FlowFixMe, @@ -363,6 +330,7 @@ function buildPropertySchema( value, types, aliasMap, + enumMap, tryParse, cxxOnly, translateTypeAnnotation, @@ -471,7 +439,6 @@ module.exports = { assertGenericTypeAnnotationHasExactlyOneTypeParameter, isObjectProperty, parseObjectProperty, - translateDefault, translateFunctionTypeAnnotation, buildPropertySchema, buildSchemaFromConfigType, diff --git a/packages/react-native-codegen/src/parsers/parsers-primitives.js b/packages/react-native-codegen/src/parsers/parsers-primitives.js index e9af9b41bbbd46..9b225fbc85c901 100644 --- a/packages/react-native-codegen/src/parsers/parsers-primitives.js +++ b/packages/react-native-codegen/src/parsers/parsers-primitives.js @@ -16,6 +16,7 @@ import type { DoubleTypeAnnotation, Int32TypeAnnotation, NativeModuleAliasMap, + NativeModuleEnumMap, NativeModuleBaseTypeAnnotation, NativeModuleTypeAnnotation, NativeModuleFloatTypeAnnotation, @@ -31,15 +32,22 @@ import type { StringTypeAnnotation, VoidTypeAnnotation, NativeModuleObjectTypeAnnotation, + NativeModuleEnumDeclaration, } from '../CodegenSchema'; +import type {ParserType} from './errors'; import type {Parser} from './parser'; import type { ParserErrorCapturer, - TypeAliasResolutionStatus, + TypeResolutionStatus, TypeDeclarationMap, } from './utils'; -const {UnsupportedUnionTypeAnnotationParserError} = require('./errors'); +const { + UnsupportedUnionTypeAnnotationParserError, + UnsupportedTypeAnnotationParserError, + ParserError, +} = require('./errors'); + const { throwIfArrayElementTypeAnnotationIsUnsupported, } = require('./error-utils'); @@ -102,6 +110,7 @@ function emitFunction( typeAnnotation: $FlowFixMe, types: TypeDeclarationMap, aliasMap: {...NativeModuleAliasMap}, + enumMap: {...NativeModuleEnumMap}, tryParse: ParserErrorCapturer, cxxOnly: boolean, translateTypeAnnotation: $FlowFixMe, @@ -113,6 +122,7 @@ function emitFunction( typeAnnotation, types, aliasMap, + enumMap, tryParse, cxxOnly, translateTypeAnnotation, @@ -136,7 +146,7 @@ function emitString(nullable: boolean): Nullable { } function typeAliasResolution( - typeAliasResolutionStatus: TypeAliasResolutionStatus, + typeResolution: TypeResolutionStatus, objectTypeAnnotation: ObjectTypeAnnotation< Nullable, >, @@ -145,14 +155,14 @@ function typeAliasResolution( ): | Nullable | Nullable>> { - if (!typeAliasResolutionStatus.successful) { + if (!typeResolution.successful) { return wrapNullable(nullable, objectTypeAnnotation); } /** * All aliases RHS are required. */ - aliasMap[typeAliasResolutionStatus.aliasName] = objectTypeAnnotation; + aliasMap[typeResolution.name] = objectTypeAnnotation; /** * Nullability of type aliases is transitive. @@ -185,7 +195,58 @@ function typeAliasResolution( */ return wrapNullable(nullable, { type: 'TypeAliasTypeAnnotation', - name: typeAliasResolutionStatus.aliasName, + name: typeResolution.name, + }); +} + +function typeEnumResolution( + typeAnnotation: $FlowFixMe, + typeResolution: TypeResolutionStatus, + nullable: boolean, + hasteModuleName: string, + language: ParserType, + enumMap: {...NativeModuleEnumMap}, + parser: Parser, +): Nullable { + if (!typeResolution.successful || typeResolution.type !== 'enum') { + throw new UnsupportedTypeAnnotationParserError( + hasteModuleName, + typeAnnotation, + language, + ); + } + + const enumName = typeResolution.name; + + const enumMemberType = parser.parseEnumMembersType(typeAnnotation); + + try { + parser.validateEnumMembersSupported(typeAnnotation, enumMemberType); + } catch (e) { + if (e instanceof Error) { + throw new ParserError( + hasteModuleName, + typeAnnotation, + `Failed parsing the enum ${enumName} in ${hasteModuleName} with the error: ${e.message}`, + ); + } else { + throw e; + } + } + + const enumMembers = parser.parseEnumMembers(typeAnnotation); + + enumMap[enumName] = { + name: enumName, + type: 'EnumDeclarationWithMembers', + memberType: enumMemberType, + members: enumMembers, + }; + + return wrapNullable(nullable, { + name: enumName, + type: 'EnumDeclaration', + memberType: enumMemberType, }); } @@ -196,6 +257,7 @@ function emitPromise( nullable: boolean, types: TypeDeclarationMap, aliasMap: {...NativeModuleAliasMap}, + enumMap: {...NativeModuleEnumMap}, tryParse: ParserErrorCapturer, cxxOnly: boolean, translateTypeAnnotation: $FlowFixMe, @@ -223,6 +285,7 @@ function emitPromise( typeAnnotation.typeParameters.params[0], types, aliasMap, + enumMap, tryParse, cxxOnly, parser, @@ -236,7 +299,7 @@ function emitPromise( } } -function emitObject( +function emitGenericObject( nullable: boolean, ): Nullable { return wrapNullable(nullable, { @@ -244,7 +307,7 @@ function emitObject( }); } -function emitPartial( +function emitObject( nullable: boolean, properties: Array<$FlowFixMe>, ): Nullable { @@ -291,6 +354,7 @@ function translateArrayTypeAnnotation( hasteModuleName: string, types: TypeDeclarationMap, aliasMap: {...NativeModuleAliasMap}, + enumMap: {...NativeModuleEnumMap}, cxxOnly: boolean, arrayType: 'Array' | 'ReadonlyArray', elementType: $FlowFixMe, @@ -310,6 +374,7 @@ function translateArrayTypeAnnotation( elementType, types, aliasMap, + enumMap, /** * TODO(T72031674): Ensure that all ParsingErrors that are thrown * while parsing the array element don't get captured and collected. @@ -349,6 +414,7 @@ function emitArrayType( parser: Parser, types: TypeDeclarationMap, aliasMap: {...NativeModuleAliasMap}, + enumMap: {...NativeModuleEnumMap}, cxxOnly: boolean, nullable: boolean, translateTypeAnnotation: $FlowFixMe, @@ -363,6 +429,7 @@ function emitArrayType( hasteModuleName, types, aliasMap, + enumMap, cxxOnly, typeAnnotation.type, typeAnnotation.typeParameters.params[0], @@ -380,8 +447,8 @@ module.exports = { emitFunction, emitInt32, emitNumber, + emitGenericObject, emitObject, - emitPartial, emitPromise, emitRootTag, emitVoid, @@ -390,5 +457,6 @@ module.exports = { emitMixed, emitUnion, typeAliasResolution, + typeEnumResolution, translateArrayTypeAnnotation, }; 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 f25e8b3d10347a..a8d08e8395ff9a 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 @@ -156,6 +156,58 @@ export interface Spec2 extends TurboModule { } `; +const EMPTY_ENUM_NATIVE_MODULE = ` +/** + * 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 + */ + +import type {TurboModule} from 'react-native/Libraries/TurboModule/RCTExport'; +import * as TurboModuleRegistry from 'react-native/Libraries/TurboModule/TurboModuleRegistry'; + +export enum SomeEnum { +} + +export interface Spec extends TurboModule { + readonly getEnums: (a: SomeEnum) => string; +} + +export default TurboModuleRegistry.getEnforcing( + 'EmptyEnumNativeModule', +); +`; + +const MIXED_VALUES_ENUM_NATIVE_MODULE = ` +/** + * 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 + */ + +import type {TurboModule} from 'react-native/Libraries/TurboModule/RCTExport'; +import * as TurboModuleRegistry from 'react-native/Libraries/TurboModule/TurboModuleRegistry'; + +export enum SomeEnum { + NUM = 1, + STR = 'str', +} + +export interface Spec extends TurboModule { + readonly getEnums: (a: SomeEnum) => string; +} + +export default TurboModuleRegistry.getEnforcing( + 'MixedValuesEnumNativeModule', +); +`; + module.exports = { NATIVE_MODULES_WITH_UNNAMED_PARAMS, NATIVE_MODULES_WITH_PROMISE_WITHOUT_TYPE, @@ -164,4 +216,6 @@ module.exports = { TWO_NATIVE_MODULES_EXPORTED_WITH_DEFAULT, NATIVE_MODULES_WITH_NOT_ONLY_METHODS, TWO_NATIVE_EXTENDING_TURBO_MODULE, + EMPTY_ENUM_NATIVE_MODULE, + MIXED_VALUES_ENUM_NATIVE_MODULE, }; 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 ead2dde77b13d8..5f6377869afb1d 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 @@ -239,6 +239,50 @@ export default TurboModuleRegistry.getEnforcing('SampleTurboModule'); `; +const NATIVE_MODULE_WITH_INTERSECTION_TYPES = ` +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + */ + + +import type {TurboModule} from '../RCTExport'; +import * as TurboModuleRegistry from '../TurboModuleRegistry'; + +type Bar = { + z: number +}; + +type Base1 = { + bar1: Bar, +} + +type Base2 = { + bar2: Bar, +} + +type Base3 = Base2 & { + bar3: Bar, +} + +type Foo = Base1 & Base3 & { + bar4: Bar, +}; + +export interface Spec extends TurboModule { + // Exported methods. + foo1: (x: Foo) => Foo; + foo2: (x: Foo) => void; +} + +export default TurboModuleRegistry.getEnforcing('SampleTurboModule'); + +`; + const NATIVE_MODULE_WITH_FLOAT_AND_INT32 = ` /** * Copyright (c) Meta Platforms, Inc. and affiliates. @@ -803,6 +847,7 @@ module.exports = { NATIVE_MODULE_WITH_ALIASES, NATIVE_MODULE_WITH_NESTED_ALIASES, NATIVE_MODULE_WITH_NESTED_INTERFACES, + NATIVE_MODULE_WITH_INTERSECTION_TYPES, NATIVE_MODULE_WITH_PROMISE, NATIVE_MODULE_WITH_COMPLEX_OBJECTS, NATIVE_MODULE_WITH_COMPLEX_OBJECTS_WITH_NULLABLE_KEY, diff --git a/packages/react-native-codegen/src/parsers/typescript/modules/__tests__/__snapshots__/typescript-module-parser-snapshot-test.js.snap b/packages/react-native-codegen/src/parsers/typescript/modules/__tests__/__snapshots__/typescript-module-parser-snapshot-test.js.snap index d6f4f9d4e3679e..6f7033c94407af 100644 --- a/packages/react-native-codegen/src/parsers/typescript/modules/__tests__/__snapshots__/typescript-module-parser-snapshot-test.js.snap +++ b/packages/react-native-codegen/src/parsers/typescript/modules/__tests__/__snapshots__/typescript-module-parser-snapshot-test.js.snap @@ -1,5 +1,9 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`RN Codegen TypeScript Parser Fails with error message EMPTY_ENUM_NATIVE_MODULE 1`] = `"Module NativeSampleTurboModule: Failed parsing the enum SomeEnum in NativeSampleTurboModule with the error: Enums should have at least one member."`; + +exports[`RN Codegen TypeScript Parser Fails with error message MIXED_VALUES_ENUM_NATIVE_MODULE 1`] = `"Module NativeSampleTurboModule: Failed parsing the enum SomeEnum in NativeSampleTurboModule with the error: Enum values can not be mixed. They all must be either blank, number, or string values."`; + exports[`RN Codegen TypeScript Parser Fails with error message NATIVE_MODULES_WITH_ARRAY_WITH_NO_TYPE_FOR_CONTENT 1`] = `"Module NativeSampleTurboModule: Generic 'Array' must have type parameters."`; exports[`RN Codegen TypeScript Parser Fails with error message NATIVE_MODULES_WITH_ARRAY_WITH_NO_TYPE_FOR_CONTENT_AS_PARAM 1`] = `"Module NativeSampleTurboModule: Generic 'Array' must have type parameters."`; @@ -19,7 +23,8 @@ exports[`RN Codegen TypeScript Parser can generate fixture ANDROID_ONLY_NATIVE_M 'modules': { 'NativeSampleTurboModule': { 'type': 'NativeModule', - 'aliases': {}, + 'aliasMap': {}, + 'enumMap': {}, 'spec': { 'properties': [] }, @@ -37,7 +42,73 @@ exports[`RN Codegen TypeScript Parser can generate fixture CXX_ONLY_NATIVE_MODUL 'modules': { 'NativeSampleTurboModule': { 'type': 'NativeModule', - 'aliases': {}, + 'aliasMap': {}, + 'enumMap': { + 'Quality': { + 'name': 'Quality', + 'type': 'EnumDeclarationWithMembers', + 'memberType': 'StringTypeAnnotation', + 'members': [ + { + 'name': 'SD', + 'value': 'SD' + }, + { + 'name': 'HD', + 'value': 'HD' + } + ] + }, + 'Resolution': { + 'name': 'Resolution', + 'type': 'EnumDeclarationWithMembers', + 'memberType': 'NumberTypeAnnotation', + 'members': [ + { + 'name': 'Low', + 'value': 720 + }, + { + 'name': 'High', + 'value': 1080 + } + ] + }, + 'Floppy': { + 'name': 'Floppy', + 'type': 'EnumDeclarationWithMembers', + 'memberType': 'NumberTypeAnnotation', + 'members': [ + { + 'name': 'LowDensity', + 'value': 0.72 + }, + { + 'name': 'HighDensity', + 'value': 1.44 + } + ] + }, + 'StringOptions': { + 'name': 'StringOptions', + 'type': 'EnumDeclarationWithMembers', + 'memberType': 'StringTypeAnnotation', + 'members': [ + { + 'name': 'One', + 'value': 'one' + }, + { + 'name': 'Two', + 'value': 'two' + }, + { + 'name': 'Three', + 'value': 'three' + } + ] + } + }, 'spec': { 'properties': [ { @@ -87,6 +158,7 @@ exports[`RN Codegen TypeScript Parser can generate fixture CXX_ONLY_NATIVE_MODUL 'name': 'quality', 'optional': false, 'typeAnnotation': { + 'name': 'Quality', 'type': 'EnumDeclaration', 'memberType': 'StringTypeAnnotation' } @@ -95,6 +167,7 @@ exports[`RN Codegen TypeScript Parser can generate fixture CXX_ONLY_NATIVE_MODUL 'name': 'resolution', 'optional': true, 'typeAnnotation': { + 'name': 'Resolution', 'type': 'EnumDeclaration', 'memberType': 'NumberTypeAnnotation' } @@ -103,6 +176,7 @@ exports[`RN Codegen TypeScript Parser can generate fixture CXX_ONLY_NATIVE_MODUL 'name': 'floppy', 'optional': false, 'typeAnnotation': { + 'name': 'Floppy', 'type': 'EnumDeclaration', 'memberType': 'NumberTypeAnnotation' } @@ -111,6 +185,7 @@ exports[`RN Codegen TypeScript Parser can generate fixture CXX_ONLY_NATIVE_MODUL 'name': 'stringOptions', 'optional': false, 'typeAnnotation': { + 'name': 'StringOptions', 'type': 'EnumDeclaration', 'memberType': 'StringTypeAnnotation' } @@ -218,7 +293,8 @@ exports[`RN Codegen TypeScript Parser can generate fixture EMPTY_NATIVE_MODULE 1 'modules': { 'NativeSampleTurboModule': { 'type': 'NativeModule', - 'aliases': {}, + 'aliasMap': {}, + 'enumMap': {}, 'spec': { 'properties': [] }, @@ -233,7 +309,73 @@ exports[`RN Codegen TypeScript Parser can generate fixture IOS_ONLY_NATIVE_MODUL 'modules': { 'NativeSampleTurboModule': { 'type': 'NativeModule', - 'aliases': {}, + 'aliasMap': {}, + 'enumMap': { + 'Quality': { + 'name': 'Quality', + 'type': 'EnumDeclarationWithMembers', + 'memberType': 'StringTypeAnnotation', + 'members': [ + { + 'name': 'SD', + 'value': 'SD' + }, + { + 'name': 'HD', + 'value': 'HD' + } + ] + }, + 'Resolution': { + 'name': 'Resolution', + 'type': 'EnumDeclarationWithMembers', + 'memberType': 'NumberTypeAnnotation', + 'members': [ + { + 'name': 'Low', + 'value': 720 + }, + { + 'name': 'High', + 'value': 1080 + } + ] + }, + 'Floppy': { + 'name': 'Floppy', + 'type': 'EnumDeclarationWithMembers', + 'memberType': 'NumberTypeAnnotation', + 'members': [ + { + 'name': 'LowDensity', + 'value': 0.72 + }, + { + 'name': 'HighDensity', + 'value': 1.44 + } + ] + }, + 'StringOptions': { + 'name': 'StringOptions', + 'type': 'EnumDeclarationWithMembers', + 'memberType': 'StringTypeAnnotation', + 'members': [ + { + 'name': 'One', + 'value': 'one' + }, + { + 'name': 'Two', + 'value': 'two' + }, + { + 'name': 'Three', + 'value': 'three' + } + ] + } + }, 'spec': { 'properties': [ { @@ -249,6 +391,7 @@ exports[`RN Codegen TypeScript Parser can generate fixture IOS_ONLY_NATIVE_MODUL 'name': 'quality', 'optional': false, 'typeAnnotation': { + 'name': 'Quality', 'type': 'EnumDeclaration', 'memberType': 'StringTypeAnnotation' } @@ -257,6 +400,7 @@ exports[`RN Codegen TypeScript Parser can generate fixture IOS_ONLY_NATIVE_MODUL 'name': 'resolution', 'optional': true, 'typeAnnotation': { + 'name': 'Resolution', 'type': 'EnumDeclaration', 'memberType': 'NumberTypeAnnotation' } @@ -265,6 +409,7 @@ exports[`RN Codegen TypeScript Parser can generate fixture IOS_ONLY_NATIVE_MODUL 'name': 'floppy', 'optional': false, 'typeAnnotation': { + 'name': 'Floppy', 'type': 'EnumDeclaration', 'memberType': 'NumberTypeAnnotation' } @@ -273,6 +418,7 @@ exports[`RN Codegen TypeScript Parser can generate fixture IOS_ONLY_NATIVE_MODUL 'name': 'stringOptions', 'optional': false, 'typeAnnotation': { + 'name': 'StringOptions', 'type': 'EnumDeclaration', 'memberType': 'StringTypeAnnotation' } @@ -296,7 +442,7 @@ exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_AL 'modules': { 'NativeSampleTurboModule': { 'type': 'NativeModule', - 'aliases': { + 'aliasMap': { 'ObjectAlias': { 'type': 'ObjectTypeAnnotation', 'properties': [ @@ -331,6 +477,7 @@ exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_AL ] } }, + 'enumMap': {}, 'spec': { 'properties': [ { @@ -493,7 +640,8 @@ exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_AR 'modules': { 'NativeSampleTurboModule': { 'type': 'NativeModule', - 'aliases': {}, + 'aliasMap': {}, + 'enumMap': {}, 'spec': { 'properties': [ { @@ -534,7 +682,8 @@ exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_AR 'modules': { 'NativeSampleTurboModule': { 'type': 'NativeModule', - 'aliases': {}, + 'aliasMap': {}, + 'enumMap': {}, 'spec': { 'properties': [ { @@ -569,7 +718,8 @@ exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_AR 'modules': { 'NativeSampleTurboModule': { 'type': 'NativeModule', - 'aliases': {}, + 'aliasMap': {}, + 'enumMap': {}, 'spec': { 'properties': [ { @@ -610,7 +760,8 @@ exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_AR 'modules': { 'NativeSampleTurboModule': { 'type': 'NativeModule', - 'aliases': {}, + 'aliasMap': {}, + 'enumMap': {}, 'spec': { 'properties': [ { @@ -645,7 +796,8 @@ exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_BA 'modules': { 'NativeSampleTurboModule': { 'type': 'NativeModule', - 'aliases': {}, + 'aliasMap': {}, + 'enumMap': {}, 'spec': { 'properties': [ { @@ -711,7 +863,8 @@ exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_BA 'modules': { 'NativeSampleTurboModule': { 'type': 'NativeModule', - 'aliases': {}, + 'aliasMap': {}, + 'enumMap': {}, 'spec': { 'properties': [ { @@ -777,7 +930,8 @@ exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_BA 'modules': { 'NativeSampleTurboModule': { 'type': 'NativeModule', - 'aliases': {}, + 'aliasMap': {}, + 'enumMap': {}, 'spec': { 'properties': [ { @@ -869,7 +1023,8 @@ exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_CA 'modules': { 'NativeSampleTurboModule': { 'type': 'NativeModule', - 'aliases': {}, + 'aliasMap': {}, + 'enumMap': {}, 'spec': { 'properties': [ { @@ -929,7 +1084,8 @@ exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_CO 'modules': { 'NativeSampleTurboModule': { 'type': 'NativeModule', - 'aliases': {}, + 'aliasMap': {}, + 'enumMap': {}, 'spec': { 'properties': [ { @@ -988,7 +1144,8 @@ exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_CO 'modules': { 'NativeSampleTurboModule': { 'type': 'NativeModule', - 'aliases': {}, + 'aliasMap': {}, + 'enumMap': {}, 'spec': { 'properties': [ { @@ -1047,7 +1204,8 @@ exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_CO 'modules': { 'NativeSampleTurboModule': { 'type': 'NativeModule', - 'aliases': {}, + 'aliasMap': {}, + 'enumMap': {}, 'spec': { 'properties': [ { @@ -1259,7 +1417,8 @@ exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_CO 'modules': { 'NativeSampleTurboModule': { 'type': 'NativeModule', - 'aliases': {}, + 'aliasMap': {}, + 'enumMap': {}, 'spec': { 'properties': [ { @@ -1363,7 +1522,8 @@ exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_FL 'modules': { 'NativeSampleTurboModule': { 'type': 'NativeModule', - 'aliases': {}, + 'aliasMap': {}, + 'enumMap': {}, 'spec': { 'properties': [ { @@ -1412,12 +1572,120 @@ exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_FL }" `; +exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_INTERSECTION_TYPES 1`] = ` +"{ + 'modules': { + 'NativeSampleTurboModule': { + 'type': 'NativeModule', + 'aliasMap': { + 'Bar': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'z', + 'optional': false, + 'typeAnnotation': { + 'type': 'NumberTypeAnnotation' + } + } + ] + }, + 'Foo': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'bar1', + 'optional': false, + 'typeAnnotation': { + 'type': 'TypeAliasTypeAnnotation', + 'name': 'Bar' + } + }, + { + 'name': 'bar2', + 'optional': false, + 'typeAnnotation': { + 'type': 'TypeAliasTypeAnnotation', + 'name': 'Bar' + } + }, + { + 'name': 'bar3', + 'optional': false, + 'typeAnnotation': { + 'type': 'TypeAliasTypeAnnotation', + 'name': 'Bar' + } + }, + { + 'name': 'bar4', + 'optional': false, + 'typeAnnotation': { + 'type': 'TypeAliasTypeAnnotation', + 'name': 'Bar' + } + } + ] + } + }, + 'enumMap': {}, + 'spec': { + 'properties': [ + { + 'name': 'foo1', + 'optional': false, + 'typeAnnotation': { + 'type': 'FunctionTypeAnnotation', + 'returnTypeAnnotation': { + 'type': 'TypeAliasTypeAnnotation', + 'name': 'Foo' + }, + 'params': [ + { + 'name': 'x', + 'optional': false, + 'typeAnnotation': { + 'type': 'TypeAliasTypeAnnotation', + 'name': 'Foo' + } + } + ] + } + }, + { + 'name': 'foo2', + 'optional': false, + 'typeAnnotation': { + 'type': 'FunctionTypeAnnotation', + 'returnTypeAnnotation': { + 'type': 'VoidTypeAnnotation' + }, + 'params': [ + { + 'name': 'x', + 'optional': false, + 'typeAnnotation': { + 'type': 'TypeAliasTypeAnnotation', + 'name': 'Foo' + } + } + ] + } + } + ] + }, + 'moduleName': 'SampleTurboModule' + } + } +}" +`; + exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_NESTED_ALIASES 1`] = ` "{ 'modules': { 'NativeSampleTurboModule': { 'type': 'NativeModule', - 'aliases': { + 'aliasMap': { 'Bar': { 'type': 'ObjectTypeAnnotation', 'properties': [ @@ -1452,6 +1720,7 @@ exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_NE ] } }, + 'enumMap': {}, 'spec': { 'properties': [ { @@ -1508,7 +1777,7 @@ exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_NE 'modules': { 'NativeSampleTurboModule': { 'type': 'NativeModule', - 'aliases': { + 'aliasMap': { 'Bar': { 'type': 'ObjectTypeAnnotation', 'properties': [ @@ -1521,6 +1790,56 @@ exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_NE } ] }, + 'Base1': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'bar1', + 'optional': false, + 'typeAnnotation': { + 'type': 'TypeAliasTypeAnnotation', + 'name': 'Bar' + } + } + ] + }, + 'Base2': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'bar2', + 'optional': false, + 'typeAnnotation': { + 'type': 'TypeAliasTypeAnnotation', + 'name': 'Bar' + } + } + ] + }, + 'Base3': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'bar2', + 'optional': false, + 'typeAnnotation': { + 'type': 'TypeAliasTypeAnnotation', + 'name': 'Bar' + } + }, + { + 'name': 'bar3', + 'optional': false, + 'typeAnnotation': { + 'type': 'TypeAliasTypeAnnotation', + 'name': 'Bar' + } + } + ], + 'baseTypes': [ + 'Base2' + ] + }, 'Foo': { 'type': 'ObjectTypeAnnotation', 'properties': [ @@ -1556,9 +1875,14 @@ exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_NE 'name': 'Bar' } } + ], + 'baseTypes': [ + 'Base1', + 'Base3' ] } }, + 'enumMap': {}, 'spec': { 'properties': [ { @@ -1615,7 +1939,8 @@ exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_NU 'modules': { 'NativeSampleTurboModule': { 'type': 'NativeModule', - 'aliases': {}, + 'aliasMap': {}, + 'enumMap': {}, 'spec': { 'properties': [ { @@ -1653,7 +1978,7 @@ exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_OB 'modules': { 'NativeSampleTurboModule': { 'type': 'NativeModule', - 'aliases': { + 'aliasMap': { 'DisplayMetricsAndroid': { 'type': 'ObjectTypeAnnotation', 'properties': [ @@ -1667,6 +1992,7 @@ exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_OB ] } }, + 'enumMap': {}, 'spec': { 'properties': [ { @@ -1742,7 +2068,7 @@ exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_PA 'modules': { 'NativeSampleTurboModule': { 'type': 'NativeModule', - 'aliases': { + 'aliasMap': { 'SomeObj': { 'type': 'ObjectTypeAnnotation', 'properties': [ @@ -1763,6 +2089,7 @@ exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_PA ] } }, + 'enumMap': {}, 'spec': { 'properties': [ { @@ -1853,7 +2180,7 @@ exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_PA 'modules': { 'NativeSampleTurboModule': { 'type': 'NativeModule', - 'aliases': { + 'aliasMap': { 'SomeObj': { 'type': 'ObjectTypeAnnotation', 'properties': [ @@ -1874,6 +2201,7 @@ exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_PA ] } }, + 'enumMap': {}, 'spec': { 'properties': [ { @@ -1948,7 +2276,7 @@ exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_PR 'modules': { 'NativeSampleTurboModule': { 'type': 'NativeModule', - 'aliases': { + 'aliasMap': { 'SomeObj': { 'type': 'ObjectTypeAnnotation', 'properties': [ @@ -1962,6 +2290,7 @@ exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_PR ] } }, + 'enumMap': {}, 'spec': { 'properties': [ { @@ -2020,7 +2349,8 @@ exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_RO 'modules': { 'NativeSampleTurboModule': { 'type': 'NativeModule', - 'aliases': {}, + 'aliasMap': {}, + 'enumMap': {}, 'spec': { 'properties': [ { @@ -2057,7 +2387,8 @@ exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_SI 'modules': { 'NativeSampleTurboModule': { 'type': 'NativeModule', - 'aliases': {}, + 'aliasMap': {}, + 'enumMap': {}, 'spec': { 'properties': [ { @@ -2092,7 +2423,8 @@ exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_UN 'modules': { 'NativeSampleTurboModule': { 'type': 'NativeModule', - 'aliases': {}, + 'aliasMap': {}, + 'enumMap': {}, 'spec': { 'properties': [ { @@ -2153,7 +2485,8 @@ exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_UN 'modules': { 'NativeSampleTurboModule': { 'type': 'NativeModule', - 'aliases': {}, + 'aliasMap': {}, + 'enumMap': {}, 'spec': { 'properties': [ { diff --git a/packages/react-native-codegen/src/parsers/typescript/modules/__tests__/typescript-module-parser-e2e-test.js b/packages/react-native-codegen/src/parsers/typescript/modules/__tests__/typescript-module-parser-e2e-test.js index 507895ba589433..04b471ac808dd0 100644 --- a/packages/react-native-codegen/src/parsers/typescript/modules/__tests__/typescript-module-parser-e2e-test.js +++ b/packages/react-native-codegen/src/parsers/typescript/modules/__tests__/typescript-module-parser-e2e-test.js @@ -60,7 +60,7 @@ type AnimalPointer = Animal; `; function expectAnimalTypeAliasToExist(module: NativeModuleSchema) { - const animalAlias = module.aliases.Animal; + const animalAlias = module.aliasMap.Animal; expect(animalAlias).not.toBe(null); invariant(animalAlias != null, ''); diff --git a/packages/react-native-codegen/src/parsers/typescript/modules/index.js b/packages/react-native-codegen/src/parsers/typescript/modules/index.js index 6097b5b11824c8..64cd08459c0858 100644 --- a/packages/react-native-codegen/src/parsers/typescript/modules/index.js +++ b/packages/react-native-codegen/src/parsers/typescript/modules/index.js @@ -13,6 +13,7 @@ import type { NamedShape, NativeModuleAliasMap, + NativeModuleEnumMap, NativeModuleBaseTypeAnnotation, NativeModulePropertyShape, NativeModuleTypeAnnotation, @@ -21,7 +22,12 @@ import type { } from '../../../CodegenSchema'; import type {Parser} from '../../parser'; -import type {ParserErrorCapturer, TypeDeclarationMap} from '../../utils'; +import type { + ParserErrorCapturer, + TypeResolutionStatus, + TypeDeclarationMap, +} from '../../utils'; +const {flattenIntersectionType} = require('../parseTopLevelType'); const {flattenProperties} = require('../components/componentsUtils'); const {visit, isModuleRegistryCall, verifyPlatforms} = require('../../utils'); @@ -29,9 +35,9 @@ const {resolveTypeAnnotation, getTypes} = require('../utils'); const { parseObjectProperty, - translateDefault, buildPropertySchema, } = require('../../parsers-commons'); +const {typeEnumResolution} = require('../../parsers-primitives'); const { emitArrayType, @@ -41,8 +47,8 @@ const { emitFunction, emitNumber, emitInt32, + emitGenericObject, emitObject, - emitPartial, emitPromise, emitRootTag, emitVoid, @@ -73,6 +79,64 @@ const { const language = 'TypeScript'; +function translateObjectTypeAnnotation( + hasteModuleName: string, + /** + * TODO(T108222691): Use flow-types for @babel/parser + */ + nullable: boolean, + objectMembers: $ReadOnlyArray<$FlowFixMe>, + typeResolutionStatus: TypeResolutionStatus, + baseTypes: $ReadOnlyArray, + types: TypeDeclarationMap, + aliasMap: {...NativeModuleAliasMap}, + enumMap: {...NativeModuleEnumMap}, + tryParse: ParserErrorCapturer, + cxxOnly: boolean, + parser: Parser, +): Nullable { + // $FlowFixMe[missing-type-arg] + const properties = objectMembers + .map>>(property => { + return tryParse(() => { + return parseObjectProperty( + property, + hasteModuleName, + types, + aliasMap, + enumMap, + tryParse, + cxxOnly, + nullable, + translateTypeAnnotation, + parser, + ); + }); + }) + .filter(Boolean); + + let objectTypeAnnotation; + if (baseTypes.length === 0) { + objectTypeAnnotation = { + type: 'ObjectTypeAnnotation', + properties, + }; + } else { + objectTypeAnnotation = { + type: 'ObjectTypeAnnotation', + properties, + baseTypes, + }; + } + + return typeAliasResolution( + typeResolutionStatus, + objectTypeAnnotation, + aliasMap, + nullable, + ); +} + function translateTypeAnnotation( hasteModuleName: string, /** @@ -81,11 +145,12 @@ function translateTypeAnnotation( typeScriptTypeAnnotation: $FlowFixMe, types: TypeDeclarationMap, aliasMap: {...NativeModuleAliasMap}, + enumMap: {...NativeModuleEnumMap}, tryParse: ParserErrorCapturer, cxxOnly: boolean, parser: Parser, ): Nullable { - const {nullable, typeAnnotation, typeAliasResolutionStatus} = + const {nullable, typeAnnotation, typeResolutionStatus} = resolveTypeAnnotation(typeScriptTypeAnnotation, types); switch (typeAnnotation.type) { @@ -94,6 +159,7 @@ function translateTypeAnnotation( hasteModuleName, types, aliasMap, + enumMap, cxxOnly, 'Array', typeAnnotation.elementType, @@ -111,6 +177,7 @@ function translateTypeAnnotation( hasteModuleName, types, aliasMap, + enumMap, cxxOnly, 'ReadonlyArray', typeAnnotation.typeAnnotation.elementType, @@ -139,6 +206,7 @@ function translateTypeAnnotation( nullable, types, aliasMap, + enumMap, tryParse, cxxOnly, translateTypeAnnotation, @@ -152,6 +220,7 @@ function translateTypeAnnotation( parser, types, aliasMap, + enumMap, cxxOnly, nullable, translateTypeAnnotation, @@ -171,7 +240,7 @@ function translateTypeAnnotation( } case 'UnsafeObject': case 'Object': { - return emitObject(nullable); + return emitGenericObject(nullable); } case 'Partial': { if (typeAnnotation.typeParameters.params.length !== 1) { @@ -199,6 +268,7 @@ function translateTypeAnnotation( member.typeAnnotation.typeAnnotation, types, aliasMap, + enumMap, tryParse, cxxOnly, parser, @@ -207,52 +277,68 @@ function translateTypeAnnotation( }, ); - return emitPartial(nullable, properties); + return emitObject(nullable, properties); } default: { - return translateDefault( + throw new UnsupportedGenericParserError( hasteModuleName, typeAnnotation, - types, - nullable, parser, ); } } } case 'TSInterfaceDeclaration': { - const objectTypeAnnotation = { - type: 'ObjectTypeAnnotation', - // $FlowFixMe[missing-type-arg] - properties: (flattenProperties( - [typeAnnotation], + const baseTypes = (typeAnnotation.extends ?? []).map( + extend => extend.expression.name, + ); + for (const baseType of baseTypes) { + // ensure base types exist and appear in aliasMap + translateTypeAnnotation( + hasteModuleName, + { + type: 'TSTypeReference', + typeName: {type: 'Identifier', name: baseType}, + }, types, - ): $ReadOnlyArray<$FlowFixMe>) - .map>>( - property => { - return tryParse(() => { - return parseObjectProperty( - property, - hasteModuleName, - types, - aliasMap, - tryParse, - cxxOnly, - nullable, - translateTypeAnnotation, - parser, - ); - }); - }, - ) - .filter(Boolean), - }; + aliasMap, + enumMap, + tryParse, + cxxOnly, + parser, + ); + } - return typeAliasResolution( - typeAliasResolutionStatus, - objectTypeAnnotation, + return translateObjectTypeAnnotation( + hasteModuleName, + nullable, + flattenProperties([typeAnnotation], types), + typeResolutionStatus, + baseTypes, + types, aliasMap, + enumMap, + tryParse, + cxxOnly, + parser, + ); + } + case 'TSIntersectionType': { + return translateObjectTypeAnnotation( + hasteModuleName, nullable, + flattenProperties( + flattenIntersectionType(typeAnnotation, types), + types, + ), + typeResolutionStatus, + [], + types, + aliasMap, + enumMap, + tryParse, + cxxOnly, + parser, ); } case 'TSTypeLiteral': { @@ -270,44 +356,39 @@ function translateTypeAnnotation( propertyType, types, aliasMap, + enumMap, tryParse, cxxOnly, parser, ); // no need to do further checking - return emitObject(nullable); + return emitGenericObject(nullable); } } - const objectTypeAnnotation = { - type: 'ObjectTypeAnnotation', - // $FlowFixMe[missing-type-arg] - properties: (typeAnnotation.members: Array<$FlowFixMe>) - .map>>( - property => { - return tryParse(() => { - return parseObjectProperty( - property, - hasteModuleName, - types, - aliasMap, - tryParse, - cxxOnly, - nullable, - translateTypeAnnotation, - parser, - ); - }); - }, - ) - .filter(Boolean), - }; - - return typeAliasResolution( - typeAliasResolutionStatus, - objectTypeAnnotation, + return translateObjectTypeAnnotation( + hasteModuleName, + nullable, + typeAnnotation.members, + typeResolutionStatus, + [], + types, aliasMap, + enumMap, + tryParse, + cxxOnly, + parser, + ); + } + case 'TSEnumDeclaration': { + return typeEnumResolution( + typeAnnotation, + typeResolutionStatus, nullable, + hasteModuleName, + language, + enumMap, + parser, ); } case 'TSBooleanKeyword': { @@ -329,6 +410,7 @@ function translateTypeAnnotation( typeAnnotation, types, aliasMap, + enumMap, tryParse, cxxOnly, translateTypeAnnotation, @@ -477,17 +559,21 @@ function buildModuleSchema( ) .map(property => { const aliasMap: {...NativeModuleAliasMap} = {}; + const enumMap: {...NativeModuleEnumMap} = {}; return tryParse(() => ({ aliasMap: aliasMap, + enumMap: enumMap, propertyShape: buildPropertySchema( hasteModuleName, property, types, aliasMap, + enumMap, tryParse, cxxOnly, resolveTypeAnnotation, @@ -498,10 +584,14 @@ function buildModuleSchema( }) .filter(Boolean) .reduce( - (moduleSchema: NativeModuleSchema, {aliasMap, propertyShape}) => { + ( + moduleSchema: NativeModuleSchema, + {aliasMap, enumMap, propertyShape}, + ) => { return { type: 'NativeModule', - aliases: {...moduleSchema.aliases, ...aliasMap}, + aliasMap: {...moduleSchema.aliasMap, ...aliasMap}, + enumMap: {...moduleSchema.enumMap, ...enumMap}, spec: { properties: [...moduleSchema.spec.properties, propertyShape], }, @@ -511,7 +601,8 @@ function buildModuleSchema( }, { type: 'NativeModule', - aliases: {}, + aliasMap: {}, + enumMap: {}, spec: {properties: []}, moduleName: moduleName, excludedPlatforms: diff --git a/packages/react-native-codegen/src/parsers/typescript/parser.js b/packages/react-native-codegen/src/parsers/typescript/parser.js index 40b4af14d8ed95..9b40a7da55b70a 100644 --- a/packages/react-native-codegen/src/parsers/typescript/parser.js +++ b/packages/react-native-codegen/src/parsers/typescript/parser.js @@ -16,6 +16,8 @@ import type { NamedShape, Nullable, NativeModuleParamTypeAnnotation, + NativeModuleEnumMembers, + NativeModuleEnumMemberType, } from '../../CodegenSchema'; import type {ParserType} from '../errors'; import type {Parser} from '../parser'; @@ -54,20 +56,6 @@ class TypeScriptParser implements Parser { return property.key.name; } - getMaybeEnumMemberType(maybeEnumDeclaration: $FlowFixMe): string { - if (maybeEnumDeclaration.members[0].initializer) { - return maybeEnumDeclaration.members[0].initializer.type - .replace('NumericLiteral', 'NumberTypeAnnotation') - .replace('StringLiteral', 'StringTypeAnnotation'); - } - - return 'StringTypeAnnotation'; - } - - isEnumDeclaration(maybeEnumDeclaration: $FlowFixMe): boolean { - return maybeEnumDeclaration.type === 'TSEnumDeclaration'; - } - language(): ParserType { return 'TypeScript'; } @@ -155,6 +143,55 @@ class TypeScriptParser implements Parser { ): $FlowFixMe { return functionTypeAnnotation.typeAnnotation.typeAnnotation; } + + parseEnumMembersType(typeAnnotation: $FlowFixMe): NativeModuleEnumMemberType { + const enumInitializer = typeAnnotation.members[0]?.initializer; + const enumMembersType: ?NativeModuleEnumMemberType = + !enumInitializer || enumInitializer.type === 'StringLiteral' + ? 'StringTypeAnnotation' + : enumInitializer.type === 'NumericLiteral' + ? 'NumberTypeAnnotation' + : null; + if (!enumMembersType) { + throw new Error( + 'Enum values must be either blank, number, or string values.', + ); + } + return enumMembersType; + } + + validateEnumMembersSupported( + typeAnnotation: $FlowFixMe, + enumMembersType: NativeModuleEnumMemberType, + ): void { + if (!typeAnnotation.members || typeAnnotation.members.length === 0) { + throw new Error('Enums should have at least one member.'); + } + + const enumInitializerType = + enumMembersType === 'StringTypeAnnotation' + ? 'StringLiteral' + : enumMembersType === 'NumberTypeAnnotation' + ? 'NumericLiteral' + : null; + + typeAnnotation.members.forEach(member => { + if ( + (member.initializer?.type ?? 'StringLiteral') !== enumInitializerType + ) { + throw new Error( + 'Enum values can not be mixed. They all must be either blank, number, or string values.', + ); + } + }); + } + + parseEnumMembers(typeAnnotation: $FlowFixMe): NativeModuleEnumMembers { + return typeAnnotation.members.map(member => ({ + name: member.id.name, + value: member.initializer?.value ?? member.id.name, + })); + } } module.exports = { TypeScriptParser, diff --git a/packages/react-native-codegen/src/parsers/typescript/utils.js b/packages/react-native-codegen/src/parsers/typescript/utils.js index 725b74968ae6cc..ae72b030f640c7 100644 --- a/packages/react-native-codegen/src/parsers/typescript/utils.js +++ b/packages/react-native-codegen/src/parsers/typescript/utils.js @@ -10,7 +10,7 @@ 'use strict'; -import type {TypeAliasResolutionStatus, TypeDeclarationMap} from '../utils'; +import type {TypeResolutionStatus, TypeDeclarationMap} from '../utils'; const {parseTopLevelType} = require('./parseTopLevelType'); @@ -56,7 +56,7 @@ function resolveTypeAnnotation( ): { nullable: boolean, typeAnnotation: $FlowFixMe, - typeAliasResolutionStatus: TypeAliasResolutionStatus, + typeResolutionStatus: TypeResolutionStatus, } { invariant( typeAnnotation != null, @@ -68,7 +68,7 @@ function resolveTypeAnnotation( ? typeAnnotation.typeAnnotation : typeAnnotation; let nullable = false; - let typeAliasResolutionStatus: TypeAliasResolutionStatus = { + let typeResolutionStatus: TypeResolutionStatus = { successful: false, }; @@ -77,40 +77,55 @@ function resolveTypeAnnotation( nullable = nullable || topLevelType.optional; node = topLevelType.type; - if (node.type === 'TSTypeReference') { - typeAliasResolutionStatus = { - successful: true, - aliasName: node.typeName.name, - }; - const resolvedTypeAnnotation = types[node.typeName.name]; - if ( - resolvedTypeAnnotation == null || - resolvedTypeAnnotation.type === 'TSEnumDeclaration' - ) { + if (node.type !== 'TSTypeReference') { + break; + } + + const resolvedTypeAnnotation = types[node.typeName.name]; + if (resolvedTypeAnnotation == null) { + break; + } + + switch (resolvedTypeAnnotation.type) { + case 'TSTypeAliasDeclaration': { + typeResolutionStatus = { + successful: true, + type: 'alias', + name: node.typeName.name, + }; + node = resolvedTypeAnnotation.typeAnnotation; break; } - - switch (resolvedTypeAnnotation.type) { - case 'TSTypeAliasDeclaration': - node = resolvedTypeAnnotation.typeAnnotation; - break; - case 'TSInterfaceDeclaration': - node = resolvedTypeAnnotation; - break; - default: - throw new Error( - `GenericTypeAnnotation '${node.typeName.name}' must resolve to a TSTypeAliasDeclaration or a TSInterfaceDeclaration. Instead, it resolved to a '${resolvedTypeAnnotation.type}'`, - ); + case 'TSInterfaceDeclaration': { + typeResolutionStatus = { + successful: true, + type: 'alias', + name: node.typeName.name, + }; + node = resolvedTypeAnnotation; + break; + } + case 'TSEnumDeclaration': { + typeResolutionStatus = { + successful: true, + type: 'enum', + name: node.typeName.name, + }; + node = resolvedTypeAnnotation; + break; + } + default: { + throw new TypeError( + `A non GenericTypeAnnotation must be a type declaration ('TSTypeAliasDeclaration'), an interface ('TSInterfaceDeclaration'), or enum ('TSEnumDeclaration'). Instead, got the unsupported ${resolvedTypeAnnotation.type}.`, + ); } - } else { - break; } } return { nullable: nullable, typeAnnotation: node, - typeAliasResolutionStatus, + typeResolutionStatus, }; } diff --git a/packages/react-native-codegen/src/parsers/utils.js b/packages/react-native-codegen/src/parsers/utils.js index f3ad6483e06eaa..299bddef91d143 100644 --- a/packages/react-native-codegen/src/parsers/utils.js +++ b/packages/react-native-codegen/src/parsers/utils.js @@ -16,10 +16,11 @@ const path = require('path'); export type TypeDeclarationMap = {[declarationName: string]: $FlowFixMe}; -export type TypeAliasResolutionStatus = +export type TypeResolutionStatus = | $ReadOnly<{ + type: 'alias' | 'enum', successful: true, - aliasName: string, + name: string, }> | $ReadOnly<{ successful: false, diff --git a/packages/react-native-gradle-plugin/build.gradle.kts b/packages/react-native-gradle-plugin/build.gradle.kts index 5ea92ee71b41c8..8a54bdaaa9e6a2 100644 --- a/packages/react-native-gradle-plugin/build.gradle.kts +++ b/packages/react-native-gradle-plugin/build.gradle.kts @@ -33,7 +33,7 @@ group = "com.facebook.react" dependencies { implementation(gradleApi()) - implementation("com.android.tools.build:gradle:7.3.1") + implementation("com.android.tools.build:gradle:7.4.1") implementation("com.google.code.gson:gson:2.8.9") implementation("com.google.guava:guava:31.0.1-jre") implementation("com.squareup:javapoet:1.13.0") diff --git a/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/ReactExtension.kt b/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/ReactExtension.kt index d805dabe31c9c7..47e24225bd4aec 100644 --- a/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/ReactExtension.kt +++ b/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/ReactExtension.kt @@ -129,9 +129,9 @@ abstract class ReactExtension @Inject constructor(project: Project) { /** * The root directory for all JS files for the app. * - * Default: [root] (i.e. ${rootProject.dir}/../) + * Default: the parent folder of the `/android` folder. */ - val jsRootDir: DirectoryProperty = objects.directoryProperty().convention(root.get()) + val jsRootDir: DirectoryProperty = objects.directoryProperty() /** * The library name that will be used for the codegen artifacts. diff --git a/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/ReactPlugin.kt b/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/ReactPlugin.kt index 8fd0a54dbd3932..8aa1c5bbdb0d9a 100644 --- a/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/ReactPlugin.kt +++ b/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/ReactPlugin.kt @@ -8,7 +8,6 @@ package com.facebook.react import com.android.build.api.variant.AndroidComponentsExtension -import com.android.build.gradle.AppExtension import com.android.build.gradle.internal.tasks.factory.dependsOn import com.facebook.react.tasks.BuildCodegenCLITask import com.facebook.react.tasks.GenerateCodegenArtifactsTask @@ -55,24 +54,6 @@ class ReactPlugin : Plugin { project.configureReactTasks(variant = variant, config = extension) } } - - // This is a legacy AGP api. Needed as AGP 7.3 is not consuming generated resources correctly. - // Can be removed as we bump to AGP 7.4 stable. - // This registers the $buildDir/generated/res/react/ folder as a - // res folder to be consumed with the old AGP Apis which are not broken. - project.extensions.getByType(AppExtension::class.java).apply { - this.applicationVariants.all { variant -> - val isDebuggableVariant = - extension.debuggableVariants.get().any { it.equals(variant.name, ignoreCase = true) } - val targetName = variant.name.replaceFirstChar { it.uppercase() } - val bundleTaskName = "createBundle${targetName}JsAndAssets" - if (!isDebuggableVariant) { - variant.registerGeneratedResFolders( - project.layout.buildDirectory.files("generated/res/react/${variant.name}")) - variant.mergeResourcesProvider.get().dependsOn(bundleTaskName) - } - } - } configureCodegen(project, extension, isLibrary = false) } @@ -110,6 +91,15 @@ class ReactPlugin : Plugin { // First, we set up the output dir for the codegen. val generatedSrcDir = File(project.buildDir, "generated/source/codegen") + // We specify the default value (convention) for jsRootDir. + // It's the root folder for apps (so ../../ from the Gradle project) + // and the package folder for library (so ../ from the Gradle project) + if (isLibrary) { + extension.jsRootDir.convention(project.layout.projectDirectory.dir("../")) + } else { + extension.jsRootDir.convention(extension.root) + } + val buildCodegenTask = project.tasks.register("buildCodegenCLI", BuildCodegenCLITask::class.java) { it.codegenDir.set(extension.codegenDir) diff --git a/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/TaskConfiguration.kt b/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/TaskConfiguration.kt index 30bad252fd823b..24ba33b297c692 100644 --- a/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/TaskConfiguration.kt +++ b/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/TaskConfiguration.kt @@ -72,9 +72,7 @@ internal fun Project.configureReactTasks(variant: Variant, config: ReactExtensio it.hermesFlags.set(config.hermesFlags) it.reactNativeDir.set(config.reactNativeDir) } - // Currently broken inside AGP 7.3 We need to wait for a release of AGP 7.4 in order to use - // the addGeneratedSourceDirectory API. - // variant.sources.res?.addGeneratedSourceDirectory(bundleTask, BundleHermesCTask::resourcesDir) + variant.sources.res?.addGeneratedSourceDirectory(bundleTask, BundleHermesCTask::resourcesDir) variant.sources.assets?.addGeneratedSourceDirectory(bundleTask, BundleHermesCTask::jsBundleDir) } } diff --git a/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/tasks/BundleHermesCTask.kt b/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/tasks/BundleHermesCTask.kt index 2801d3aea63413..2eb989143b80a2 100644 --- a/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/tasks/BundleHermesCTask.kt +++ b/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/tasks/BundleHermesCTask.kt @@ -7,6 +7,7 @@ package com.facebook.react.tasks +import com.facebook.react.utils.Os.cliPath import com.facebook.react.utils.detectOSAwareHermesCommand import com.facebook.react.utils.moveTo import com.facebook.react.utils.windowsAwareCommandLine @@ -135,8 +136,9 @@ abstract class BundleHermesCTask : DefaultTask() { internal fun getBundleCommand(bundleFile: File, sourceMapFile: File): List = windowsAwareCommandLine( buildList { + val rootFile = root.get().asFile addAll(nodeExecutableAndArgs.get()) - add(cliFile.get().asFile.absolutePath) + add(cliFile.get().asFile.cliPath(rootFile)) add(bundleCommand.get()) add("--platform") add("android") @@ -144,16 +146,16 @@ abstract class BundleHermesCTask : DefaultTask() { add(devEnabled.get().toString()) add("--reset-cache") add("--entry-file") - add(entryFile.get().asFile.toString()) + add(entryFile.get().asFile.cliPath(rootFile)) add("--bundle-output") - add(bundleFile.toString()) + add(bundleFile.cliPath(rootFile)) add("--assets-dest") - add(resourcesDir.get().asFile.toString()) + add(resourcesDir.get().asFile.cliPath(rootFile)) add("--sourcemap-output") - add(sourceMapFile.toString()) + add(sourceMapFile.cliPath(rootFile)) if (bundleConfig.isPresent) { add("--config") - add(bundleConfig.get().asFile.absolutePath) + add(bundleConfig.get().asFile.cliPath(rootFile)) } add("--minify") add(minifyEnabled.get().toString()) @@ -165,26 +167,30 @@ abstract class BundleHermesCTask : DefaultTask() { hermesCommand: String, bytecodeFile: File, bundleFile: File - ): List = - windowsAwareCommandLine( - hermesCommand, - "-emit-binary", - "-out", - bytecodeFile.absolutePath, - bundleFile.absolutePath, - *hermesFlags.get().toTypedArray()) + ): List { + val rootFile = root.get().asFile + return windowsAwareCommandLine( + hermesCommand, + "-emit-binary", + "-out", + bytecodeFile.cliPath(rootFile), + bundleFile.cliPath(rootFile), + *hermesFlags.get().toTypedArray()) + } internal fun getComposeSourceMapsCommand( composeScript: File, packagerSourceMap: File, compilerSourceMap: File, outputSourceMap: File - ): List = - windowsAwareCommandLine( - *nodeExecutableAndArgs.get().toTypedArray(), - composeScript.absolutePath, - packagerSourceMap.toString(), - compilerSourceMap.toString(), - "-o", - outputSourceMap.toString()) + ): List { + val rootFile = root.get().asFile + return windowsAwareCommandLine( + *nodeExecutableAndArgs.get().toTypedArray(), + composeScript.cliPath(rootFile), + packagerSourceMap.cliPath(rootFile), + compilerSourceMap.cliPath(rootFile), + "-o", + outputSourceMap.cliPath(rootFile)) + } } diff --git a/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/tasks/GenerateCodegenArtifactsTask.kt b/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/tasks/GenerateCodegenArtifactsTask.kt index b6003eeb5e14e6..30f92ff7d4749d 100644 --- a/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/tasks/GenerateCodegenArtifactsTask.kt +++ b/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/tasks/GenerateCodegenArtifactsTask.kt @@ -8,6 +8,7 @@ package com.facebook.react.tasks import com.facebook.react.utils.JsonUtils +import com.facebook.react.utils.Os.cliPath import com.facebook.react.utils.windowsAwareCommandLine import org.gradle.api.file.Directory import org.gradle.api.file.DirectoryProperty @@ -63,16 +64,17 @@ abstract class GenerateCodegenArtifactsTask : Exec() { } internal fun setupCommandLine(libraryName: String, codegenJavaPackageName: String) { + val workingDir = project.projectDir commandLine( windowsAwareCommandLine( *nodeExecutableAndArgs.get().toTypedArray(), - reactNativeDir.file("scripts/generate-specs-cli.js").get().asFile.absolutePath, + reactNativeDir.file("scripts/generate-specs-cli.js").get().asFile.cliPath(workingDir), "--platform", "android", "--schemaPath", - generatedSchemaFile.get().asFile.absolutePath, + generatedSchemaFile.get().asFile.cliPath(workingDir), "--outputDir", - generatedSrcDir.get().asFile.absolutePath, + generatedSrcDir.get().asFile.cliPath(workingDir), "--libraryName", libraryName, "--javaPackageName", diff --git a/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/tasks/GenerateCodegenSchemaTask.kt b/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/tasks/GenerateCodegenSchemaTask.kt index d72bc0a379f214..3f724eb5ff222d 100644 --- a/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/tasks/GenerateCodegenSchemaTask.kt +++ b/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/tasks/GenerateCodegenSchemaTask.kt @@ -7,6 +7,7 @@ package com.facebook.react.tasks +import com.facebook.react.utils.Os.cliPath import com.facebook.react.utils.windowsAwareCommandLine import org.gradle.api.file.DirectoryProperty import org.gradle.api.file.RegularFile @@ -63,6 +64,7 @@ abstract class GenerateCodegenSchemaTask : Exec() { } internal fun setupCommandLine() { + val workingDir = project.projectDir commandLine( windowsAwareCommandLine( *nodeExecutableAndArgs.get().toTypedArray(), @@ -70,11 +72,11 @@ abstract class GenerateCodegenSchemaTask : Exec() { .file("lib/cli/combine/combine-js-to-schema-cli.js") .get() .asFile - .absolutePath, + .cliPath(workingDir), "--platform", "android", - generatedSchemaFile.get().asFile.absolutePath, - jsRootDir.asFile.get().absolutePath, + generatedSchemaFile.get().asFile.cliPath(workingDir), + jsRootDir.asFile.get().cliPath(workingDir), )) } } diff --git a/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/Os.kt b/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/Os.kt index c4dfad637fc531..4ca00699b84170 100644 --- a/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/Os.kt +++ b/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/Os.kt @@ -7,7 +7,9 @@ package com.facebook.react.utils -object Os { +import java.io.File + +internal object Os { fun isWindows(): Boolean = System.getProperty("os.name")?.lowercase()?.contains("windows") ?: false @@ -28,4 +30,15 @@ object Os { it } } + + /** + * As Gradle doesn't support well path with spaces on Windows, we need to return relative path on + * Win. On Linux & Mac we'll default to return absolute path. + */ + fun File.cliPath(base: File): String = + if (isWindows()) { + this.relativeTo(base).path + } else { + this.absolutePath + } } diff --git a/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/PathUtils.kt b/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/PathUtils.kt index 552a611d5225c0..0710f04b994e07 100644 --- a/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/PathUtils.kt +++ b/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/PathUtils.kt @@ -11,6 +11,7 @@ package com.facebook.react.utils import com.facebook.react.ReactExtension import com.facebook.react.model.ModelPackageJson +import com.facebook.react.utils.Os.cliPath import java.io.File import org.gradle.api.Project @@ -130,7 +131,7 @@ internal fun detectOSAwareHermesCommand(projectRoot: File, hermesCommand: String val builtHermesc = getBuiltHermescFile(projectRoot, System.getenv("REACT_NATIVE_OVERRIDE_HERMES_DIR")) if (builtHermesc.exists()) { - return builtHermesc.absolutePath + return builtHermesc.cliPath(projectRoot) } // 3. If the react-native contains a pre-built hermesc, use it. @@ -142,7 +143,7 @@ internal fun detectOSAwareHermesCommand(projectRoot: File, hermesCommand: String val prebuiltHermes = File(projectRoot, prebuiltHermesPath) if (prebuiltHermes.exists()) { - return prebuiltHermes.absolutePath + return prebuiltHermes.cliPath(projectRoot) } error( diff --git a/packages/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/tasks/BundleHermesCTaskTest.kt b/packages/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/tasks/BundleHermesCTaskTest.kt index fbe7fed6304946..3e07a78b36e1b4 100644 --- a/packages/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/tasks/BundleHermesCTaskTest.kt +++ b/packages/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/tasks/BundleHermesCTaskTest.kt @@ -7,7 +7,9 @@ package com.facebook.react.tasks +import com.facebook.react.tests.OS import com.facebook.react.tests.OsRule +import com.facebook.react.tests.WithOs import com.facebook.react.tests.createTestTask import java.io.File import org.junit.Assert.* @@ -205,6 +207,7 @@ class BundleHermesCTaskTest { val task = createTestTask { it.nodeExecutableAndArgs.set(listOf("node", "arg1", "arg2")) + it.root.set(tempFolder.root) it.cliFile.set(cliFile) it.bundleCommand.set("bundle") it.devEnabled.set(true) @@ -244,6 +247,60 @@ class BundleHermesCTaskTest { assertEquals(24, bundleCommand.size) } + @Test + @WithOs(OS.WIN) + fun getBundleCommand_onWindows_returnsWinValidCommandsPaths() { + val entryFile = tempFolder.newFile("index.js") + val cliFile = tempFolder.newFile("cli.js") + val bundleFile = tempFolder.newFile("bundle.js") + val sourceMapFile = tempFolder.newFile("bundle.js.map") + val resourcesDir = tempFolder.newFolder("res") + val bundleConfig = tempFolder.newFile("bundle.config") + val task = + createTestTask { + it.nodeExecutableAndArgs.set(listOf("node", "arg1", "arg2")) + it.root.set(tempFolder.root) + it.cliFile.set(cliFile) + it.bundleCommand.set("bundle") + it.devEnabled.set(true) + it.entryFile.set(entryFile) + it.resourcesDir.set(resourcesDir) + it.bundleConfig.set(bundleConfig) + it.minifyEnabled.set(true) + it.extraPackagerArgs.set(listOf("--read-global-cache")) + } + + val bundleCommand = task.getBundleCommand(bundleFile, sourceMapFile) + + assertEquals("cmd", bundleCommand[0]) + assertEquals("/c", bundleCommand[1]) + assertEquals("node", bundleCommand[2]) + assertEquals("arg1", bundleCommand[3]) + assertEquals("arg2", bundleCommand[4]) + assertEquals(cliFile.relativeTo(tempFolder.root).path, bundleCommand[5]) + assertEquals("bundle", bundleCommand[6]) + assertEquals("--platform", bundleCommand[7]) + assertEquals("android", bundleCommand[8]) + assertEquals("--dev", bundleCommand[9]) + assertEquals("true", bundleCommand[10]) + assertEquals("--reset-cache", bundleCommand[11]) + assertEquals("--entry-file", bundleCommand[12]) + assertEquals(entryFile.relativeTo(tempFolder.root).path, bundleCommand[13]) + assertEquals("--bundle-output", bundleCommand[14]) + assertEquals(bundleFile.relativeTo(tempFolder.root).path, bundleCommand[15]) + assertEquals("--assets-dest", bundleCommand[16]) + assertEquals(resourcesDir.relativeTo(tempFolder.root).path, bundleCommand[17]) + assertEquals("--sourcemap-output", bundleCommand[18]) + assertEquals(sourceMapFile.relativeTo(tempFolder.root).path, bundleCommand[19]) + assertEquals("--config", bundleCommand[20]) + assertEquals(bundleConfig.relativeTo(tempFolder.root).path, bundleCommand[21]) + assertEquals("--minify", bundleCommand[22]) + assertEquals("true", bundleCommand[23]) + assertEquals("--read-global-cache", bundleCommand[24]) + assertEquals("--verbose", bundleCommand[25]) + assertEquals(26, bundleCommand.size) + } + @Test fun getBundleCommand_withoutConfig_returnsCommandWithoutConfig() { val entryFile = tempFolder.newFile("index.js") @@ -254,6 +311,7 @@ class BundleHermesCTaskTest { val task = createTestTask { it.nodeExecutableAndArgs.set(listOf("node", "arg1", "arg2")) + it.root.set(tempFolder.root) it.cliFile.set(cliFile) it.bundleCommand.set("bundle") it.devEnabled.set(true) @@ -274,7 +332,10 @@ class BundleHermesCTaskTest { val bytecodeFile = tempFolder.newFile("bundle.js.hbc") val bundleFile = tempFolder.newFile("bundle.js") val task = - createTestTask { it.hermesFlags.set(listOf("my-custom-hermes-flag")) } + createTestTask { + it.root.set(tempFolder.root) + it.hermesFlags.set(listOf("my-custom-hermes-flag")) + } val hermesCommand = task.getHermescCommand(customHermesc, bytecodeFile, bundleFile) @@ -287,6 +348,31 @@ class BundleHermesCTaskTest { assertEquals(6, hermesCommand.size) } + @Test + @WithOs(OS.WIN) + fun getHermescCommand_onWindows_returnsRelativePaths() { + val customHermesc = "hermesc" + val bytecodeFile = tempFolder.newFile("bundle.js.hbc") + val bundleFile = tempFolder.newFile("bundle.js") + val task = + createTestTask { + it.root.set(tempFolder.root) + it.hermesFlags.set(listOf("my-custom-hermes-flag")) + } + + val hermesCommand = task.getHermescCommand(customHermesc, bytecodeFile, bundleFile) + + assertEquals("cmd", hermesCommand[0]) + assertEquals("/c", hermesCommand[1]) + assertEquals(customHermesc, hermesCommand[2]) + assertEquals("-emit-binary", hermesCommand[3]) + assertEquals("-out", hermesCommand[4]) + assertEquals(bytecodeFile.relativeTo(tempFolder.root).path, hermesCommand[5]) + assertEquals(bundleFile.relativeTo(tempFolder.root).path, hermesCommand[6]) + assertEquals("my-custom-hermes-flag", hermesCommand[7]) + assertEquals(8, hermesCommand.size) + } + @Test fun getComposeSourceMapsCommand_returnsCorrectCommand() { val packagerMap = tempFolder.newFile("bundle.js.packager.map") @@ -296,6 +382,7 @@ class BundleHermesCTaskTest { val composeSourceMapsFile = File(reactNativeDir, "scripts/compose-source-maps.js") val task = createTestTask { + it.root.set(tempFolder.root) it.nodeExecutableAndArgs.set(listOf("node", "arg1", "arg2")) } @@ -312,4 +399,34 @@ class BundleHermesCTaskTest { assertEquals(outputMap.absolutePath, composeSourcemapCommand[7]) assertEquals(8, composeSourcemapCommand.size) } + + @Test + @WithOs(OS.WIN) + fun getComposeSourceMapsCommand_onWindows_returnsRelativePaths() { + val packagerMap = tempFolder.newFile("bundle.js.packager.map") + val compilerMap = tempFolder.newFile("bundle.js.compiler.map") + val outputMap = tempFolder.newFile("bundle.js.map") + val reactNativeDir = tempFolder.newFolder("node_modules/react-native") + val composeSourceMapsFile = File(reactNativeDir, "scripts/compose-source-maps.js") + val task = + createTestTask { + it.root.set(tempFolder.root) + it.nodeExecutableAndArgs.set(listOf("node", "arg1", "arg2")) + } + + val composeSourcemapCommand = + task.getComposeSourceMapsCommand(composeSourceMapsFile, packagerMap, compilerMap, outputMap) + + assertEquals("cmd", composeSourcemapCommand[0]) + assertEquals("/c", composeSourcemapCommand[1]) + assertEquals("node", composeSourcemapCommand[2]) + assertEquals("arg1", composeSourcemapCommand[3]) + assertEquals("arg2", composeSourcemapCommand[4]) + assertEquals(composeSourceMapsFile.relativeTo(tempFolder.root).path, composeSourcemapCommand[5]) + assertEquals(packagerMap.relativeTo(tempFolder.root).path, composeSourcemapCommand[6]) + assertEquals(compilerMap.relativeTo(tempFolder.root).path, composeSourcemapCommand[7]) + assertEquals("-o", composeSourcemapCommand[8]) + assertEquals(outputMap.relativeTo(tempFolder.root).path, composeSourcemapCommand[9]) + assertEquals(10, composeSourcemapCommand.size) + } } diff --git a/packages/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/tasks/GenerateCodegenArtifactsTaskTest.kt b/packages/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/tasks/GenerateCodegenArtifactsTaskTest.kt index e188e47c849525..e2bf1ad7b9b4a7 100644 --- a/packages/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/tasks/GenerateCodegenArtifactsTaskTest.kt +++ b/packages/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/tasks/GenerateCodegenArtifactsTaskTest.kt @@ -7,9 +7,8 @@ package com.facebook.react.tasks -import com.facebook.react.tests.OS -import com.facebook.react.tests.OsRule -import com.facebook.react.tests.WithOs +import com.facebook.react.tests.* +import com.facebook.react.tests.createProject import com.facebook.react.tests.createTestTask import java.io.File import org.junit.Assert.assertEquals @@ -97,6 +96,44 @@ class GenerateCodegenArtifactsTaskTest { task.commandLine.toMutableList()) } + @Test + @WithOs(OS.WIN) + fun setupCommandLine_onWindows_willSetupCorrectly() { + val reactNativeDir = tempFolder.newFolder("node_modules/react-native/") + val outputDir = tempFolder.newFolder("output") + + val project = createProject() + val task = + createTestTask(project) { + it.reactNativeDir.set(reactNativeDir) + it.generatedSrcDir.set(outputDir) + it.nodeExecutableAndArgs.set(listOf("--verbose")) + } + + task.setupCommandLine("example-test", "com.example.test") + + assertEquals( + listOf( + "cmd", + "/c", + "--verbose", + File(reactNativeDir, "scripts/generate-specs-cli.js") + .relativeTo(project.projectDir) + .path, + "--platform", + "android", + "--schemaPath", + File(outputDir, "schema.json").relativeTo(project.projectDir).path, + "--outputDir", + outputDir.relativeTo(project.projectDir).path, + "--libraryName", + "example-test", + "--javaPackageName", + "com.example.test", + ), + task.commandLine.toMutableList()) + } + @Test fun resolveTaskParameters_withConfigInPackageJson_usesIt() { val packageJsonFile = diff --git a/packages/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/tasks/GenerateCodegenSchemaTaskTest.kt b/packages/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/tasks/GenerateCodegenSchemaTaskTest.kt index 98e2b39795c1cb..abe77f0dd15527 100644 --- a/packages/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/tasks/GenerateCodegenSchemaTaskTest.kt +++ b/packages/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/tasks/GenerateCodegenSchemaTaskTest.kt @@ -7,9 +7,8 @@ package com.facebook.react.tasks -import com.facebook.react.tests.OS -import com.facebook.react.tests.OsRule -import com.facebook.react.tests.WithOs +import com.facebook.react.tests.* +import com.facebook.react.tests.createProject import com.facebook.react.tests.createTestTask import java.io.File import org.junit.Assert.* @@ -140,13 +139,14 @@ class GenerateCodegenSchemaTaskTest { it.codegenDir.set(codegenDir) it.jsRootDir.set(jsRootDir) it.generatedSrcDir.set(outputDir) - it.nodeExecutableAndArgs.set(listOf("--verbose")) + it.nodeExecutableAndArgs.set(listOf("node", "--verbose")) } task.setupCommandLine() assertEquals( listOf( + "node", "--verbose", File(codegenDir, "lib/cli/combine/combine-js-to-schema-cli.js").toString(), "--platform", @@ -156,4 +156,39 @@ class GenerateCodegenSchemaTaskTest { ), task.commandLine.toMutableList()) } + + @Test + @WithOs(OS.WIN) + fun setupCommandLine_onWindows_willSetupCorrectly() { + val codegenDir = tempFolder.newFolder("codegen") + val jsRootDir = tempFolder.newFolder("js") + val outputDir = tempFolder.newFolder("output") + + val project = createProject() + val task = + createTestTask(project) { + it.codegenDir.set(codegenDir) + it.jsRootDir.set(jsRootDir) + it.generatedSrcDir.set(outputDir) + it.nodeExecutableAndArgs.set(listOf("node", "--verbose")) + } + + task.setupCommandLine() + + assertEquals( + listOf( + "cmd", + "/c", + "node", + "--verbose", + File(codegenDir, "lib/cli/combine/combine-js-to-schema-cli.js") + .relativeTo(project.projectDir) + .path, + "--platform", + "android", + File(outputDir, "schema.json").relativeTo(project.projectDir).path, + jsRootDir.relativeTo(project.projectDir).path, + ), + task.commandLine.toMutableList()) + } } diff --git a/packages/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/utils/OsTest.kt b/packages/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/utils/OsTest.kt index fd37f2474f77e3..b58a2e067f8dc5 100644 --- a/packages/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/utils/OsTest.kt +++ b/packages/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/utils/OsTest.kt @@ -10,14 +10,17 @@ package com.facebook.react.utils import com.facebook.react.tests.OS import com.facebook.react.tests.OsRule import com.facebook.react.tests.WithOs +import com.facebook.react.utils.Os.cliPath import com.facebook.react.utils.Os.unixifyPath import org.junit.Assert.* import org.junit.Rule import org.junit.Test +import org.junit.rules.TemporaryFolder class OsTest { @get:Rule val osRule = OsRule() + @get:Rule val tempFolder = TemporaryFolder() @Test @WithOs(OS.LINUX, "amd64") @@ -56,4 +59,28 @@ class OsTest { assertEquals("/D/just/a/windows/path/", aWindowsPath.unixifyPath()) } + + @Test + @WithOs(OS.WIN) + fun cliPath_onWindows_returnsRelativePath() { + val tempFile = tempFolder.newFile("test.txt").apply { createNewFile() } + + assertEquals(tempFile.relativeTo(tempFolder.root).path, tempFile.cliPath(tempFolder.root)) + } + + @Test + @WithOs(OS.LINUX) + fun cliPath_onLinux_returnsAbsolutePath() { + val tempFile = tempFolder.newFile("test.txt").apply { createNewFile() } + + assertEquals(tempFile.absolutePath, tempFile.cliPath(tempFolder.root)) + } + + @Test + @WithOs(OS.MAC) + fun cliPath_onMac_returnsAbsolutePath() { + val tempFile = tempFolder.newFile("test.txt").apply { createNewFile() } + + assertEquals(tempFile.absolutePath, tempFile.cliPath(tempFolder.root)) + } } diff --git a/packages/rn-tester/RCTTest/FBSnapshotTestCase/UIImage+Diff.m b/packages/rn-tester/RCTTest/FBSnapshotTestCase/UIImage+Diff.m index 5713d4b74c5ef8..178f988fa595c3 100644 --- a/packages/rn-tester/RCTTest/FBSnapshotTestCase/UIImage+Diff.m +++ b/packages/rn-tester/RCTTest/FBSnapshotTestCase/UIImage+Diff.m @@ -21,15 +21,16 @@ - (UIImage *)diffWithImage:(UIImage *)image UIGraphicsImageRenderer *const renderer = [[UIGraphicsImageRenderer alloc] initWithSize:imageSize format:rendererFormat]; - return [renderer imageWithActions:^(UIGraphicsImageRendererContext *_Nonnull context) { + return [renderer imageWithActions:^(UIGraphicsImageRendererContext *_Nonnull rendererContext) { + const CGContextRef context = rendererContext.CGContext; [self drawInRect:CGRectMake(0, 0, self.size.width, self.size.height)]; - CGContextSetAlpha(context.CGContext, 0.5f); - CGContextBeginTransparencyLayer(context.CGContext, NULL); + CGContextSetAlpha(context, 0.5f); + CGContextBeginTransparencyLayer(context, NULL); [image drawInRect:CGRectMake(0, 0, image.size.width, image.size.height)]; - CGContextSetBlendMode(context.CGContext, kCGBlendModeDifference); - CGContextSetFillColorWithColor(context.CGContext, [UIColor whiteColor].CGColor); - CGContextFillRect(context.CGContext, CGRectMake(0, 0, self.size.width, self.size.height)); - CGContextEndTransparencyLayer(context.CGContext); + CGContextSetBlendMode(context, kCGBlendModeDifference); + CGContextSetFillColorWithColor(context, [UIColor whiteColor].CGColor); + CGContextFillRect(context, CGRectMake(0, 0, self.size.width, self.size.height)); + CGContextEndTransparencyLayer(context); }]; } diff --git a/packages/rn-tester/android/app/build.gradle b/packages/rn-tester/android/app/build.gradle index 964948984f041f..7e409761fab2c9 100644 --- a/packages/rn-tester/android/app/build.gradle +++ b/packages/rn-tester/android/app/build.gradle @@ -77,6 +77,11 @@ def enableProguardInReleaseBuilds = true */ def jscFlavor = 'org.webkit:android-jsc:+' +/** + * This allows to customized the CMake version used for compiling RN Tester. + */ +def cmakeVersion = project(":ReactAndroid").cmake_version + /** * Architectures to build native code for. */ @@ -128,6 +133,11 @@ android { keyPassword MYAPP_RELEASE_KEY_PASSWORD } } + externalNativeBuild { + cmake { + version cmakeVersion + } + } splits { abi { enable enableSeparateBuildPerCPUArchitecture diff --git a/packages/rn-tester/js/examples/FlatList/FlatList-basic.js b/packages/rn-tester/js/examples/FlatList/FlatList-basic.js index 25c511e570a3eb..97f991265de3ba 100644 --- a/packages/rn-tester/js/examples/FlatList/FlatList-basic.js +++ b/packages/rn-tester/js/examples/FlatList/FlatList-basic.js @@ -12,7 +12,7 @@ import type {AnimatedComponentType} from 'react-native/Libraries/Animated/createAnimatedComponent'; import typeof FlatListType from 'react-native/Libraries/Lists/FlatList'; -import type {RenderItemProps} from 'react-native/Libraries/Lists/VirtualizedListProps'; +import type {RenderItemProps} from 'react-native/Libraries/Lists/VirtualizedList'; import type {RNTesterModuleExample} from '../../types/RNTesterTypes'; import * as React from 'react'; diff --git a/packages/rn-tester/js/examples/FlatList/FlatList-nested.js b/packages/rn-tester/js/examples/FlatList/FlatList-nested.js index bb53258da9c82c..cd1f96ded9d3af 100644 --- a/packages/rn-tester/js/examples/FlatList/FlatList-nested.js +++ b/packages/rn-tester/js/examples/FlatList/FlatList-nested.js @@ -9,8 +9,8 @@ */ 'use strict'; -import type {ViewToken} from '../../../../../Libraries/Lists/ViewabilityHelper'; -import type {RenderItemProps} from '../../../../../Libraries/Lists/VirtualizedListProps'; +import type {ViewToken} from 'react-native/Libraries/Lists/ViewabilityHelper'; +import type {RenderItemProps} from 'react-native/Libraries/Lists/VirtualizedList'; import type {RNTesterModuleExample} from '../../types/RNTesterTypes'; import RNTesterPage from '../../components/RNTesterPage'; diff --git a/packages/rn-tester/js/examples/FlatList/FlatList-onViewableItemsChanged.js b/packages/rn-tester/js/examples/FlatList/FlatList-onViewableItemsChanged.js index 76e29fac105fe1..f65111e16596ba 100644 --- a/packages/rn-tester/js/examples/FlatList/FlatList-onViewableItemsChanged.js +++ b/packages/rn-tester/js/examples/FlatList/FlatList-onViewableItemsChanged.js @@ -10,7 +10,7 @@ 'use strict'; -import type {ViewToken} from '../../../../../Libraries/Lists/ViewabilityHelper'; +import type {ViewToken} from 'react-native/Libraries/Lists/ViewabilityHelper'; import type {RNTesterModuleExample} from '../../types/RNTesterTypes'; import BaseFlatListExample from './BaseFlatListExample'; diff --git a/packages/rn-tester/js/examples/View/ViewExample.js b/packages/rn-tester/js/examples/View/ViewExample.js index de2e04acc1aec4..8602101cf521bd 100644 --- a/packages/rn-tester/js/examples/View/ViewExample.js +++ b/packages/rn-tester/js/examples/View/ViewExample.js @@ -738,4 +738,43 @@ exports.examples = [ ); }, }, + { + title: 'Logical Border Color', + render(): React.Node { + return ( + + + + borderBlockColor orange + + + + + borderBlockStartColor purple + borderBlockEndColor green + + + + ); + }, + }, ]; diff --git a/Libraries/Interaction/Batchinator.js b/packages/virtualized-lists/Interaction/Batchinator.js similarity index 97% rename from Libraries/Interaction/Batchinator.js rename to packages/virtualized-lists/Interaction/Batchinator.js index 2ca2d7986d1a78..4fbc1931ca5708 100644 --- a/Libraries/Interaction/Batchinator.js +++ b/packages/virtualized-lists/Interaction/Batchinator.js @@ -10,7 +10,7 @@ 'use strict'; -const InteractionManager = require('./InteractionManager'); +const {InteractionManager} = require('react-native'); /** * A simple class for batching up invocations of a low-pri callback. A timeout is set to run the diff --git a/Libraries/Interaction/__tests__/Batchinator-test.js b/packages/virtualized-lists/Interaction/__tests__/Batchinator-test.js similarity index 95% rename from Libraries/Interaction/__tests__/Batchinator-test.js rename to packages/virtualized-lists/Interaction/__tests__/Batchinator-test.js index e8261b3515e23f..b680e98c507d00 100644 --- a/Libraries/Interaction/__tests__/Batchinator-test.js +++ b/packages/virtualized-lists/Interaction/__tests__/Batchinator-test.js @@ -10,10 +10,6 @@ 'use strict'; -jest - .mock('../../vendor/core/ErrorUtils') - .mock('../../BatchedBridge/BatchedBridge'); - function expectToBeCalledOnce(fn) { expect(fn.mock.calls.length).toBe(1); } diff --git a/Libraries/Lists/CellRenderMask.js b/packages/virtualized-lists/Lists/CellRenderMask.js similarity index 100% rename from Libraries/Lists/CellRenderMask.js rename to packages/virtualized-lists/Lists/CellRenderMask.js diff --git a/Libraries/Lists/ChildListCollection.js b/packages/virtualized-lists/Lists/ChildListCollection.js similarity index 100% rename from Libraries/Lists/ChildListCollection.js rename to packages/virtualized-lists/Lists/ChildListCollection.js diff --git a/packages/virtualized-lists/Lists/FillRateHelper.js b/packages/virtualized-lists/Lists/FillRateHelper.js new file mode 100644 index 00000000000000..87482e73f6be3e --- /dev/null +++ b/packages/virtualized-lists/Lists/FillRateHelper.js @@ -0,0 +1,253 @@ +/** + * 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 type {FrameMetricProps} from './VirtualizedListProps'; + +export type FillRateInfo = Info; + +class Info { + any_blank_count: number = 0; + any_blank_ms: number = 0; + any_blank_speed_sum: number = 0; + mostly_blank_count: number = 0; + mostly_blank_ms: number = 0; + pixels_blank: number = 0; + pixels_sampled: number = 0; + pixels_scrolled: number = 0; + total_time_spent: number = 0; + sample_count: number = 0; +} + +type FrameMetrics = { + inLayout?: boolean, + length: number, + offset: number, + ... +}; + +const DEBUG = false; + +let _listeners: Array<(Info) => void> = []; +let _minSampleCount = 10; +let _sampleRate = DEBUG ? 1 : null; + +/** + * A helper class for detecting when the maximem fill rate of `VirtualizedList` is exceeded. + * By default the sampling rate is set to zero and this will do nothing. If you want to collect + * samples (e.g. to log them), make sure to call `FillRateHelper.setSampleRate(0.0-1.0)`. + * + * Listeners and sample rate are global for all `VirtualizedList`s - typical usage will combine with + * `SceneTracker.getActiveScene` to determine the context of the events. + */ +class FillRateHelper { + _anyBlankStartTime: ?number = null; + _enabled = false; + _getFrameMetrics: (index: number, props: FrameMetricProps) => ?FrameMetrics; + _info: Info = new Info(); + _mostlyBlankStartTime: ?number = null; + _samplesStartTime: ?number = null; + + static addListener(callback: FillRateInfo => void): { + remove: () => void, + ... + } { + if (_sampleRate === null) { + console.warn('Call `FillRateHelper.setSampleRate` before `addListener`.'); + } + _listeners.push(callback); + return { + remove: () => { + _listeners = _listeners.filter(listener => callback !== listener); + }, + }; + } + + static setSampleRate(sampleRate: number) { + _sampleRate = sampleRate; + } + + static setMinSampleCount(minSampleCount: number) { + _minSampleCount = minSampleCount; + } + + constructor( + getFrameMetrics: (index: number, props: FrameMetricProps) => ?FrameMetrics, + ) { + this._getFrameMetrics = getFrameMetrics; + this._enabled = (_sampleRate || 0) > Math.random(); + this._resetData(); + } + + activate() { + if (this._enabled && this._samplesStartTime == null) { + DEBUG && console.debug('FillRateHelper: activate'); + this._samplesStartTime = global.performance.now(); + } + } + + deactivateAndFlush() { + if (!this._enabled) { + return; + } + const start = this._samplesStartTime; // const for flow + if (start == null) { + DEBUG && + console.debug('FillRateHelper: bail on deactivate with no start time'); + return; + } + if (this._info.sample_count < _minSampleCount) { + // Don't bother with under-sampled events. + this._resetData(); + return; + } + const total_time_spent = global.performance.now() - start; + const info: any = { + ...this._info, + total_time_spent, + }; + if (DEBUG) { + const derived = { + avg_blankness: this._info.pixels_blank / this._info.pixels_sampled, + avg_speed: this._info.pixels_scrolled / (total_time_spent / 1000), + avg_speed_when_any_blank: + this._info.any_blank_speed_sum / this._info.any_blank_count, + any_blank_per_min: + this._info.any_blank_count / (total_time_spent / 1000 / 60), + any_blank_time_frac: this._info.any_blank_ms / total_time_spent, + mostly_blank_per_min: + this._info.mostly_blank_count / (total_time_spent / 1000 / 60), + mostly_blank_time_frac: this._info.mostly_blank_ms / total_time_spent, + }; + for (const key in derived) { + // $FlowFixMe[prop-missing] + derived[key] = Math.round(1000 * derived[key]) / 1000; + } + console.debug('FillRateHelper deactivateAndFlush: ', {derived, info}); + } + _listeners.forEach(listener => listener(info)); + this._resetData(); + } + + computeBlankness( + props: { + ...FrameMetricProps, + initialNumToRender?: ?number, + ... + }, + cellsAroundViewport: { + first: number, + last: number, + ... + }, + scrollMetrics: { + dOffset: number, + offset: number, + velocity: number, + visibleLength: number, + ... + }, + ): number { + if ( + !this._enabled || + props.getItemCount(props.data) === 0 || + cellsAroundViewport.last < cellsAroundViewport.first || + this._samplesStartTime == null + ) { + return 0; + } + const {dOffset, offset, velocity, visibleLength} = scrollMetrics; + + // Denominator metrics that we track for all events - most of the time there is no blankness and + // we want to capture that. + this._info.sample_count++; + this._info.pixels_sampled += Math.round(visibleLength); + this._info.pixels_scrolled += Math.round(Math.abs(dOffset)); + const scrollSpeed = Math.round(Math.abs(velocity) * 1000); // px / sec + + // Whether blank now or not, record the elapsed time blank if we were blank last time. + const now = global.performance.now(); + if (this._anyBlankStartTime != null) { + this._info.any_blank_ms += now - this._anyBlankStartTime; + } + this._anyBlankStartTime = null; + if (this._mostlyBlankStartTime != null) { + this._info.mostly_blank_ms += now - this._mostlyBlankStartTime; + } + this._mostlyBlankStartTime = null; + + let blankTop = 0; + let first = cellsAroundViewport.first; + let firstFrame = this._getFrameMetrics(first, props); + while ( + first <= cellsAroundViewport.last && + (!firstFrame || !firstFrame.inLayout) + ) { + firstFrame = this._getFrameMetrics(first, props); + first++; + } + // Only count blankTop if we aren't rendering the first item, otherwise we will count the header + // as blank. + if (firstFrame && first > 0) { + blankTop = Math.min( + visibleLength, + Math.max(0, firstFrame.offset - offset), + ); + } + let blankBottom = 0; + let last = cellsAroundViewport.last; + let lastFrame = this._getFrameMetrics(last, props); + while ( + last >= cellsAroundViewport.first && + (!lastFrame || !lastFrame.inLayout) + ) { + lastFrame = this._getFrameMetrics(last, props); + last--; + } + // Only count blankBottom if we aren't rendering the last item, otherwise we will count the + // footer as blank. + if (lastFrame && last < props.getItemCount(props.data) - 1) { + const bottomEdge = lastFrame.offset + lastFrame.length; + blankBottom = Math.min( + visibleLength, + Math.max(0, offset + visibleLength - bottomEdge), + ); + } + const pixels_blank = Math.round(blankTop + blankBottom); + const blankness = pixels_blank / visibleLength; + if (blankness > 0) { + this._anyBlankStartTime = now; + this._info.any_blank_speed_sum += scrollSpeed; + this._info.any_blank_count++; + this._info.pixels_blank += pixels_blank; + if (blankness > 0.5) { + this._mostlyBlankStartTime = now; + this._info.mostly_blank_count++; + } + } else if (scrollSpeed < 0.01 || Math.abs(dOffset) < 1) { + this.deactivateAndFlush(); + } + return blankness; + } + + enabled(): boolean { + return this._enabled; + } + + _resetData() { + this._anyBlankStartTime = null; + this._info = new Info(); + this._mostlyBlankStartTime = null; + this._samplesStartTime = null; + } +} + +module.exports = FillRateHelper; diff --git a/Libraries/Lists/StateSafePureComponent.js b/packages/virtualized-lists/Lists/StateSafePureComponent.js similarity index 100% rename from Libraries/Lists/StateSafePureComponent.js rename to packages/virtualized-lists/Lists/StateSafePureComponent.js diff --git a/packages/virtualized-lists/Lists/ViewabilityHelper.js b/packages/virtualized-lists/Lists/ViewabilityHelper.js new file mode 100644 index 00000000000000..33a9811825affd --- /dev/null +++ b/packages/virtualized-lists/Lists/ViewabilityHelper.js @@ -0,0 +1,360 @@ +/** + * 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 type {FrameMetricProps} from './VirtualizedListProps'; + +const invariant = require('invariant'); + +export type ViewToken = { + item: any, + key: string, + index: ?number, + isViewable: boolean, + section?: any, + ... +}; + +export type ViewabilityConfigCallbackPair = { + viewabilityConfig: ViewabilityConfig, + onViewableItemsChanged: (info: { + viewableItems: Array, + changed: Array, + ... + }) => void, + ... +}; + +export type ViewabilityConfig = {| + /** + * Minimum amount of time (in milliseconds) that an item must be physically viewable before the + * viewability callback will be fired. A high number means that scrolling through content without + * stopping will not mark the content as viewable. + */ + minimumViewTime?: number, + + /** + * Percent of viewport that must be covered for a partially occluded item to count as + * "viewable", 0-100. Fully visible items are always considered viewable. A value of 0 means + * that a single pixel in the viewport makes the item viewable, and a value of 100 means that + * an item must be either entirely visible or cover the entire viewport to count as viewable. + */ + viewAreaCoveragePercentThreshold?: number, + + /** + * Similar to `viewAreaPercentThreshold`, but considers the percent of the item that is visible, + * rather than the fraction of the viewable area it covers. + */ + itemVisiblePercentThreshold?: number, + + /** + * Nothing is considered viewable until the user scrolls or `recordInteraction` is called after + * render. + */ + waitForInteraction?: boolean, +|}; + +/** + * A Utility class for calculating viewable items based on current metrics like scroll position and + * layout. + * + * An item is said to be in a "viewable" state when any of the following + * is true for longer than `minimumViewTime` milliseconds (after an interaction if `waitForInteraction` + * is true): + * + * - Occupying >= `viewAreaCoveragePercentThreshold` of the view area XOR fraction of the item + * visible in the view area >= `itemVisiblePercentThreshold`. + * - Entirely visible on screen + */ +class ViewabilityHelper { + _config: ViewabilityConfig; + _hasInteracted: boolean = false; + _timers: Set = new Set(); + _viewableIndices: Array = []; + _viewableItems: Map = new Map(); + + constructor( + config: ViewabilityConfig = {viewAreaCoveragePercentThreshold: 0}, + ) { + this._config = config; + } + + /** + * Cleanup, e.g. on unmount. Clears any pending timers. + */ + dispose() { + /* $FlowFixMe[incompatible-call] (>=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. */ + this._timers.forEach(clearTimeout); + } + + /** + * Determines which items are viewable based on the current metrics and config. + */ + computeViewableItems( + props: FrameMetricProps, + scrollOffset: number, + viewportHeight: number, + getFrameMetrics: ( + index: number, + props: FrameMetricProps, + ) => ?{ + length: number, + offset: number, + ... + }, + // Optional optimization to reduce the scan size + renderRange?: { + first: number, + last: number, + ... + }, + ): Array { + const itemCount = props.getItemCount(props.data); + const {itemVisiblePercentThreshold, viewAreaCoveragePercentThreshold} = + this._config; + const viewAreaMode = viewAreaCoveragePercentThreshold != null; + const viewablePercentThreshold = viewAreaMode + ? viewAreaCoveragePercentThreshold + : itemVisiblePercentThreshold; + invariant( + viewablePercentThreshold != null && + (itemVisiblePercentThreshold != null) !== + (viewAreaCoveragePercentThreshold != null), + 'Must set exactly one of itemVisiblePercentThreshold or viewAreaCoveragePercentThreshold', + ); + const viewableIndices = []; + if (itemCount === 0) { + return viewableIndices; + } + let firstVisible = -1; + const {first, last} = renderRange || {first: 0, last: itemCount - 1}; + if (last >= itemCount) { + console.warn( + 'Invalid render range computing viewability ' + + JSON.stringify({renderRange, itemCount}), + ); + return []; + } + for (let idx = first; idx <= last; idx++) { + const metrics = getFrameMetrics(idx, props); + if (!metrics) { + continue; + } + const top = metrics.offset - scrollOffset; + const bottom = top + metrics.length; + if (top < viewportHeight && bottom > 0) { + firstVisible = idx; + if ( + _isViewable( + viewAreaMode, + viewablePercentThreshold, + top, + bottom, + viewportHeight, + metrics.length, + ) + ) { + viewableIndices.push(idx); + } + } else if (firstVisible >= 0) { + break; + } + } + return viewableIndices; + } + + /** + * Figures out which items are viewable and how that has changed from before and calls + * `onViewableItemsChanged` as appropriate. + */ + onUpdate( + props: FrameMetricProps, + scrollOffset: number, + viewportHeight: number, + getFrameMetrics: ( + index: number, + props: FrameMetricProps, + ) => ?{ + length: number, + offset: number, + ... + }, + createViewToken: ( + index: number, + isViewable: boolean, + props: FrameMetricProps, + ) => ViewToken, + onViewableItemsChanged: ({ + viewableItems: Array, + changed: Array, + ... + }) => void, + // Optional optimization to reduce the scan size + renderRange?: { + first: number, + last: number, + ... + }, + ): void { + const itemCount = props.getItemCount(props.data); + if ( + (this._config.waitForInteraction && !this._hasInteracted) || + itemCount === 0 || + !getFrameMetrics(0, props) + ) { + return; + } + let viewableIndices: Array = []; + if (itemCount) { + viewableIndices = this.computeViewableItems( + props, + scrollOffset, + viewportHeight, + getFrameMetrics, + renderRange, + ); + } + if ( + this._viewableIndices.length === viewableIndices.length && + this._viewableIndices.every((v, ii) => v === viewableIndices[ii]) + ) { + // We might get a lot of scroll events where visibility doesn't change and we don't want to do + // extra work in those cases. + return; + } + this._viewableIndices = viewableIndices; + if (this._config.minimumViewTime) { + const handle: TimeoutID = setTimeout(() => { + /* $FlowFixMe[incompatible-call] (>=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. */ + this._timers.delete(handle); + this._onUpdateSync( + props, + viewableIndices, + onViewableItemsChanged, + createViewToken, + ); + }, this._config.minimumViewTime); + /* $FlowFixMe[incompatible-call] (>=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. */ + this._timers.add(handle); + } else { + this._onUpdateSync( + props, + viewableIndices, + onViewableItemsChanged, + createViewToken, + ); + } + } + + /** + * clean-up cached _viewableIndices to evaluate changed items on next update + */ + resetViewableIndices() { + this._viewableIndices = []; + } + + /** + * Records that an interaction has happened even if there has been no scroll. + */ + recordInteraction() { + this._hasInteracted = true; + } + + _onUpdateSync( + props: FrameMetricProps, + viewableIndicesToCheck: Array, + onViewableItemsChanged: ({ + changed: Array, + viewableItems: Array, + ... + }) => void, + createViewToken: ( + index: number, + isViewable: boolean, + props: FrameMetricProps, + ) => ViewToken, + ) { + // Filter out indices that have gone out of view since this call was scheduled. + viewableIndicesToCheck = viewableIndicesToCheck.filter(ii => + this._viewableIndices.includes(ii), + ); + const prevItems = this._viewableItems; + const nextItems = new Map( + viewableIndicesToCheck.map(ii => { + const viewable = createViewToken(ii, true, props); + return [viewable.key, viewable]; + }), + ); + + const changed = []; + for (const [key, viewable] of nextItems) { + if (!prevItems.has(key)) { + changed.push(viewable); + } + } + for (const [key, viewable] of prevItems) { + if (!nextItems.has(key)) { + changed.push({...viewable, isViewable: false}); + } + } + if (changed.length > 0) { + this._viewableItems = nextItems; + onViewableItemsChanged({ + viewableItems: Array.from(nextItems.values()), + changed, + viewabilityConfig: this._config, + }); + } + } +} + +function _isViewable( + viewAreaMode: boolean, + viewablePercentThreshold: number, + top: number, + bottom: number, + viewportHeight: number, + itemLength: number, +): boolean { + if (_isEntirelyVisible(top, bottom, viewportHeight)) { + return true; + } else { + const pixels = _getPixelsVisible(top, bottom, viewportHeight); + const percent = + 100 * (viewAreaMode ? pixels / viewportHeight : pixels / itemLength); + return percent >= viewablePercentThreshold; + } +} + +function _getPixelsVisible( + top: number, + bottom: number, + viewportHeight: number, +): number { + const visibleHeight = Math.min(bottom, viewportHeight) - Math.max(top, 0); + return Math.max(0, visibleHeight); +} + +function _isEntirelyVisible( + top: number, + bottom: number, + viewportHeight: number, +): boolean { + return top >= 0 && bottom <= viewportHeight && bottom > top; +} + +module.exports = ViewabilityHelper; diff --git a/packages/virtualized-lists/Lists/VirtualizeUtils.js b/packages/virtualized-lists/Lists/VirtualizeUtils.js new file mode 100644 index 00000000000000..3a70d9f683091e --- /dev/null +++ b/packages/virtualized-lists/Lists/VirtualizeUtils.js @@ -0,0 +1,258 @@ +/** + * 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 type {FrameMetricProps} from './VirtualizedListProps'; + +/** + * Used to find the indices of the frames that overlap the given offsets. Useful for finding the + * items that bound different windows of content, such as the visible area or the buffered overscan + * area. + */ +export function elementsThatOverlapOffsets( + offsets: Array, + props: FrameMetricProps, + getFrameMetrics: ( + index: number, + props: FrameMetricProps, + ) => { + length: number, + offset: number, + ... + }, + zoomScale: number = 1, +): Array { + const itemCount = props.getItemCount(props.data); + const result = []; + for (let offsetIndex = 0; offsetIndex < offsets.length; offsetIndex++) { + const currentOffset = offsets[offsetIndex]; + let left = 0; + let right = itemCount - 1; + + while (left <= right) { + // eslint-disable-next-line no-bitwise + const mid = left + ((right - left) >>> 1); + const frame = getFrameMetrics(mid, props); + const scaledOffsetStart = frame.offset * zoomScale; + const scaledOffsetEnd = (frame.offset + frame.length) * zoomScale; + + // We want the first frame that contains the offset, with inclusive bounds. Thus, for the + // first frame the scaledOffsetStart is inclusive, while for other frames it is exclusive. + if ( + (mid === 0 && currentOffset < scaledOffsetStart) || + (mid !== 0 && currentOffset <= scaledOffsetStart) + ) { + right = mid - 1; + } else if (currentOffset > scaledOffsetEnd) { + left = mid + 1; + } else { + result[offsetIndex] = mid; + break; + } + } + } + + return result; +} + +/** + * Computes the number of elements in the `next` range that are new compared to the `prev` range. + * Handy for calculating how many new items will be rendered when the render window changes so we + * can restrict the number of new items render at once so that content can appear on the screen + * faster. + */ +export function newRangeCount( + prev: { + first: number, + last: number, + ... + }, + next: { + first: number, + last: number, + ... + }, +): number { + return ( + next.last - + next.first + + 1 - + Math.max( + 0, + 1 + Math.min(next.last, prev.last) - Math.max(next.first, prev.first), + ) + ); +} + +/** + * Custom logic for determining which items should be rendered given the current frame and scroll + * metrics, as well as the previous render state. The algorithm may evolve over time, but generally + * prioritizes the visible area first, then expands that with overscan regions ahead and behind, + * biased in the direction of scroll. + */ +export function computeWindowedRenderLimits( + props: FrameMetricProps, + maxToRenderPerBatch: number, + windowSize: number, + prev: { + first: number, + last: number, + }, + getFrameMetricsApprox: ( + index: number, + props: FrameMetricProps, + ) => { + length: number, + offset: number, + ... + }, + scrollMetrics: { + dt: number, + offset: number, + velocity: number, + visibleLength: number, + zoomScale: number, + ... + }, +): { + first: number, + last: number, +} { + const itemCount = props.getItemCount(props.data); + if (itemCount === 0) { + return {first: 0, last: -1}; + } + const {offset, velocity, visibleLength, zoomScale = 1} = scrollMetrics; + + // Start with visible area, then compute maximum overscan region by expanding from there, biased + // in the direction of scroll. Total overscan area is capped, which should cap memory consumption + // too. + const visibleBegin = Math.max(0, offset); + const visibleEnd = visibleBegin + visibleLength; + const overscanLength = (windowSize - 1) * visibleLength; + + // Considering velocity seems to introduce more churn than it's worth. + const leadFactor = 0.5; // Math.max(0, Math.min(1, velocity / 25 + 0.5)); + + const fillPreference = + velocity > 1 ? 'after' : velocity < -1 ? 'before' : 'none'; + + const overscanBegin = Math.max( + 0, + visibleBegin - (1 - leadFactor) * overscanLength, + ); + const overscanEnd = Math.max(0, visibleEnd + leadFactor * overscanLength); + + const lastItemOffset = + getFrameMetricsApprox(itemCount - 1, props).offset * zoomScale; + if (lastItemOffset < overscanBegin) { + // Entire list is before our overscan window + return { + first: Math.max(0, itemCount - 1 - maxToRenderPerBatch), + last: itemCount - 1, + }; + } + + // Find the indices that correspond to the items at the render boundaries we're targeting. + let [overscanFirst, first, last, overscanLast] = elementsThatOverlapOffsets( + [overscanBegin, visibleBegin, visibleEnd, overscanEnd], + props, + getFrameMetricsApprox, + zoomScale, + ); + overscanFirst = overscanFirst == null ? 0 : overscanFirst; + first = first == null ? Math.max(0, overscanFirst) : first; + overscanLast = overscanLast == null ? itemCount - 1 : overscanLast; + last = + last == null + ? Math.min(overscanLast, first + maxToRenderPerBatch - 1) + : last; + const visible = {first, last}; + + // We want to limit the number of new cells we're rendering per batch so that we can fill the + // content on the screen quickly. If we rendered the entire overscan window at once, the user + // could be staring at white space for a long time waiting for a bunch of offscreen content to + // render. + let newCellCount = newRangeCount(prev, visible); + + while (true) { + if (first <= overscanFirst && last >= overscanLast) { + // If we fill the entire overscan range, we're done. + break; + } + const maxNewCells = newCellCount >= maxToRenderPerBatch; + const firstWillAddMore = first <= prev.first || first > prev.last; + const firstShouldIncrement = + first > overscanFirst && (!maxNewCells || !firstWillAddMore); + const lastWillAddMore = last >= prev.last || last < prev.first; + const lastShouldIncrement = + last < overscanLast && (!maxNewCells || !lastWillAddMore); + if (maxNewCells && !firstShouldIncrement && !lastShouldIncrement) { + // We only want to stop if we've hit maxNewCells AND we cannot increment first or last + // without rendering new items. This let's us preserve as many already rendered items as + // possible, reducing render churn and keeping the rendered overscan range as large as + // possible. + break; + } + if ( + firstShouldIncrement && + !(fillPreference === 'after' && lastShouldIncrement && lastWillAddMore) + ) { + if (firstWillAddMore) { + newCellCount++; + } + first--; + } + if ( + lastShouldIncrement && + !(fillPreference === 'before' && firstShouldIncrement && firstWillAddMore) + ) { + if (lastWillAddMore) { + newCellCount++; + } + last++; + } + } + if ( + !( + last >= first && + first >= 0 && + last < itemCount && + first >= overscanFirst && + last <= overscanLast && + first <= visible.first && + last >= visible.last + ) + ) { + throw new Error( + 'Bad window calculation ' + + JSON.stringify({ + first, + last, + itemCount, + overscanFirst, + overscanLast, + visible, + }), + ); + } + return {first, last}; +} + +export function keyExtractor(item: any, index: number): string { + if (typeof item === 'object' && item?.key != null) { + return item.key; + } + if (typeof item === 'object' && item?.id != null) { + return item.id; + } + return String(index); +} diff --git a/Libraries/Lists/VirtualizedList.d.ts b/packages/virtualized-lists/Lists/VirtualizedList.d.ts similarity index 97% rename from Libraries/Lists/VirtualizedList.d.ts rename to packages/virtualized-lists/Lists/VirtualizedList.d.ts index d874dab4d10271..a2702d9101e107 100644 --- a/Libraries/Lists/VirtualizedList.d.ts +++ b/packages/virtualized-lists/Lists/VirtualizedList.d.ts @@ -8,15 +8,15 @@ */ import type * as React from 'react'; -import type {LayoutChangeEvent} from '../../types'; -import {StyleProp} from '../StyleSheet/StyleSheet'; -import {ViewStyle} from '../StyleSheet/StyleSheetTypes'; import type { + StyleProp, + ViewStyle, + ScrollViewProps, + LayoutChangeEvent, + View, ScrollResponderMixin, ScrollView, - ScrollViewProps, -} from '../Components/ScrollView/ScrollView'; -import type {View} from '../Components/View/View'; +} from 'react-native'; export interface ViewToken { item: any; diff --git a/packages/virtualized-lists/Lists/VirtualizedList.js b/packages/virtualized-lists/Lists/VirtualizedList.js new file mode 100644 index 00000000000000..638daf14895558 --- /dev/null +++ b/packages/virtualized-lists/Lists/VirtualizedList.js @@ -0,0 +1,1944 @@ +/** + * 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 'react-native/Libraries/Components/ScrollView/ScrollView'; +import type {ViewStyleProp} from 'react-native/Libraries/StyleSheet/StyleSheet'; +import type { + LayoutEvent, + ScrollEvent, +} from 'react-native/Libraries/Types/CoreEventTypes'; +import type {ViewToken} from './ViewabilityHelper'; +import type { + FrameMetricProps, + Item, + Props, + RenderItemProps, + RenderItemType, + Separators, +} from './VirtualizedListProps'; + +import { + RefreshControl, + ScrollView, + View, + StyleSheet, + findNodeHandle, +} from 'react-native'; +import Batchinator from '../Interaction/Batchinator'; +import clamp from '../Utilities/clamp'; +import infoLog from '../Utilities/infoLog'; +import {CellRenderMask} from './CellRenderMask'; +import ChildListCollection from './ChildListCollection'; +import FillRateHelper from './FillRateHelper'; +import StateSafePureComponent from './StateSafePureComponent'; +import ViewabilityHelper from './ViewabilityHelper'; +import CellRenderer from './VirtualizedListCellRenderer'; +import { + VirtualizedListCellContextProvider, + VirtualizedListContext, + VirtualizedListContextProvider, +} from './VirtualizedListContext.js'; +import { + computeWindowedRenderLimits, + keyExtractor as defaultKeyExtractor, +} from './VirtualizeUtils'; +import invariant from 'invariant'; +import * as React from 'react'; + +export type {RenderItemProps, RenderItemType, Separators}; + +const ON_EDGE_REACHED_EPSILON = 0.001; + +let _usedIndexForKey = false; +let _keylessItemComponentName: string = ''; + +type ViewabilityHelperCallbackTuple = { + viewabilityHelper: ViewabilityHelper, + onViewableItemsChanged: (info: { + viewableItems: Array, + changed: Array, + ... + }) => void, + ... +}; + +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; +} + +// onStartReachedThresholdOrDefault(this.props.onStartReachedThreshold) +function onStartReachedThresholdOrDefault(onStartReachedThreshold: ?number) { + return onStartReachedThreshold ?? 2; +} + +// onEndReachedThresholdOrDefault(this.props.onEndReachedThreshold) +function onEndReachedThresholdOrDefault(onEndReachedThreshold: ?number) { + return onEndReachedThreshold ?? 2; +} + +// getScrollingThreshold(visibleLength, onEndReachedThreshold) +function getScrollingThreshold(threshold: number, visibleLength: number) { + return (threshold * visibleLength) / 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 StateSafePureComponent { + 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; + if (veryLast < 0) { + return; + } + const frame = this.__getFrameMetricsApprox(veryLast, this.props); + 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, + ... + }): $FlowFixMe { + 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(Math.floor(index), this.props); + const offset = + Math.max( + 0, + this._getOffsetApprox(index, this.props) - + (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, + viewOffset?: number, + 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.recordInteraction(); + }); + this._viewabilityTuples.forEach(t => { + t.viewabilityHelper.recordInteraction(); + }); + this._updateViewableItems(this.props, this.state.cellsAroundViewport); + } + + 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 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'; + } + + // $FlowFixMe[missing-local-annot] + _getScrollMetrics = () => { + return this._scrollMetrics; + }; + + hasMore(): boolean { + return this._hasMore; + } + + // $FlowFixMe[missing-local-annot] + _getOutermostParentListRef = () => { + if (this._isNestedWithSameOrientation()) { + return this.context.getOutermostParentListRef(); + } else { + return this; + } + }; + + _registerAsNestedChild = (childList: { + cellKey: string, + ref: React.ElementRef, + }): void => { + this._nestedChildLists.add(childList.ref, childList.cellKey); + if (this._hasInteracted) { + childList.ref.recordInteraction(); + } + }; + + _unregisterAsNestedChild = (childList: { + ref: React.ElementRef, + }): void => { + this._nestedChildLists.remove(childList.ref); + }; + + 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, + }); + } + } + + invariant( + !this.context, + 'Unexpectedly saw VirtualizedListContext available in ctor', + ); + + const initialRenderRegion = VirtualizedList._initialRenderRegion(props); + + this.state = { + cellsAroundViewport: initialRenderRegion, + renderMask: VirtualizedList._createRenderMask(props, initialRenderRegion), + }; + } + + 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) { + 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 = Math.floor(Math.max(0, 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(props, cellsAroundViewport); + + 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.last >= getItemCount(data) + ? VirtualizedList._constrainToItemCount(cellsAroundViewport, props) + : cellsAroundViewport; + } + + let newCellsAroundViewport: {first: number, last: number}; + if (props.disableVirtualization) { + const renderAhead = + distanceFromEnd < onEndReachedThreshold * visibleLength + ? maxToRenderPerBatchOrDefault(props.maxToRenderPerBatch) + : 0; + + newCellsAroundViewport = { + first: 0, + last: Math.min( + 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 ( + props.initialScrollIndex && + !this._scrollMetrics.offset && + Math.abs(distanceFromEnd) >= Number.EPSILON + ) { + return cellsAroundViewport.last >= getItemCount(data) + ? VirtualizedList._constrainToItemCount(cellsAroundViewport, props) + : cellsAroundViewport; + } + + newCellsAroundViewport = computeWindowedRenderLimits( + props, + maxToRenderPerBatchOrDefault(props.maxToRenderPerBatch), + windowSizeOrDefault(props.windowSize), + cellsAroundViewport, + this.__getFrameMetricsApprox, + this._scrollMetrics, + ); + invariant( + newCellsAroundViewport.last < getItemCount(data), + 'computeWindowedRenderLimits() should return range in-bounds', + ); + } + + 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); + if ( + cellKeyForIndex != null && + this._nestedChildLists.anyInCell(cellKeyForIndex, childList => + childList.hasMore(), + ) + ) { + return ii; + } + } + + return null; + } + + componentDidMount() { + if (this._isNestedWithSameOrientation()) { + this.context.registerAsNestedChild({ + ref: this, + cellKey: this.context.cellKey, + }); + } + } + + componentWillUnmount() { + if (this._isNestedWithSameOrientation()) { + this.context.unregisterAsNestedChild({ref: this}); + } + 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.props); + 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); + }); + }; + + _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, + props: { + keyExtractor?: ?(item: Item, index: number) => string, + ... + }, + // $FlowFixMe[missing-local-annot] + ) { + if (props.keyExtractor != null) { + return 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__) { + // $FlowFixMe[underconstrained-implicit-instantiation] + const flatStyles = StyleSheet.flatten(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: Array = []; + 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, { + onLayout: (event: LayoutEvent) => { + 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.props.disableVirtualization) { + 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, + this.props, + ); + const lastMetrics = this.__getFrameMetricsApprox(last, this.props); + 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 && + this.props.scrollEnabled !== false + ) { + // 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; + _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: ChildListCollection = + new ChildListCollection(); + _offsetFromParentVirtualizedList: number = 0; + _prevParentOffset: number = 0; + // $FlowFixMe[missing-local-annot] + _scrollMetrics = { + contentLength: 0, + dOffset: 0, + dt: 10, + offset: 0, + timestamp: 0, + velocity: 0, + visibleLength: 0, + zoomScale: 1, + }; + _scrollRef: ?React.ElementRef = null; + _sentStartForContentLength = 0; + _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 + // $FlowFixMe[incompatible-use] + + ) : ( + props.refreshControl + ) + } + /> + ); + } else { + // $FlowFixMe[prop-missing] Invalid prop usage + // $FlowFixMe[incompatible-use] + 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, this.state.cellsAroundViewport); + }; + + _onCellFocusCapture(cellKey: string) { + this._lastFocusedCellKey = cellKey; + this._updateCellsToRender(); + } + + _onCellUnmount = (cellKey: string) => { + const curr = this._frames[cellKey]; + if (curr) { + this._frames[cellKey] = {...curr, inLayout: false}; + } + }; + + _triggerRemeasureForChildListsInCell(cellKey: string): void { + this._nestedChildLists.forEachInCell(cellKey, childList => { + childList.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._nestedChildLists.forEach(childList => { + childList.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._maybeCallOnEdgeReached(); + }; + + _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); + }; + + // $FlowFixMe[missing-local-annot] + _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, this.props); + /* $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, + this.props, + ).offset; + const frameLast = this.__getFrameMetricsApprox( + this.state.cellsAroundViewport.last, + this.props, + ); + 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; + } + + _maybeCallOnEdgeReached() { + const { + data, + getItemCount, + onStartReached, + onStartReachedThreshold, + onEndReached, + onEndReachedThreshold, + initialScrollIndex, + } = this.props; + const {contentLength, visibleLength, offset} = this._scrollMetrics; + let distanceFromStart = offset; + let distanceFromEnd = contentLength - visibleLength - offset; + + // Especially when oERT is zero it's necessary to 'floor' very small distance 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 edge of the list with a distance approximating 0 but not quite there. + if (distanceFromStart < ON_EDGE_REACHED_EPSILON) { + distanceFromStart = 0; + } + if (distanceFromEnd < ON_EDGE_REACHED_EPSILON) { + distanceFromEnd = 0; + } + + // TODO: T121172172 Look into why we're "defaulting" to a threshold of 2px + // when oERT is not present (different from 2 viewports used elsewhere) + const DEFAULT_THRESHOLD_PX = 2; + + const startThreshold = + onStartReachedThreshold != null + ? onStartReachedThreshold * visibleLength + : DEFAULT_THRESHOLD_PX; + const endThreshold = + onEndReachedThreshold != null + ? onEndReachedThreshold * visibleLength + : DEFAULT_THRESHOLD_PX; + const isWithinStartThreshold = distanceFromStart <= startThreshold; + const isWithinEndThreshold = distanceFromEnd <= endThreshold; + + // First check if the user just scrolled within the end threshold + // and call onEndReached only once for a given content length, + // and only if onStartReached is not being executed + if ( + onEndReached && + this.state.cellsAroundViewport.last === getItemCount(data) - 1 && + isWithinEndThreshold && + this._scrollMetrics.contentLength !== this._sentEndForContentLength + ) { + this._sentEndForContentLength = this._scrollMetrics.contentLength; + onEndReached({distanceFromEnd}); + } + + // Next check if the user just scrolled within the start threshold + // and call onStartReached only once for a given content length, + // and only if onEndReached is not being executed + else if ( + onStartReached != null && + this.state.cellsAroundViewport.first === 0 && + isWithinStartThreshold && + this._scrollMetrics.contentLength !== this._sentStartForContentLength + ) { + // On initial mount when using initialScrollIndex the offset will be 0 initially + // and will trigger an unexpected onStartReached. To avoid this we can use + // timestamp to differentiate between the initial scroll metrics and when we actually + // received the first scroll event. + if (!initialScrollIndex || this._scrollMetrics.timestamp !== 0) { + this._sentStartForContentLength = this._scrollMetrics.contentLength; + onStartReached({distanceFromStart}); + } + } + + // If the user scrolls away from the start or end and back again, + // cause onStartReached or onEndReached to be triggered again + else { + this._sentStartForContentLength = isWithinStartThreshold + ? this._sentStartForContentLength + : 0; + this._sentEndForContentLength = isWithinEndThreshold + ? 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._maybeCallOnEdgeReached(); + }; + + /* Translates metrics from a scroll event in a parent VirtualizedList into + * coordinates relative to the child list. + */ + _convertParentScrollMetrics = (metrics: { + visibleLength: number, + offset: number, + ... + }): $FlowFixMe => { + // 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._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, this.state.cellsAroundViewport); + if (!this.props) { + return; + } + this._maybeCallOnEdgeReached(); + 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 onStartReachedThreshold = onStartReachedThresholdOrDefault( + this.props.onStartReachedThreshold, + ); + const onEndReachedThreshold = onEndReachedThresholdOrDefault( + this.props.onEndReachedThreshold, + ); + // 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, this.props).offset; + hiPri = + distTop < 0 || + (velocity < -2 && + distTop < + getScrollingThreshold(onStartReachedThreshold, visibleLength)); + } + // 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 (!hiPri && last >= 0 && last < itemCount - 1) { + const distBottom = + this.__getFrameMetricsApprox(last, this.props).offset - + (offset + visibleLength); + hiPri = + distBottom < 0 || + (velocity > 2 && + distBottom < + getScrollingThreshold(onEndReachedThreshold, visibleLength)); + } + // 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._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._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._onMomentumScrollBegin(e); + }); + this.props.onMomentumScrollBegin && this.props.onMomentumScrollBegin(e); + }; + + _onMomentumScrollEnd = (e: ScrollEvent): void => { + this._nestedChildLists.forEach(childList => { + childList._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(props), + ); + + 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, + props: FrameMetricProps, + // $FlowFixMe[missing-local-annot] + ) => { + const {data, getItem} = props; + const item = getItem(data, index); + return { + index, + item, + key: this._keyExtractor(item, index, props), + isViewable, + }; + }; + + /** + * Gets an approximate offset to an item at a given index. Supports + * fractional indices. + */ + _getOffsetApprox = (index: number, props: FrameMetricProps): number => { + if (Number.isInteger(index)) { + return this.__getFrameMetricsApprox(index, props).offset; + } else { + const frameMetrics = this.__getFrameMetricsApprox( + Math.floor(index), + props, + ); + const remainder = index - Math.floor(index); + return frameMetrics.offset + remainder * frameMetrics.length; + } + }; + + __getFrameMetricsApprox: ( + index: number, + props: FrameMetricProps, + ) => { + length: number, + offset: number, + ... + } = (index, props) => { + const frame = this._getFrameMetrics(index, props); + if (frame && frame.index === index) { + // check for invalid frames due to row re-ordering + return frame; + } else { + const {data, getItemCount, getItemLayout} = 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, + props: FrameMetricProps, + ): ?{ + length: number, + offset: number, + index: number, + inLayout?: boolean, + ... + } => { + const {data, getItem, getItemCount, getItemLayout} = props; + invariant( + index >= 0 && index < getItemCount(data), + 'Tried to get frame for out of range index ' + index, + ); + const item = getItem(data, index); + const frame = this._frames[this._keyExtractor(item, index, props)]; + 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 = ( + props: FrameMetricProps, + ): $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 = props.getItemCount(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, + props, + ).length; + } + + let last = focusedCellIndex; + let heightOfCellsAfterFocused = 0; + for ( + let i = last + 1; + i < itemCount && + heightOfCellsAfterFocused < this._scrollMetrics.visibleLength; + i++ + ) { + last++; + heightOfCellsAfterFocused += this.__getFrameMetricsApprox( + i, + props, + ).length; + } + + return [{first, last}]; + }; + + _updateViewableItems( + props: FrameMetricProps, + cellsAroundViewport: {first: number, last: number}, + ) { + this._viewabilityTuples.forEach(tuple => { + tuple.viewabilityHelper.onUpdate( + props, + this._scrollMetrics.offset, + this._scrollMetrics.visibleLength, + this._getFrameMetrics, + this._createViewToken, + tuple.onViewableItemsChanged, + cellsAroundViewport, + ); + }); + } +} + +const styles = StyleSheet.create({ + verticallyInverted: { + transform: [{scaleY: -1}], + }, + horizontallyInverted: { + transform: [{scaleX: -1}], + }, + 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/VirtualizedListCellRenderer.js b/packages/virtualized-lists/Lists/VirtualizedListCellRenderer.js similarity index 96% rename from Libraries/Lists/VirtualizedListCellRenderer.js rename to packages/virtualized-lists/Lists/VirtualizedListCellRenderer.js index b16900d63b742b..0064f788b8a9c4 100644 --- a/Libraries/Lists/VirtualizedListCellRenderer.js +++ b/packages/virtualized-lists/Lists/VirtualizedListCellRenderer.js @@ -8,13 +8,15 @@ * @format */ -import type {ViewStyleProp} from '../StyleSheet/StyleSheet'; -import type {FocusEvent, LayoutEvent} from '../Types/CoreEventTypes'; +import type {ViewStyleProp} from 'react-native/Libraries/StyleSheet/StyleSheet'; +import type { + FocusEvent, + LayoutEvent, +} from 'react-native/Libraries/Types/CoreEventTypes'; import type FillRateHelper from './FillRateHelper'; import type {RenderItemType} from './VirtualizedListProps'; -import View from '../Components/View/View'; -import StyleSheet from '../StyleSheet/StyleSheet'; +import {View, StyleSheet} from 'react-native'; import {VirtualizedListCellContextProvider} from './VirtualizedListContext.js'; import invariant from 'invariant'; import * as React from 'react'; diff --git a/packages/virtualized-lists/Lists/VirtualizedListContext.js b/packages/virtualized-lists/Lists/VirtualizedListContext.js new file mode 100644 index 00000000000000..bca5724498a356 --- /dev/null +++ b/packages/virtualized-lists/Lists/VirtualizedListContext.js @@ -0,0 +1,116 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow strict-local + * @format + */ + +import typeof VirtualizedList from './VirtualizedList'; + +import * as React from 'react'; +import {useContext, useMemo} from 'react'; + +type Context = $ReadOnly<{ + cellKey: ?string, + getScrollMetrics: () => { + contentLength: number, + dOffset: number, + dt: number, + offset: number, + timestamp: number, + velocity: number, + visibleLength: number, + zoomScale: number, + }, + horizontal: ?boolean, + getOutermostParentListRef: () => React.ElementRef, + registerAsNestedChild: ({ + cellKey: string, + ref: React.ElementRef, + }) => void, + unregisterAsNestedChild: ({ + ref: React.ElementRef, + }) => void, +}>; + +export const VirtualizedListContext: React.Context = + React.createContext(null); +if (__DEV__) { + VirtualizedListContext.displayName = 'VirtualizedListContext'; +} + +/** + * Resets the context. Intended for use by portal-like components (e.g. Modal). + */ +export function VirtualizedListContextResetter({ + children, +}: { + children: React.Node, +}): React.Node { + return ( + + {children} + + ); +} + +/** + * Sets the context with memoization. Intended to be used by `VirtualizedList`. + */ +export function VirtualizedListContextProvider({ + children, + value, +}: { + children: React.Node, + value: Context, +}): React.Node { + // Avoid setting a newly created context object if the values are identical. + const context = useMemo( + () => ({ + cellKey: null, + getScrollMetrics: value.getScrollMetrics, + horizontal: value.horizontal, + getOutermostParentListRef: value.getOutermostParentListRef, + registerAsNestedChild: value.registerAsNestedChild, + unregisterAsNestedChild: value.unregisterAsNestedChild, + }), + [ + value.getScrollMetrics, + value.horizontal, + value.getOutermostParentListRef, + value.registerAsNestedChild, + value.unregisterAsNestedChild, + ], + ); + return ( + + {children} + + ); +} + +/** + * Sets the `cellKey`. Intended to be used by `VirtualizedList` for each cell. + */ +export function VirtualizedListCellContextProvider({ + cellKey, + children, +}: { + cellKey: string, + children: React.Node, +}): React.Node { + // Avoid setting a newly created context object if the values are identical. + const currContext = useContext(VirtualizedListContext); + const context = useMemo( + () => (currContext == null ? null : {...currContext, cellKey}), + [currContext, cellKey], + ); + return ( + + {children} + + ); +} diff --git a/Libraries/Lists/VirtualizedListProps.js b/packages/virtualized-lists/Lists/VirtualizedListProps.js similarity index 98% rename from Libraries/Lists/VirtualizedListProps.js rename to packages/virtualized-lists/Lists/VirtualizedListProps.js index f4d497b1d467a8..bfc59673270a57 100644 --- a/Libraries/Lists/VirtualizedListProps.js +++ b/packages/virtualized-lists/Lists/VirtualizedListProps.js @@ -8,8 +8,8 @@ * @format */ -import typeof ScrollView from '../Components/ScrollView/ScrollView'; -import type {ViewStyleProp} from '../StyleSheet/StyleSheet'; +import {typeof ScrollView} from 'react-native'; +import type {ViewStyleProp} from 'react-native/Libraries/StyleSheet/StyleSheet'; import type { ViewabilityConfig, ViewabilityConfigCallbackPair, diff --git a/packages/virtualized-lists/Lists/VirtualizedSectionList.js b/packages/virtualized-lists/Lists/VirtualizedSectionList.js new file mode 100644 index 00000000000000..61519bca4dc866 --- /dev/null +++ b/packages/virtualized-lists/Lists/VirtualizedSectionList.js @@ -0,0 +1,617 @@ +/** + * 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 {ViewToken} from './ViewabilityHelper'; + +import {View} from 'react-native'; +import VirtualizedList from './VirtualizedList'; +import {keyExtractor as defaultKeyExtractor} from './VirtualizeUtils'; +import invariant from 'invariant'; +import * as React from 'react'; + +type Item = any; + +export type SectionBase = { + /** + * The data for rendering items in this section. + */ + data: $ReadOnlyArray, + /** + * Optional key to keep track of section re-ordering. If you don't plan on re-ordering sections, + * the array index will be used by default. + */ + key?: string, + // Optional props will override list-wide props just for this section. + renderItem?: ?(info: { + item: SectionItemT, + index: number, + section: SectionBase, + separators: { + highlight: () => void, + unhighlight: () => void, + updateProps: (select: 'leading' | 'trailing', newProps: Object) => void, + ... + }, + ... + }) => null | React.Element, + ItemSeparatorComponent?: ?React.ComponentType, + keyExtractor?: (item: SectionItemT, index?: ?number) => string, + ... +}; + +type RequiredProps> = {| + sections: $ReadOnlyArray, +|}; + +type OptionalProps> = {| + /** + * Default renderer for every item in every section. + */ + renderItem?: (info: { + item: Item, + index: number, + section: SectionT, + separators: { + highlight: () => void, + unhighlight: () => void, + updateProps: (select: 'leading' | 'trailing', newProps: Object) => void, + ... + }, + ... + }) => null | React.Element, + /** + * Rendered at the top of each section. These stick to the top of the `ScrollView` by default on + * iOS. See `stickySectionHeadersEnabled`. + */ + renderSectionHeader?: ?(info: { + section: SectionT, + ... + }) => null | React.Element, + /** + * Rendered at the bottom of each section. + */ + renderSectionFooter?: ?(info: { + section: SectionT, + ... + }) => null | React.Element, + /** + * Rendered at the top and bottom of each section (note this is different from + * `ItemSeparatorComponent` which is only rendered between items). These are intended to separate + * sections from the headers above and below and typically have the same highlight response as + * `ItemSeparatorComponent`. Also receives `highlighted`, `[leading/trailing][Item/Separator]`, + * and any custom props from `separators.updateProps`. + */ + SectionSeparatorComponent?: ?React.ComponentType, + /** + * Makes section headers stick to the top of the screen until the next one pushes it off. Only + * enabled by default on iOS because that is the platform standard there. + */ + stickySectionHeadersEnabled?: boolean, + onEndReached?: ?({distanceFromEnd: number, ...}) => void, +|}; + +type VirtualizedListProps = React.ElementConfig; + +export type Props = {| + ...RequiredProps, + ...OptionalProps, + ...$Diff< + VirtualizedListProps, + { + renderItem: $PropertyType, + data: $PropertyType, + ... + }, + >, +|}; +export type ScrollToLocationParamsType = {| + animated?: ?boolean, + itemIndex: number, + sectionIndex: number, + viewOffset?: number, + viewPosition?: number, +|}; + +type State = {childProps: VirtualizedListProps, ...}; + +/** + * Right now this just flattens everything into one list and uses VirtualizedList under the + * hood. The only operation that might not scale well is concatting the data arrays of all the + * sections when new props are received, which should be plenty fast for up to ~10,000 items. + */ +class VirtualizedSectionList< + SectionT: SectionBase, +> extends React.PureComponent, State> { + scrollToLocation(params: ScrollToLocationParamsType) { + let index = params.itemIndex; + for (let i = 0; i < params.sectionIndex; i++) { + index += this.props.getItemCount(this.props.sections[i].data) + 2; + } + let viewOffset = params.viewOffset || 0; + if (this._listRef == null) { + return; + } + if (params.itemIndex > 0 && this.props.stickySectionHeadersEnabled) { + const frame = this._listRef.__getFrameMetricsApprox( + index - params.itemIndex, + this._listRef.props, + ); + viewOffset += frame.length; + } + const toIndexParams = { + ...params, + viewOffset, + index, + }; + // $FlowFixMe[incompatible-use] + this._listRef.scrollToIndex(toIndexParams); + } + + getListRef(): ?React.ElementRef { + return this._listRef; + } + + render(): React.Node { + const { + ItemSeparatorComponent, // don't pass through, rendered with renderItem + SectionSeparatorComponent, + renderItem: _renderItem, + renderSectionFooter, + renderSectionHeader, + sections: _sections, + stickySectionHeadersEnabled, + ...passThroughProps + } = this.props; + + const listHeaderOffset = this.props.ListHeaderComponent ? 1 : 0; + + const stickyHeaderIndices = this.props.stickySectionHeadersEnabled + ? ([]: Array) + : undefined; + + let itemCount = 0; + for (const section of this.props.sections) { + // Track the section header indices + if (stickyHeaderIndices != null) { + stickyHeaderIndices.push(itemCount + listHeaderOffset); + } + + // Add two for the section header and footer. + itemCount += 2; + itemCount += this.props.getItemCount(section.data); + } + const renderItem = this._renderItem(itemCount); + + return ( + + this._getItem(this.props, sections, index) + } + getItemCount={() => itemCount} + onViewableItemsChanged={ + this.props.onViewableItemsChanged + ? this._onViewableItemsChanged + : undefined + } + ref={this._captureRef} + /> + ); + } + + _getItem( + props: Props, + sections: ?$ReadOnlyArray, + index: number, + ): ?Item { + if (!sections) { + return null; + } + let itemIdx = index - 1; + for (let i = 0; i < sections.length; i++) { + const section = sections[i]; + const sectionData = section.data; + const itemCount = props.getItemCount(sectionData); + if (itemIdx === -1 || itemIdx === itemCount) { + // We intend for there to be overflow by one on both ends of the list. + // This will be for headers and footers. When returning a header or footer + // item the section itself is the item. + return section; + } else if (itemIdx < itemCount) { + // If we are in the bounds of the list's data then return the item. + return props.getItem(sectionData, itemIdx); + } else { + itemIdx -= itemCount + 2; // Add two for the header and footer + } + } + return null; + } + + // $FlowFixMe[missing-local-annot] + _keyExtractor = (item: Item, index: number) => { + const info = this._subExtractor(index); + return (info && info.key) || String(index); + }; + + _subExtractor(index: number): ?{ + section: SectionT, + // Key of the section or combined key for section + item + key: string, + // Relative index within the section + index: ?number, + // True if this is the section header + header?: ?boolean, + leadingItem?: ?Item, + leadingSection?: ?SectionT, + trailingItem?: ?Item, + trailingSection?: ?SectionT, + ... + } { + let itemIndex = index; + const {getItem, getItemCount, keyExtractor, sections} = this.props; + for (let i = 0; i < sections.length; i++) { + const section = sections[i]; + const sectionData = section.data; + const key = section.key || String(i); + itemIndex -= 1; // The section adds an item for the header + if (itemIndex >= getItemCount(sectionData) + 1) { + itemIndex -= getItemCount(sectionData) + 1; // The section adds an item for the footer. + } else if (itemIndex === -1) { + return { + section, + key: key + ':header', + index: null, + header: true, + trailingSection: sections[i + 1], + }; + } else if (itemIndex === getItemCount(sectionData)) { + return { + section, + key: key + ':footer', + index: null, + header: false, + trailingSection: sections[i + 1], + }; + } else { + const extractor = + section.keyExtractor || keyExtractor || defaultKeyExtractor; + return { + section, + key: + key + ':' + extractor(getItem(sectionData, itemIndex), itemIndex), + index: itemIndex, + leadingItem: getItem(sectionData, itemIndex - 1), + leadingSection: sections[i - 1], + trailingItem: getItem(sectionData, itemIndex + 1), + trailingSection: sections[i + 1], + }; + } + } + } + + _convertViewable = (viewable: ViewToken): ?ViewToken => { + invariant(viewable.index != null, 'Received a broken ViewToken'); + const info = this._subExtractor(viewable.index); + if (!info) { + return null; + } + const keyExtractorWithNullableIndex = info.section.keyExtractor; + const keyExtractorWithNonNullableIndex = + this.props.keyExtractor || defaultKeyExtractor; + const key = + keyExtractorWithNullableIndex != null + ? keyExtractorWithNullableIndex(viewable.item, info.index) + : keyExtractorWithNonNullableIndex(viewable.item, info.index ?? 0); + + return { + ...viewable, + index: info.index, + key, + section: info.section, + }; + }; + + _onViewableItemsChanged = ({ + viewableItems, + changed, + }: { + viewableItems: Array, + changed: Array, + ... + }) => { + const onViewableItemsChanged = this.props.onViewableItemsChanged; + if (onViewableItemsChanged != null) { + onViewableItemsChanged({ + viewableItems: viewableItems + .map(this._convertViewable, this) + .filter(Boolean), + changed: changed.map(this._convertViewable, this).filter(Boolean), + }); + } + }; + + _renderItem = + (listItemCount: number): $FlowFixMe => + // eslint-disable-next-line react/no-unstable-nested-components + ({item, index}: {item: Item, index: number, ...}) => { + const info = this._subExtractor(index); + if (!info) { + return null; + } + const infoIndex = info.index; + if (infoIndex == null) { + const {section} = info; + if (info.header === true) { + const {renderSectionHeader} = this.props; + return renderSectionHeader ? renderSectionHeader({section}) : null; + } else { + const {renderSectionFooter} = this.props; + return renderSectionFooter ? renderSectionFooter({section}) : null; + } + } else { + const renderItem = info.section.renderItem || this.props.renderItem; + const SeparatorComponent = this._getSeparatorComponent( + index, + info, + listItemCount, + ); + invariant(renderItem, 'no renderItem!'); + return ( + + ); + } + }; + + _updatePropsFor = (cellKey: string, value: any) => { + const updateProps = this._updatePropsMap[cellKey]; + if (updateProps != null) { + updateProps(value); + } + }; + + _updateHighlightFor = (cellKey: string, value: boolean) => { + const updateHighlight = this._updateHighlightMap[cellKey]; + if (updateHighlight != null) { + updateHighlight(value); + } + }; + + _setUpdateHighlightFor = ( + cellKey: string, + updateHighlightFn: ?(boolean) => void, + ) => { + if (updateHighlightFn != null) { + this._updateHighlightMap[cellKey] = updateHighlightFn; + } else { + // $FlowFixMe[prop-missing] + delete this._updateHighlightFor[cellKey]; + } + }; + + _setUpdatePropsFor = (cellKey: string, updatePropsFn: ?(boolean) => void) => { + if (updatePropsFn != null) { + this._updatePropsMap[cellKey] = updatePropsFn; + } else { + delete this._updatePropsMap[cellKey]; + } + }; + + _getSeparatorComponent( + index: number, + info?: ?Object, + listItemCount: number, + ): ?React.ComponentType { + info = info || this._subExtractor(index); + if (!info) { + return null; + } + const ItemSeparatorComponent = + info.section.ItemSeparatorComponent || this.props.ItemSeparatorComponent; + const {SectionSeparatorComponent} = this.props; + const isLastItemInList = index === listItemCount - 1; + const isLastItemInSection = + info.index === this.props.getItemCount(info.section.data) - 1; + if (SectionSeparatorComponent && isLastItemInSection) { + return SectionSeparatorComponent; + } + if (ItemSeparatorComponent && !isLastItemInSection && !isLastItemInList) { + return ItemSeparatorComponent; + } + return null; + } + + _updateHighlightMap: {[string]: (boolean) => void} = {}; + _updatePropsMap: {[string]: void | (boolean => void)} = {}; + _listRef: ?React.ElementRef; + _captureRef = (ref: null | React$ElementRef>) => { + this._listRef = ref; + }; +} + +type ItemWithSeparatorCommonProps = $ReadOnly<{| + leadingItem: ?Item, + leadingSection: ?Object, + section: Object, + trailingItem: ?Item, + trailingSection: ?Object, +|}>; + +type ItemWithSeparatorProps = $ReadOnly<{| + ...ItemWithSeparatorCommonProps, + LeadingSeparatorComponent: ?React.ComponentType, + SeparatorComponent: ?React.ComponentType, + cellKey: string, + index: number, + item: Item, + setSelfHighlightCallback: ( + cellKey: string, + updateFn: ?(boolean) => void, + ) => void, + setSelfUpdatePropsCallback: ( + cellKey: string, + updateFn: ?(boolean) => void, + ) => void, + prevCellKey?: ?string, + updateHighlightFor: (prevCellKey: string, value: boolean) => void, + updatePropsFor: (prevCellKey: string, value: Object) => void, + renderItem: Function, + inverted: boolean, +|}>; + +function ItemWithSeparator(props: ItemWithSeparatorProps): React.Node { + const { + LeadingSeparatorComponent, + // this is the trailing separator and is associated with this item + SeparatorComponent, + cellKey, + prevCellKey, + setSelfHighlightCallback, + updateHighlightFor, + setSelfUpdatePropsCallback, + updatePropsFor, + item, + index, + section, + inverted, + } = props; + + const [leadingSeparatorHiglighted, setLeadingSeparatorHighlighted] = + React.useState(false); + + const [separatorHighlighted, setSeparatorHighlighted] = React.useState(false); + + const [leadingSeparatorProps, setLeadingSeparatorProps] = React.useState({ + leadingItem: props.leadingItem, + leadingSection: props.leadingSection, + section: props.section, + trailingItem: props.item, + trailingSection: props.trailingSection, + }); + const [separatorProps, setSeparatorProps] = React.useState({ + leadingItem: props.item, + leadingSection: props.leadingSection, + section: props.section, + trailingItem: props.trailingItem, + trailingSection: props.trailingSection, + }); + + React.useEffect(() => { + setSelfHighlightCallback(cellKey, setSeparatorHighlighted); + // $FlowFixMe[incompatible-call] + setSelfUpdatePropsCallback(cellKey, setSeparatorProps); + + return () => { + setSelfUpdatePropsCallback(cellKey, null); + setSelfHighlightCallback(cellKey, null); + }; + }, [ + cellKey, + setSelfHighlightCallback, + setSeparatorProps, + setSelfUpdatePropsCallback, + ]); + + const separators = { + highlight: () => { + setLeadingSeparatorHighlighted(true); + setSeparatorHighlighted(true); + if (prevCellKey != null) { + updateHighlightFor(prevCellKey, true); + } + }, + unhighlight: () => { + setLeadingSeparatorHighlighted(false); + setSeparatorHighlighted(false); + if (prevCellKey != null) { + updateHighlightFor(prevCellKey, false); + } + }, + updateProps: ( + select: 'leading' | 'trailing', + newProps: $Shape, + ) => { + if (select === 'leading') { + if (LeadingSeparatorComponent != null) { + setLeadingSeparatorProps({...leadingSeparatorProps, ...newProps}); + } else if (prevCellKey != null) { + // update the previous item's separator + updatePropsFor(prevCellKey, {...leadingSeparatorProps, ...newProps}); + } + } else if (select === 'trailing' && SeparatorComponent != null) { + setSeparatorProps({...separatorProps, ...newProps}); + } + }, + }; + const element = props.renderItem({ + item, + index, + section, + separators, + }); + const leadingSeparator = LeadingSeparatorComponent != null && ( + + ); + const separator = SeparatorComponent != null && ( + + ); + return leadingSeparator || separator ? ( + + {inverted === false ? leadingSeparator : separator} + {element} + {inverted === false ? separator : leadingSeparator} + + ) : ( + element + ); +} + +/* $FlowFixMe[class-object-subtyping] added when improving typing for this + * parameters */ +// $FlowFixMe[method-unbinding] +module.exports = (VirtualizedSectionList: React.AbstractComponent< + React.ElementConfig, + $ReadOnly<{ + getListRef: () => ?React.ElementRef, + scrollToLocation: (params: ScrollToLocationParamsType) => void, + ... + }>, +>); diff --git a/Libraries/Lists/__tests__/CellRenderMask-test.js b/packages/virtualized-lists/Lists/__tests__/CellRenderMask-test.js similarity index 100% rename from Libraries/Lists/__tests__/CellRenderMask-test.js rename to packages/virtualized-lists/Lists/__tests__/CellRenderMask-test.js diff --git a/Libraries/Lists/__tests__/FillRateHelper-test.js b/packages/virtualized-lists/Lists/__tests__/FillRateHelper-test.js similarity index 100% rename from Libraries/Lists/__tests__/FillRateHelper-test.js rename to packages/virtualized-lists/Lists/__tests__/FillRateHelper-test.js diff --git a/Libraries/Lists/__tests__/ViewabilityHelper-test.js b/packages/virtualized-lists/Lists/__tests__/ViewabilityHelper-test.js similarity index 100% rename from Libraries/Lists/__tests__/ViewabilityHelper-test.js rename to packages/virtualized-lists/Lists/__tests__/ViewabilityHelper-test.js diff --git a/Libraries/Lists/__tests__/VirtualizeUtils-test.js b/packages/virtualized-lists/Lists/__tests__/VirtualizeUtils-test.js similarity index 100% rename from Libraries/Lists/__tests__/VirtualizeUtils-test.js rename to packages/virtualized-lists/Lists/__tests__/VirtualizeUtils-test.js diff --git a/Libraries/Lists/__tests__/VirtualizedList-test.js b/packages/virtualized-lists/Lists/__tests__/VirtualizedList-test.js similarity index 99% rename from Libraries/Lists/__tests__/VirtualizedList-test.js rename to packages/virtualized-lists/Lists/__tests__/VirtualizedList-test.js index e05f68ee8708aa..45858695abbe8b 100644 --- a/Libraries/Lists/__tests__/VirtualizedList-test.js +++ b/packages/virtualized-lists/Lists/__tests__/VirtualizedList-test.js @@ -137,6 +137,20 @@ describe('VirtualizedList', () => { expect(component).toMatchSnapshot(); }); + it('scrollToEnd works with null list', () => { + const listRef = React.createRef(null); + ReactTestRenderer.create( + } + getItem={(data, index) => data[index]} + getItemCount={data => 0} + ref={listRef} + />, + ); + listRef.current.scrollToEnd(); + }); + it('renders empty list with empty component', () => { const component = ReactTestRenderer.create( ): void { + return console.log(...args); +} + +module.exports = infoLog; diff --git a/packages/virtualized-lists/index.d.ts b/packages/virtualized-lists/index.d.ts new file mode 100644 index 00000000000000..c66fc20521e439 --- /dev/null +++ b/packages/virtualized-lists/index.d.ts @@ -0,0 +1,10 @@ +/** + * 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 + */ + +export * from './Lists/VirtualizedList'; diff --git a/packages/virtualized-lists/index.js b/packages/virtualized-lists/index.js new file mode 100644 index 00000000000000..8516f7ccf73289 --- /dev/null +++ b/packages/virtualized-lists/index.js @@ -0,0 +1,57 @@ +/** + * 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 + */ + +'use strict'; + +import {keyExtractor} from './Lists/VirtualizeUtils'; + +import typeof VirtualizedList from './Lists/VirtualizedList'; +import typeof VirtualizedSectionList from './Lists/VirtualizedSectionList'; +import {typeof VirtualizedListContextResetter} from './Lists/VirtualizedListContext'; +import typeof ViewabilityHelper from './Lists/ViewabilityHelper'; +import typeof FillRateHelper from './Lists/FillRateHelper'; + +export type { + ViewToken, + ViewabilityConfig, + ViewabilityConfigCallbackPair, +} from './Lists/ViewabilityHelper'; +export type { + RenderItemProps, + RenderItemType, + Separators, +} from './Lists/VirtualizedListProps'; +export type { + Props as VirtualizedSectionListProps, + ScrollToLocationParamsType, + SectionBase, +} from './Lists/VirtualizedSectionList'; +export type {FillRateInfo} from './Lists/FillRateHelper'; + +module.exports = { + keyExtractor, + + get VirtualizedList(): VirtualizedList { + return require('./Lists/VirtualizedList'); + }, + get VirtualizedSectionList(): VirtualizedSectionList { + return require('./Lists/VirtualizedSectionList'); + }, + get VirtualizedListContextResetter(): VirtualizedListContextResetter { + const VirtualizedListContext = require('./Lists/VirtualizedListContext'); + return VirtualizedListContext.VirtualizedListContextResetter; + }, + get ViewabilityHelper(): ViewabilityHelper { + return require('./Lists/ViewabilityHelper'); + }, + get FillRateHelper(): FillRateHelper { + return require('./Lists/FillRateHelper'); + }, +}; diff --git a/packages/virtualized-lists/package.json b/packages/virtualized-lists/package.json new file mode 100644 index 00000000000000..8b19cd2c199f7a --- /dev/null +++ b/packages/virtualized-lists/package.json @@ -0,0 +1,21 @@ +{ + "name": "@react-native/virtualized-lists", + "version": "0.72.0", + "description": "Virtualized lists for React Native.", + "repository": { + "type": "git", + "url": "git@github.com:facebook/react-native.git", + "directory": "packages/virtualized-lists" + }, + "license": "MIT", + "dependencies": { + "invariant": "^2.2.4" + }, + "devDependencies": { + "react-test-renderer": "18.2.0" + }, + "peerDependencies": { + "react-native": "*", + "react-test-renderer": "18.2.0" + } +} diff --git a/repo-config/package.json b/repo-config/package.json index 5377cf8187ccb2..82002581f821e4 100644 --- a/repo-config/package.json +++ b/repo-config/package.json @@ -38,7 +38,7 @@ "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-native": "^4.0.0", "eslint-plugin-relay": "^1.8.3", - "flow-bin": "^0.198.2", + "flow-bin": "^0.199.1", "inquirer": "^7.1.0", "jest": "^29.2.1", "jest-junit": "^10.0.0", diff --git a/scripts/__tests__/version-utils-test.js b/scripts/__tests__/version-utils-test.js index da5b67402a4810..ad6d958ebff313 100644 --- a/scripts/__tests__/version-utils-test.js +++ b/scripts/__tests__/version-utils-test.js @@ -141,15 +141,6 @@ describe('version-utils', () => { expect(prerelease).toBe('rc.4'); }); - it('should reject pre-release version with patch != 0', () => { - function testInvalidVersion() { - parseVersion('0.66.3-rc.4', 'release'); - } - expect(testInvalidVersion).toThrowErrorMatchingInlineSnapshot( - `"Version 0.66.3-rc.4 is not valid for Release"`, - ); - }); - it('should reject pre-release version from tag with random prerelease pattern', () => { function testInvalidVersion() { parseVersion('v0.66.0-something_invalid', 'release'); @@ -233,15 +224,6 @@ describe('version-utils', () => { expect(prerelease).toBe('rc.0'); }); - it('should reject dryrun with prerelease . version with patch different from 0', () => { - function testInvalidFunction() { - parseVersion('0.20.3-rc.0', 'dry-run'); - } - expect(testInvalidFunction).toThrowErrorMatchingInlineSnapshot( - `"Version 0.20.3-rc.0 is not valid for dry-runs"`, - ); - }); - it('should parse dryrun with prerelease - version', () => { const {version, major, minor, patch, prerelease} = parseVersion( '0.20.0-rc-0', @@ -254,15 +236,6 @@ describe('version-utils', () => { expect(prerelease).toBe('rc-0'); }); - it('should reject dryrun with prerelease - version with patch different from 0', () => { - function testInvalidFunction() { - parseVersion('0.20.3-rc-0', 'dry-run'); - } - expect(testInvalidFunction).toThrowErrorMatchingInlineSnapshot( - `"Version 0.20.3-rc-0 is not valid for dry-runs"`, - ); - }); - it('should parse dryrun with main version', () => { const {version, major, minor, patch, prerelease} = parseVersion( '1000.0.0', diff --git a/scripts/codegen/generate-artifacts-executor.js b/scripts/codegen/generate-artifacts-executor.js index 757ce492c5ae14..38a2b8f22493c7 100644 --- a/scripts/codegen/generate-artifacts-executor.js +++ b/scripts/codegen/generate-artifacts-executor.js @@ -22,9 +22,9 @@ const os = require('os'); const path = require('path'); const RN_ROOT = path.join(__dirname, '../..'); - +const CODEGEN_DEPENDENCY_NAME = '@react-native/codegen'; const CODEGEN_REPO_PATH = `${RN_ROOT}/packages/react-native-codegen`; -const CODEGEN_NPM_PATH = `${RN_ROOT}/../@react-native/codegen`; +const CODEGEN_NPM_PATH = `${RN_ROOT}/../${CODEGEN_DEPENDENCY_NAME}`; const CORE_LIBRARIES = new Set(['rncore', 'FBReactNativeSpec']); const REACT_NATIVE_DEPENDENCY_NAME = 'react-native'; @@ -293,7 +293,7 @@ function getCodeGenCliPath() { } else if (fs.existsSync(CODEGEN_NPM_PATH)) { codegenCliPath = CODEGEN_NPM_PATH; } else { - throw "error: Could not determine react-native-codegen location. Try running 'yarn install' or 'npm install' in your project root."; + throw `error: Could not determine ${CODEGEN_DEPENDENCY_NAME} location. Try running 'yarn install' or 'npm install' in your project root.`; } return codegenCliPath; } diff --git a/scripts/find-node-for-xcode.sh b/scripts/find-node-for-xcode.sh index 0a49e25ce6d0b8..e928cd8e31be52 100644 --- a/scripts/find-node-for-xcode.sh +++ b/scripts/find-node-for-xcode.sh @@ -58,7 +58,10 @@ if [[ ! -x node && -d ${HOME}/.anyenv/bin ]]; then fi # Set up asdf-vm if present -if [[ -f "$HOME/.asdf/asdf.sh" ]]; then +if [[ -f "$ASDF_DIR/asdf.sh" ]]; then + # shellcheck source=/dev/null + . "$ASDF_DIR/asdf.sh" +elif [[ -f "$HOME/.asdf/asdf.sh" ]]; then # shellcheck source=/dev/null . "$HOME/.asdf/asdf.sh" elif [[ -x "$(command -v brew)" && -f "$(brew --prefix asdf)/asdf.sh" ]]; then diff --git a/scripts/monorepo/find-and-publish-all-bumped-packages.js b/scripts/monorepo/find-and-publish-all-bumped-packages.js index 17e06596c3af2b..f700f5c9c9889d 100644 --- a/scripts/monorepo/find-and-publish-all-bumped-packages.js +++ b/scripts/monorepo/find-and-publish-all-bumped-packages.js @@ -103,15 +103,15 @@ const findAndPublishAllBumpedPackages = () => { const npmOTPFlag = NPM_CONFIG_OTP ? `--otp ${NPM_CONFIG_OTP}` : ''; - const {stderr} = spawnSync('npm', ['publish', `${npmOTPFlag}`], { + const {status, stderr} = spawnSync('npm', ['publish', `${npmOTPFlag}`], { cwd: packageAbsolutePath, shell: true, stdio: 'pipe', encoding: 'utf-8', }); - if (stderr) { + if (status !== 0) { console.log( - `\u274c Failed to publish version ${nextVersion} of ${packageManifest.name}:`, + `\u274c Failed to publish version ${nextVersion} of ${packageManifest.name}. npm publish exited with code ${status}:`, ); console.log(stderr); diff --git a/scripts/react-native-xcode.sh b/scripts/react-native-xcode.sh index 30a5ac2227afa4..54a4eb9de34262 100755 --- a/scripts/react-native-xcode.sh +++ b/scripts/react-native-xcode.sh @@ -58,9 +58,8 @@ esac # Path to react-native folder inside node_modules REACT_NATIVE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" -# The project should be located next to where react-native is installed -# in node_modules. -PROJECT_ROOT=${PROJECT_ROOT:-"$REACT_NATIVE_DIR/../.."} +# Most projects have their project root, one level up from their Xcode project dir (the "ios" directory) +PROJECT_ROOT=${PROJECT_ROOT:-"$PROJECT_DIR/.."} cd "$PROJECT_ROOT" || exit diff --git a/scripts/version-utils.js b/scripts/version-utils.js index 661eccb97c733f..826050ac0d0f4a 100644 --- a/scripts/version-utils.js +++ b/scripts/version-utils.js @@ -131,7 +131,7 @@ function isStablePrerelease(version) { return ( version.major === '0' && version.minor !== '0' && - version.patch === '0' && + version.patch.match(/^\d+$/) && version.prerelease != null && (version.prerelease.startsWith('rc.') || version.prerelease.startsWith('rc-') || diff --git a/template/__tests__/App.test.tsx b/template/__tests__/App.test.tsx index 178476699b6055..3413ac1c403683 100644 --- a/template/__tests__/App.test.tsx +++ b/template/__tests__/App.test.tsx @@ -6,6 +6,9 @@ import 'react-native'; import React from 'react'; import App from '../App'; +// Note: import explicitly to use the types shiped with jest. +import {it} from '@jest/globals'; + // Note: test renderer must be required after react-native. import renderer from 'react-test-renderer'; diff --git a/template/android/build.gradle b/template/android/build.gradle index 67d887b03078b6..34ea71819406f6 100644 --- a/template/android/build.gradle +++ b/template/android/build.gradle @@ -15,7 +15,7 @@ buildscript { mavenCentral() } dependencies { - classpath("com.android.tools.build:gradle:7.3.1") + classpath("com.android.tools.build:gradle") classpath("com.facebook.react:react-native-gradle-plugin") } } diff --git a/template/package.json b/template/package.json index 3ac504d528f1e8..cf3b10d19e9e0e 100644 --- a/template/package.json +++ b/template/package.json @@ -19,7 +19,6 @@ "@babel/runtime": "^7.12.5", "@react-native/eslint-config": "^0.72.1", "@tsconfig/react-native": "^2.0.2", - "@types/jest": "^29.2.1", "@types/react": "^18.0.24", "@types/react-test-renderer": "^18.0.0", "babel-jest": "^29.2.1", diff --git a/tools/eslint/rules/sort-imports.js b/tools/eslint/rules/sort-imports.js index 42312a93c1e47e..0c3c2f50e080e9 100644 --- a/tools/eslint/rules/sort-imports.js +++ b/tools/eslint/rules/sort-imports.js @@ -6,7 +6,7 @@ * * To regenerate this file, please run this command on Meta's monorepo: * @codegen-command : xplat/js/tools/sort-imports/scripts/build.sh - * @generated SignedSource<> + * @generated SignedSource<<7b94a136bcb0a75c0ed8a3e4fea96e2b>> * @nolint */ -"use strict";function e(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}function t(e){var t=e.default;if("function"==typeof t){var n=function(){return t.apply(this,arguments)};n.prototype=t.prototype}else n={};return Object.defineProperty(n,"__esModule",{value:!0}),Object.keys(e).forEach((function(t){var r=Object.getOwnPropertyDescriptor(e,t);Object.defineProperty(n,t,r.get?r:{enumerable:!0,get:function(){return e[t]}})})),n}const n=e(require("path")).default,r=__dirname.split(n.sep).includes("xplat");function i(e){if(("Literal"===e.type||"JSXText"===e.type)&&"string"==typeof e.value)return e.value;if("BinaryExpression"===e.type&&"+"===e.operator){const t=i(e.left),n=i(e.right);if(null!=t&&null!=n)return t+n}return null}function o(e){if("Identifier"===e.type)return e.name;if("ThisExpression"===e.type)return"this";if("MemberExpression"===e.type){const t=o(e.object),n=e.computed?i(e.property):o(e.property);if(null!=t&&null!=n)return t+"."+n}else if("TypeCastExpression"===e.type)return o(e.expression);return null}function a(e){return e.callee?o(e.callee):null}function l(e,t,n){const r=e.getSourceCode().getText(),i=function(e,t){if(t.line<1)throw new RangeError("Line number "+t.line+" is before the start of file");const n=/\r\n|\r|\n|\u2028|\u2029/g;let r={index:0};for(let i=1;i=e.length)throw new RangeError("computed offset "+t+" is past the end of file");const n=/\r\n|\r|\n|\u2028|\u2029/g;let r,i={index:0},o=0;do{r=i,i=n.exec(e),++o}while(i&&i.index"string"==typeof e&&e.charCodeAt(0)>=97,c=e=>"string"==typeof e&&e.charCodeAt(0)<=90;function p(e){return null!=e&&"VariableDeclaration"===e.type&&"Program"===e.parent.type&&1===e.declarations.length&&null!=e.declarations[0].init&&m(e.declarations[0].init)}function f(e){return null!=e&&"VariableDeclarator"===e.type&&"VariableDeclaration"===e.parent.type&&"Program"===e.parent.parent.type&&1===e.parent.declarations.length&&m(e.init)}function m(e){return null!=e&&(d(e)||y(e)||h(e))}function g(e){return null!=e&&"CallExpression"===e.type&&e.callee&&"Identifier"===e.callee.type&&"requireNUX"===e.callee.name&&2===e.arguments.length&&"Literal"===e.arguments[0].type}function d(e){return"CallExpression"===e.type&&e.callee&&"Identifier"===e.callee.type&&"require"===e.callee.name&&1===e.arguments.length&&"Literal"===e.arguments[0].type}function y(e){return"CallExpression"===e.type&&"Identifier"===e.callee.type&&"requireDeferred"===e.callee.name&&1===e.arguments.length&&"Literal"===e.arguments[0].type&&"string"==typeof e.arguments[0].value}function h(e){return"CallExpression"===e.type&&"Identifier"===e.callee.type&&"requireDeferredForDisplay"===e.callee.name&&1===e.arguments.length&&"Literal"===e.arguments[0].type&&"string"==typeof e.arguments[0].value}function x(e){return"ImportDeclaration"===e.type&&(null==e.importKind||"value"===e.importKind)}function b(e){return"ImportDeclaration"===e.type&&("type"===e.importKind||"typeof"===e.importKind)}function C(e){return x(e)||b(e)}function S(e){return null!=e&&"CallExpression"===e.type&&e.callee&&"Identifier"===e.callee.type&&"JSResource"===e.callee.name&&1===e.arguments.length&&"Literal"===e.arguments[0].type}function v(e){return null!=e&&"CallExpression"===e.type&&e.callee&&"Identifier"===e.callee.type&&"JSResourceForInteraction"===e.callee.name&&2===e.arguments.length&&"Literal"===e.arguments[0].type}function E(e){return null!=e&&"CallExpression"===e.type&&"Identifier"===e.callee.type&&"ClientJSResource"===e.callee.name&&1===e.arguments.length&&"Literal"===e.arguments[0].type&&"string"==typeof e.arguments[0].value}function I(e){if(null==e||"CallExpression"!==e.type||null==e.callee)return!1;let t;return"Identifier"===e.callee.type&&(t=e.callee),"MemberExpression"===e.callee.type&&"Identifier"===e.callee.object.type&&(t=e.callee.object),null!=t&&"requireCond"===t.name&&e.arguments.length>0}function T(e){return 0===e.indexOf("m#")?e.substring(2):e}function R(e,t,n=1){return"CallExpression"!==e.type||e.arguments.length!==n||null!=t&&"string"==typeof t&&a(e)!==t||"Literal"!==e.arguments[0].type||"string"!=typeof e.arguments[0].value?null:T(e.arguments[0].value)}function D(e,t,n){const r=e.arguments;return I(e)?3!==r.length?null:(null==t||r[0]&&"Literal"===r[0].type&&r[0].value===t)&&(null==n||r[1]&&"Literal"===r[1].type&&r[1].value===n)?r[2]&&"ObjectExpression"===r[2].type?r[2].properties.reduce(((e,t)=>{if("Property"===t.type&&"Literal"===t.value.type){let n;if("Identifier"===t.key.type)n=t.key.name;else{if("Literal"!==t.key.type)return e;n=String(t.key.value)}e[n]="string"==typeof t.value.value?T(t.value.value):null}return e}),{}):r[2]&&"Literal"===r[2].type&&"string"==typeof r[2].value?T(r[2].value):null:null:null}function w(e){return R(e,"JSResource")}function N(e){return null==e?null:m(e)?"string"!=typeof e.arguments[0].value?null:T(e.arguments[0].value):null}function q(e,t){const n=e.getSourceCode().ast.body.find((e=>"VariableDeclaration"===e.type&&1===e.declarations.length&&"VariableDeclarator"===e.declarations[0].type&&null!=e.declarations[0].init&&N(e.declarations[0].init)===t));return n||null}function k(e){let t=e;for(;"TypeCastExpression"===t.type;)t=t.expression;return t}function L(e){if("value"!==e.importKind)return!0;return e.specifiers.every((e=>"ImportSpecifier"===e.type&&("type"===e.importKind||"typeof"===e.importKind)))}function O(e,t){const n=e.getSourceCode().ast.body.find((e=>"ImportDeclaration"===e.type&&e.source.value===t&&!L(e)));return n||null}var P={asAnyKindOfRequireCall:function(e){return m(e)?e:null},asAnyKindOfRequireVariableDeclaration:function(e){return p(e)?e:null},asAnyKindOfRequireVariableDeclarator:function(e){return f(e)?e:null},getAnyRequiredModuleName:function(e,t=Object.freeze({})){const n=N(e)||w(e)||function(e){return R(e,"JSResourceForInteraction",2)}(e)||function(e){if(!g(e))return null;if(2!==e.arguments.length)return null;if("string"!=typeof e.arguments[1].value)return null;return T(e.arguments[1].value)}(e);return null!=n?n:D(e,t.condType,t.condition)},getBaseNode:function(e){let t=e;for(;"MemberExpression"===t.type;)t=t.object;return t},getBinding:s,getBootloadedModuleNames:function(e){return"ExpressionStatement"===e.type&&e.expression&&"CallExpression"===e.expression.type&&e.expression.callee&&"MemberExpression"===e.expression.callee.type&&e.expression.callee.object&&"Bootloader"===e.expression.callee.object.name&&e.expression.callee.property&&"loadModules"===e.expression.callee.property.name&&e.expression.arguments.length>0&&"ArrayExpression"===e.expression.arguments[0].type&&e.expression.arguments[0].elements.length>0?e.expression.arguments[0].elements.map((e=>"Literal"===e.type&&"string"==typeof e.value?e.value:null)).filter(Boolean):null},getCalleeName:a,getConstantStringExpression:i,getCurrentClassName:function(e){const t=e.getAncestors().find((e=>"ClassDeclaration"===e.type));return t&&"ClassDeclaration"===t.type&&null!=t.id?t.id.name:null},getEnglishForNth:function(e){return["first","second","third","fourth","fifth","sixth"][e]},getFullyQualifiedIdentifier:o,getJSResourceModuleName:w,getJSXMemberOrNamespaceRoot:function(e){let t=e;for(;"JSXIdentifier"!==t.type;)if("JSXMemberExpression"===t.type)t=t.object;else{if("JSXNamespacedName"!==t.type)throw new Error("unexpected "+t.type);t=t.namespace}return t},getLocOffset:function(e,t,n){return l(e,t.loc.start,n)},getLocOffsetOfLoc:l,getName:function(e){const t=k(e);return"Identifier"===t.type?t.name:"Literal"===t.type?String(t.value):null},getObjectPropertyName:function(e){if("Property"!==e.type&&"PropertyDefinition"!==e.type&&"MethodDefinition"!==e.type)return null;const t=e.key;return"Identifier"!==t.type||e.computed?function(e){switch(e.type){case"Literal":switch(e.literalType){case"bigint":return e.bigint;case"null":return"null";case"regexp":return`/${e.regex.pattern}/${e.regex.flags}`;default:return String(e.value)}case"TemplateLiteral":if(0===e.expressions.length&&1===e.quasis.length)return e.quasis[0].value.cooked}return null}(t):t.name},getParamComments:function(e,t){return t.params.map((function(t){const n=e.getSourceCode().getCommentsBefore(t);return n[n.length-1]}))},getPropertyName:function(e){return"MemberExpression"!==e.type?null:e.computed?i(e.property):"Identifier"!==e.property.type?null:e.property.name},getPropTokens:function(e,t){const n=e.getSourceCode().getTokens(t),r=[];return n.forEach(((e,t,n)=>{"JSXIdentifier"===e.type&&"Punctuator"===n[t+1].type&&"="===n[t+1].value&&r.push(e)})),r},getRequireCondModules:D,getRequireModuleName:N,getRequireModuleNode:q,getReturnComment:function(e,t){return e.getSourceCode().getCommentsBefore(t.body)[0]},getValueImportNode:O,hasValueImport:function(e){return e.getSourceCode().ast.body.some((e=>"ImportDeclaration"===e.type&&!L(e)))},getVariable:function(e,t){let n=t;for(;n;){const t=n.set.get(e);if(t)return t;n=n.upper}return null},insertRequireStatement:function(e,t,n,r=""){if(""===n)throw new Error("Name must be a string with length larger than 0");const i=`const ${n} = require('${n}${r}');`,o=[];e.getSourceCode().ast.body.forEach((e=>{if("VariableDeclaration"===e.type&&1===e.declarations.length&&"VariableDeclarator"===e.declarations[0].type&&e.declarations[0].init){const t=N(e.declarations[0].init);null!=t&&o.push({name:t,node:e})}}));const a=o.find((e=>e.name>=n));if(a){if(a.name.replace(r,"")===n)return[];const e=o[0];if(u(a.name)&&c(n)){if(e!==a){const e=a.node.range[0];return[t.removeRange([e-1,e-1]),t.insertTextBefore(a.node,i+"\n\n")]}return[t.insertTextBefore(a.node,i+"\n\n")]}return[t.insertTextBefore(a.node,i+"\n")]}if(o.length>0){const e=o[o.length-1],r=c(e.name)&&u(n)?"\n":"";return[t.insertTextAfter(e.node,"\n"+i+r)]}{const n=e.getSourceCode().ast.body,r=n[0];return"ExpressionStatement"===r.type&&"Literal"===r.expression.type&&"use strict"===r.expression.value?[t.insertTextBefore(n[1],i+"\n")]:[t.insertTextBefore(n[0],i+"\n")]}},insertValueImportStatement:function(e,t,n,r=""){if(""===n)throw new Error("Name must be a string with length larger than 0");const i=`import ${n} from '${n}${r}';`,o=[];e.getSourceCode().ast.body.forEach((e=>{if(x(e)){const t=function(e){if(m(e))return"string"!=typeof e.arguments[0].value?null:T(e.arguments[0].value);if(C(e))return e.source.value;return null}(e);null!=t&&o.push({name:t,node:e})}}));const a=o.find((e=>e.name>=n));if(a){if(a.name.replace(r,"")===n)return[];const e=o[0];if(u(a.name)&&c(n)){if(e!==a){const e=a.node.range[0];return[t.removeRange([e-1,e-1]),t.insertTextBefore(a.node,i+"\n\n")]}return[t.insertTextBefore(a.node,i+"\n\n")]}return[t.insertTextBefore(a.node,i+"\n")]}if(o.length>0){const e=o[o.length-1],r=c(e.name)&&u(n)?"\n":"";return[t.insertTextAfter(e.node,"\n"+i+r)]}{const n=e.getSourceCode().ast.body,r=n[0];return"ExpressionStatement"===r.type&&"Literal"===r.expression.type&&"use strict"===r.expression.value?[t.insertTextBefore(n[1],i+"\n")]:[t.insertTextBefore(n[0],i+"\n")]}},isAnyKindOfImport:C,isAnyKindOfModuleCall:function(e){return m(e)||I(e)||S(e)||v(e)||E(e)||g(e)},isAnyKindOfRequireCall:m,isAnyKindOfRequireVariableDeclaration:p,isAnyKindOfRequireVariableDeclarator:f,isClientJSResource:E,isFbSourceRepo:r,isGraphQLTemplate:function(e){return"Identifier"===e.tag.type&&"graphql"===e.tag.name&&1===e.quasi.quasis.length},isInsideMethod:function(e,t){return e.getAncestors().some((e=>"MethodDefinition"===e.type&&"Identifier"===e.key.type&&e.key.name===t))},isJSResource:S,isJSResourceForInteraction:v,isModuleRef:function(e){return"Literal"===e.type&&"string"==typeof e.value&&e.value.startsWith("m#")},isOnlyTypeImport:L,isOnlyTypeExport:function(e){return"type"===e.exportKind},isReferenced:function(e){const t=e.parent;switch(t.type){case"MemberExpression":case"JSXMemberExpression":return t.property===e&&!0===t.computed||t.object===e;case"MetaProperty":case"ImportDefaultSpecifier":case"ImportNamespaceSpecifier":case"ImportSpecifier":case"LabeledStatement":case"RestElement":case"ObjectPattern":case"ArrayPattern":return!1;case"Property":case"MethodDefinition":return t.key===e&&t.computed;case"VariableDeclarator":case"ClassDeclaration":case"ClassExpression":return t.id!==e;case"ArrowFunctionExpression":case"FunctionDeclaration":case"FunctionExpression":for(let n=0;ne.writeExpr));return null!=i?i.writeExpr:null},stripModuleRef:T,uncast:k};var j=t(Object.freeze({__proto__:null,isCommaOrSemiToken:function(e){return"Punctuator"===e.type&&(","===e.value||";"===e.value)}}));const{isCommaOrSemiToken:B}=j;var F={getInlineComments:function(e,t,n=B){const r=e.ast.comments.filter((e=>e.loc.start.line===t.loc.end.line&&e.range[0]>t.range[1])).sort(((e,t)=>e.range[0]-t.range[0])),i=[];let o=t;for(const t of r){const r=e.getTokensBetween(o,t);if(r.length>0){if(!n)break;if(!r.every(n))break}i.push(t),o=t}return i},getLeadingComments:function(e,t,n){const r=e.getCommentsBefore(t),i=[];let o=t;for(let t=r.length-1;t>=0;t-=1){const a=r[t];if(a===n)break;if(a.loc.end.line===o.loc.start.line){i.unshift(a),o=a;continue}if(a.loc.end.line!==o.loc.start.line-1)break;const l=e.getTokenBefore(a);if(l&&l.loc.end.line===a.loc.start.line)break;i.unshift(a),o=a}return i}};var M=function(e){return e.getSourceCode().ast.docblock?.comment};const{getInlineComments:A,getLeadingComments:V}=F,{isCommaOrSemiToken:$}=j;function K(e){return"@"===e[0]||":"===e[0]}const J=/\d{1,3}(\.\d+)?%/;function _(e){switch(typeof e){case"number":return{isSafeNumericString:!0,isPercentage:!1};case"boolean":return{isSafeNumericString:!1,isPercentage:!1}}return isNaN(e)||isNaN(parseFloat(e))?J.test(e)?{isSafeNumericString:!0,isPercentage:!0}:{isSafeNumericString:!1,isPercentage:!1}:{isSafeNumericString:!0,isPercentage:!1}}function X(e){return e.reduce((([e,t],[n,r])=>[Math.min(e,n),Math.max(t,r)]),[Number.MAX_SAFE_INTEGER,0])}var U={compareNames:function(e,t,n=!1){if("number"==typeof e&&"number"==typeof t)return e-t;const r=String(e),i=String(t);if(""===r&&""!==i)return-1;if(""!==r&&""===i)return 1;if(""===r&&""===i)return 0;const{isSafeNumericString:o,isPercentage:a}=_(r),{isSafeNumericString:l,isPercentage:s}=_(i);if(o&&l){const e=Number.parseFloat(r),t=Number.parseFloat(i);if(e===t){if(!a&&s)return-1;if(a&&!s)return 1}return e-t}if(n){const e=K(r),t=K(i);if(!e&&t)return-1;if(e&&!t)return 1}const u=o||r[0].toLowerCase()===r[0].toUpperCase(),c=l||i[0].toLowerCase()===i[0].toUpperCase();if(!u&&c)return 1;if(u&&!c)return-1;if(!u&&!c){const e=r[0].toLowerCase()===r[0],t=i[0].toLowerCase()===i[0];if(!e&&t)return-1;if(e&&!t)return 1}return r.localeCompare(i,"en",{caseFirst:"upper",sensitivity:"base"})},getEncompassingRange:X,getNodeTextWithComments:function(e,t,n,{shouldIncludeNextTokenInRange:r=$,ensureTextFollowsNode:i,inlineCommentIgnoreToken:o}={}){const a=A(e,t,o),l=[...V(e,t,n).map((({range:e})=>e)),t.range,...a.map((({range:e})=>e))],s=e.getTokenAfter(t);s&&!0===r?.(s)&&l.push(s.range);const u=X(l);let c=e.text.slice(u[0],u[1]);const p=t.range[1]-u[0];if(null!=i){e.getTokenAfter(t)?.value!==i&&(c=c.slice(0,p)+i+c.slice(p))}return{range:u,text:c}},isComma:function(e){return"Punctuator"===e.type&&","===e.value}};const z=P,{getInlineComments:G,getLeadingComments:Q}=F,W=M,{compareNames:H}=U,Y=0,Z={default:1,namespace:2,named:3},ee={default:4,namespace:5,named:6},te={default:7,namespace:8,named:9},ne=0,re=1,ie=2,oe=3,ae=99;var le={meta:{fixable:"code",messages:{incorrectOrder:"Requires should be sorted alphabetically"}},create(e){const t=e.getSourceCode(),n=function(e){const t=W(e);if(null!=t)return t;const n=e.getSourceCode().ast,r=n.body.length>0?n.body[0]:n,i=e.getSourceCode().getCommentsBefore(r)[0];return i&&"Block"===i.type?i:null}(e);if(n&&(n.value.includes("* @generated")||n.value.includes("* @partially-generated")))return{};const r=Object.freeze({typeImport:{priority:10,uppercase:[],lowercase:[],tiebreakFunction:s},valueImport:{priority:20,uppercase:[],lowercase:[],tiebreakFunction:s},requiresUsedByOtherRequires:{priority:30,uppercase:[],lowercase:[],tiebreakFunction:u},require:{priority:40,uppercase:[],lowercase:[],tiebreakFunction:u}}),i=[];let o=null,a=null;const l=new Set;return{Program(n){for(const e of n.body)switch(e.type){case"ImportDeclaration":if("type"===e.importKind||"typeof"===e.importKind)g(r.typeImport,e,e.source.value,!0);else{const n=t.getLastToken(e.source,(e=>"from"===e.value));0===e.specifiers.length&&null==n?d(e):g(r.valueImport,e,e.source.value)}break;case"VariableDeclaration":{const t=e.declarations[0]?.init;if(1!==e.declarations.length||null==t){d(e);break}f(t,e);break}default:d(e)}const s=[];for(const e of Object.keys(r)){const t=r[e];s.push({priority:t.priority,nodes:t.uppercase.sort(((e,n)=>c(e,n,t.tiebreakFunction)))}),s.push({priority:t.priority+5,nodes:t.lowercase.sort(((e,n)=>c(e,n,t.tiebreakFunction)))})}function u(e){return[e.leadingComments.length?e.leadingComments.map((e=>t.getText(e))).join("\n")+"\n":"",e.inlineComments.length?" "+e.inlineComments.map((e=>t.getText(e))).join(" "):""]}const p=s.filter((e=>0!==e.nodes.length)).sort(((e,t)=>e.priority-t.priority)).map((e=>e.nodes.map((e=>{const[n,r]=u(e),i=function(e,t){const n=t.node,r=e.getText(n),i=(()=>{if("ImportDeclaration"===n.type&&null!=n.specifiers.find((e=>"ImportSpecifier"===e.type))){const t=e.getFirstToken(n,(e=>"Punctuator"===e.type&&"{"===e.value)),r=e.getFirstToken(n,(e=>"Punctuator"===e.type&&"}"===e.value));return null==t||null==r?null:e.getText().substring(t.range[0],r.range[1])}if("VariableDeclaration"===n.type&&"ObjectPattern"===n.declarations[0].id.type){const t=n.declarations[0].id.typeAnnotation,r=e.getText(n.declarations[0].id);return t?r.substr(0,t.range[0]-n.declarations[0].id.range[0]):r}return null})();if(null==i)return r;let o=[],a=null;"ImportDeclaration"===n.type?o=n.specifiers.map((t=>"ImportDefaultSpecifier"===t.type||"ImportNamespaceSpecifier"===t.type?null:{leadingComments:e.getCommentsBefore(t),name:t.imported.name,node:t})).filter(Boolean):"VariableDeclaration"===n.type&&"ObjectPattern"===n.declarations[0].id.type&&(o=n.declarations[0].id.properties.map((t=>{if("ExperimentalRestProperty"===t.type||"RestElement"===t.type)return a=t,null;const n=t.key,r="Literal"===n.type?String(n.value):"Identifier"===n.type?t.computed?null:n.name:null;return null==r?null:{leadingComments:e.getCommentsBefore(t),name:r,node:t}})).filter(Boolean));if(o.length<=1)return r;const l=i.indexOf("\n")>=0,s=o.sort(((e,t)=>H(e.name,t.name))).map((e=>e.node));null!=a&&s.push(a);const u=s.map((t=>{const n=e.getCommentsBefore(t).map((t=>e.getText(t))),r=n.length?n.join(""):"";return l?(r?" "+r+"\n":"")+" "+e.getText(t):(r?r+" ":"")+e.getText(t)})),c=(()=>{const t=[];if("ImportDeclaration"===n.type){if(t.push(...e.getCommentsBefore(n.source)),l&&null!=n.specifiers.find((e=>"ImportSpecifier"===e.type))){const r=e.getTokenBefore(n.source,(e=>"Punctuator"===e.type&&"}"===e.value));null!=r&&t.push(...e.getCommentsBefore(r))}}else if("VariableDeclaration"===n.type&&"ObjectPattern"===n.declarations[0].id.type){const r=e.getLastToken(n.declarations[0].id);null!=r&&t.push(...e.getCommentsBefore(r))}return t})(),p=l&&c.length?c.map((t=>" "+e.getText(t))).join("\n")+"\n":"",f=l?"\n"+u.map((e=>e.includes("...")?`${e}\n`:`${e},\n`)).join("")+p:u.join(", ");return r.replace(i,`{${f}}`)}(t,e);return n+i+r})).join("\n"))).join("\n\n"),m=o;if(null==m||null==a)return;const y=m.leadingComments.length?m.leadingComments[0].range[0]:m.node.range[0],h=a.inlineComments.length>0?a.inlineComments[a.inlineComments.length-1].range[1]:a.node.range[1];t.getText(m.node,m.node.range[0]-y,h-m.node.range[1])!==p&&e.report({node:m.node,messageId:"incorrectOrder",fix(e){const n=i.filter((({node:e})=>e.range[0]>=y&&e.range[1]<=h)).map((e=>{const[n,r]=u(e),i=t.getText(e.node);return{range:e.node.range,text:n+i+r}})).flat().concat(t.getAllComments().filter((e=>e.range[0]>=y&&e.range[1]<=h&&!l.has(e))).map((e=>({range:e.range,text:t.getText(e)})))).sort(((e,t)=>e.range[0]-t.range[0]||e.range[1]-t.range[1])).map((({text:e})=>e)).join("\n");return e.replaceTextRange([y,h],[p,n].filter(Boolean).join("\n\n"))}})}};function s(e){if(0===e.specifiers.length)return Y;const t=(()=>{switch(e.importKind){default:case"value":return Z;case"type":return ee;case"typeof":return te}})();return e.specifiers.find((e=>"ImportDefaultSpecifier"===e.type))?t.default:e.specifiers.find((e=>"ImportNamespaceSpecifier"===e.type))?t.namespace:t.named}function u(e){if("ExpressionStatement"===e.type)return ne;switch(e.declarations[0].id.type){case"Identifier":return re;case"ObjectPattern":return ie;case"ArrayPattern":return oe}return ae}function c(e,t,n){const r=H(e.moduleName,t.moduleName);if(0!==r)return r;const i=n(e.node)-n(t.node);return 0!==i?i:e.node.loc.start.line-t.node.loc.start.line}function p(e,t){if(null==e)throw new Error("Missing required module name");return null!=t?`${e}_${t}`:e}function f(e,n,i){const o=z.getRequireModuleName(e);if(z.isRequire(e)){const e=p(o,i);g("requireCond"===e||"requireDeferred"===e||"requireDeferredForDisplay"===e?r.requiresUsedByOtherRequires:r.require,n,p(o,i))}else if(z.isRequireDeferred(e)||z.isRequireDeferredForDisplay(e))g(r.require,n,p(o,i));else{if(z.isRequireCond(e)){if("VariableDeclaration"===n.type){const e=t.getText(n.declarations[0].id);return void g(r.require,n,p(e,i))}}else{if("MemberExpression"===e.type)return void f(e.object,n,p(t.getText(e.property),i));if("CallExpression"===e.type)return void f(e.callee,n,i)}d(n)}}function m(e){e.leadingComments.forEach((e=>l.add(e))),e.inlineComments.forEach((e=>l.add(e)));t.getCommentsInside(e.node).forEach((e=>l.add(e)))}function g(e,r,i,l=!1){const s={inlineComments:G(t,r),leadingComments:Q(t,r,n),moduleName:i,node:r};if(l)e.uppercase.push(s);else{const t=i[0]||"";t.toLowerCase()===t?e.lowercase.push(s):e.uppercase.push(s)}null==o&&(o=s),a=s,m(s)}function d(e){const r={inlineComments:G(t,e),leadingComments:Q(t,e,n),node:e};i.push(r),m(r)}}};const se=le;var ue={...se,create:e=>e.getSourceCode().getText().includes("@generated SignedSource<<")?{}:se.create(e)};module.exports=ue; +"use strict";function e(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}function t(e){var t=e.default;if("function"==typeof t){var n=function(){return t.apply(this,arguments)};n.prototype=t.prototype}else n={};return Object.defineProperty(n,"__esModule",{value:!0}),Object.keys(e).forEach((function(t){var r=Object.getOwnPropertyDescriptor(e,t);Object.defineProperty(n,t,r.get?r:{enumerable:!0,get:function(){return e[t]}})})),n}const n=e(require("path")).default,r=__dirname.split(n.sep).includes("xplat");function i(e){if(("Literal"===e.type||"JSXText"===e.type)&&"string"==typeof e.value)return e.value;if("BinaryExpression"===e.type&&"+"===e.operator){const t=i(e.left),n=i(e.right);if(null!=t&&null!=n)return t+n}return null}function o(e){if("Identifier"===e.type)return e.name;if("ThisExpression"===e.type)return"this";if("MemberExpression"===e.type){const t=o(e.object),n=e.computed?i(e.property):o(e.property);if(null!=t&&null!=n)return t+"."+n}else if("TypeCastExpression"===e.type)return o(e.expression);return null}function a(e){return e.callee?o(e.callee):null}function l(e,t,n){const r=e.getSourceCode().getText(),i=function(e,t){if(t.line<1)throw new RangeError("Line number "+t.line+" is before the start of file");const n=/\r\n|\r|\n|\u2028|\u2029/g;let r={index:0};for(let i=1;i=e.length)throw new RangeError("computed offset "+t+" is past the end of file");const n=/\r\n|\r|\n|\u2028|\u2029/g;let r,i={index:0},o=0;do{r=i,i=n.exec(e),++o}while(i&&i.index"string"==typeof e&&e.charCodeAt(0)>=97,c=e=>"string"==typeof e&&e.charCodeAt(0)<=90;function p(e){return null!=e&&"VariableDeclaration"===e.type&&"Program"===e.parent.type&&1===e.declarations.length&&null!=e.declarations[0].init&&m(e.declarations[0].init)}function f(e){return null!=e&&"VariableDeclarator"===e.type&&"VariableDeclaration"===e.parent.type&&"Program"===e.parent.parent.type&&1===e.parent.declarations.length&&m(e.init)}function m(e){return null!=e&&(d(e)||y(e)||h(e))}function g(e){return null!=e&&"CallExpression"===e.type&&e.callee&&"Identifier"===e.callee.type&&"requireNUX"===e.callee.name&&2===e.arguments.length&&"Literal"===e.arguments[0].type}function d(e){return"CallExpression"===e.type&&e.callee&&"Identifier"===e.callee.type&&"require"===e.callee.name&&1===e.arguments.length&&"Literal"===e.arguments[0].type}function y(e){return"CallExpression"===e.type&&"Identifier"===e.callee.type&&"requireDeferred"===e.callee.name&&1===e.arguments.length&&"Literal"===e.arguments[0].type&&"string"==typeof e.arguments[0].value}function h(e){return"CallExpression"===e.type&&"Identifier"===e.callee.type&&"requireDeferredForDisplay"===e.callee.name&&1===e.arguments.length&&"Literal"===e.arguments[0].type&&"string"==typeof e.arguments[0].value}function x(e){return"ImportDeclaration"===e.type&&(null==e.importKind||"value"===e.importKind)}function b(e){return"ImportDeclaration"===e.type&&("type"===e.importKind||"typeof"===e.importKind)}function C(e){return x(e)||b(e)}function S(e){return null!=e&&"CallExpression"===e.type&&e.callee&&"Identifier"===e.callee.type&&"JSResource"===e.callee.name&&1===e.arguments.length&&"Literal"===e.arguments[0].type}function v(e){return null!=e&&"CallExpression"===e.type&&e.callee&&"Identifier"===e.callee.type&&"JSResourceForInteraction"===e.callee.name&&2===e.arguments.length&&"Literal"===e.arguments[0].type}function E(e){return null!=e&&"CallExpression"===e.type&&"Identifier"===e.callee.type&&"ClientJSResource"===e.callee.name&&1===e.arguments.length&&"Literal"===e.arguments[0].type&&"string"==typeof e.arguments[0].value}function I(e){if(null==e||"CallExpression"!==e.type||null==e.callee)return!1;let t;return"Identifier"===e.callee.type&&(t=e.callee),"MemberExpression"===e.callee.type&&"Identifier"===e.callee.object.type&&(t=e.callee.object),null!=t&&"requireCond"===t.name&&e.arguments.length>0}function T(e){return 0===e.indexOf("m#")?e.substring(2):e}function R(e,t,n=1){return"CallExpression"!==e.type||e.arguments.length!==n||null!=t&&"string"==typeof t&&a(e)!==t||"Literal"!==e.arguments[0].type||"string"!=typeof e.arguments[0].value?null:T(e.arguments[0].value)}function D(e,t,n){const r=e.arguments;return I(e)?3!==r.length?null:(null==t||r[0]&&"Literal"===r[0].type&&r[0].value===t)&&(null==n||r[1]&&"Literal"===r[1].type&&r[1].value===n)?r[2]&&"ObjectExpression"===r[2].type?r[2].properties.reduce(((e,t)=>{if("Property"===t.type&&"Literal"===t.value.type){let n;if("Identifier"===t.key.type)n=t.key.name;else{if("Literal"!==t.key.type)return e;n=String(t.key.value)}e[n]="string"==typeof t.value.value?T(t.value.value):null}return e}),{}):r[2]&&"Literal"===r[2].type&&"string"==typeof r[2].value?T(r[2].value):null:null:null}function w(e){return R(e,"JSResource")}function N(e){return null==e?null:m(e)?"string"!=typeof e.arguments[0].value?null:T(e.arguments[0].value):null}function q(e,t){const n=e.getSourceCode().ast.body.find((e=>"VariableDeclaration"===e.type&&1===e.declarations.length&&"VariableDeclarator"===e.declarations[0].type&&null!=e.declarations[0].init&&N(e.declarations[0].init)===t));return n||null}function k(e){let t=e;for(;"TypeCastExpression"===t.type;)t=t.expression;return t}function L(e){if("value"!==e.importKind)return!0;return e.specifiers.every((e=>"ImportSpecifier"===e.type&&("type"===e.importKind||"typeof"===e.importKind)))}function O(e,t){const n=e.getSourceCode().ast.body.find((e=>"ImportDeclaration"===e.type&&e.source.value===t&&!L(e)));return n||null}var P={asAnyKindOfRequireCall:function(e){return m(e)?e:null},asAnyKindOfRequireVariableDeclaration:function(e){return p(e)?e:null},asAnyKindOfRequireVariableDeclarator:function(e){return f(e)?e:null},getAnyRequiredModuleName:function(e,t=Object.freeze({})){const n=N(e)||w(e)||function(e){return R(e,"JSResourceForInteraction",2)}(e)||function(e){if(!g(e))return null;if(2!==e.arguments.length)return null;if("string"!=typeof e.arguments[1].value)return null;return T(e.arguments[1].value)}(e);return null!=n?n:D(e,t.condType,t.condition)},getBaseNode:function(e){let t=e;for(;"MemberExpression"===t.type;)t=t.object;return t},getBinding:s,getBootloadedModuleNames:function(e){return"ExpressionStatement"===e.type&&e.expression&&"CallExpression"===e.expression.type&&e.expression.callee&&"MemberExpression"===e.expression.callee.type&&e.expression.callee.object&&"Bootloader"===e.expression.callee.object.name&&e.expression.callee.property&&"loadModules"===e.expression.callee.property.name&&e.expression.arguments.length>0&&"ArrayExpression"===e.expression.arguments[0].type&&e.expression.arguments[0].elements.length>0?e.expression.arguments[0].elements.map((e=>"Literal"===e.type&&"string"==typeof e.value?e.value:null)).filter(Boolean):null},getCalleeName:a,getConstantStringExpression:i,getCurrentClassName:function(e){const t=e.getAncestors().find((e=>"ClassDeclaration"===e.type));return t&&"ClassDeclaration"===t.type&&null!=t.id?t.id.name:null},getEnglishForNth:function(e){return["first","second","third","fourth","fifth","sixth"][e]},getFullyQualifiedIdentifier:o,getJSResourceModuleName:w,getJSXMemberOrNamespaceRoot:function(e){let t=e;for(;"JSXIdentifier"!==t.type;)if("JSXMemberExpression"===t.type)t=t.object;else{if("JSXNamespacedName"!==t.type)throw new Error("unexpected "+t.type);t=t.namespace}return t},getLocOffset:function(e,t,n){return l(e,t.loc.start,n)},getLocOffsetOfLoc:l,getName:function(e){const t=k(e);return"Identifier"===t.type?t.name:"Literal"===t.type?String(t.value):null},getObjectPropertyName:function(e){if("Property"!==e.type&&"PropertyDefinition"!==e.type&&"MethodDefinition"!==e.type)return null;const t=e.key;return"Identifier"!==t.type||e.computed?function(e){switch(e.type){case"Literal":switch(e.literalType){case"bigint":return e.bigint;case"null":return"null";case"regexp":return`/${e.regex.pattern}/${e.regex.flags}`;default:return String(e.value)}case"TemplateLiteral":if(0===e.expressions.length&&1===e.quasis.length)return e.quasis[0].value.cooked}return null}(t):t.name},getParamComments:function(e,t){return t.params.map((function(t){const n=e.getSourceCode().getCommentsBefore(t);return n[n.length-1]}))},getPropertyName:function(e){return"MemberExpression"!==e.type?null:e.computed?i(e.property):"Identifier"!==e.property.type?null:e.property.name},getPropTokens:function(e,t){const n=e.getSourceCode().getTokens(t),r=[];return n.forEach(((e,t,n)=>{"JSXIdentifier"===e.type&&"Punctuator"===n[t+1].type&&"="===n[t+1].value&&r.push(e)})),r},getRequireCondModules:D,getRequireModuleName:N,getRequireModuleNode:q,getReturnComment:function(e,t){return e.getSourceCode().getCommentsBefore(t.body)[0]},getValueImportNode:O,hasValueImport:function(e){return e.getSourceCode().ast.body.some((e=>"ImportDeclaration"===e.type&&!L(e)))},getVariable:function(e,t){let n=t;for(;n;){const t=n.set.get(e);if(t)return t;n=n.upper}return null},insertRequireStatement:function(e,t,n,r=""){if(""===n)throw new Error("Name must be a string with length larger than 0");const i=`const ${n} = require('${n}${r}');`,o=[];e.getSourceCode().ast.body.forEach((e=>{if("VariableDeclaration"===e.type&&1===e.declarations.length&&"VariableDeclarator"===e.declarations[0].type&&e.declarations[0].init){const t=N(e.declarations[0].init);null!=t&&o.push({name:t,node:e})}}));const a=o.find((e=>e.name>=n));if(a){if(a.name.replace(r,"")===n)return[];const e=o[0];if(u(a.name)&&c(n)){if(e!==a){const e=a.node.range[0];return[t.removeRange([e-1,e-1]),t.insertTextBefore(a.node,i+"\n\n")]}return[t.insertTextBefore(a.node,i+"\n\n")]}return[t.insertTextBefore(a.node,i+"\n")]}if(o.length>0){const e=o[o.length-1],r=c(e.name)&&u(n)?"\n":"";return[t.insertTextAfter(e.node,"\n"+i+r)]}{const n=e.getSourceCode().ast.body,r=n[0];return"ExpressionStatement"===r.type&&"Literal"===r.expression.type&&"use strict"===r.expression.value?[t.insertTextBefore(n[1],i+"\n")]:[t.insertTextBefore(n[0],i+"\n")]}},insertValueImportStatement:function(e,t,n,r=""){if(""===n)throw new Error("Name must be a string with length larger than 0");const i=`import ${n} from '${n}${r}';`,o=[];e.getSourceCode().ast.body.forEach((e=>{if(x(e)){const t=function(e){if(m(e))return"string"!=typeof e.arguments[0].value?null:T(e.arguments[0].value);if(C(e))return e.source.value;return null}(e);null!=t&&o.push({name:t,node:e})}}));const a=o.find((e=>e.name>=n));if(a){if(a.name.replace(r,"")===n)return[];const e=o[0];if(u(a.name)&&c(n)){if(e!==a){const e=a.node.range[0];return[t.removeRange([e-1,e-1]),t.insertTextBefore(a.node,i+"\n\n")]}return[t.insertTextBefore(a.node,i+"\n\n")]}return[t.insertTextBefore(a.node,i+"\n")]}if(o.length>0){const e=o[o.length-1],r=c(e.name)&&u(n)?"\n":"";return[t.insertTextAfter(e.node,"\n"+i+r)]}{const n=e.getSourceCode().ast.body,r=n[0];return"ExpressionStatement"===r.type&&"Literal"===r.expression.type&&"use strict"===r.expression.value?[t.insertTextBefore(n[1],i+"\n")]:[t.insertTextBefore(n[0],i+"\n")]}},isAnyKindOfImport:C,isAnyKindOfModuleCall:function(e){return m(e)||I(e)||S(e)||v(e)||E(e)||g(e)},isAnyKindOfRequireCall:m,isAnyKindOfRequireVariableDeclaration:p,isAnyKindOfRequireVariableDeclarator:f,isClientJSResource:E,isFbSourceRepo:r,isGraphQLTemplate:function(e){return"Identifier"===e.tag.type&&"graphql"===e.tag.name&&1===e.quasi.quasis.length},isInsideMethod:function(e,t){return e.getAncestors().some((e=>"MethodDefinition"===e.type&&"Identifier"===e.key.type&&e.key.name===t))},isJSResource:S,isJSResourceForInteraction:v,isModuleRef:function(e){return"Literal"===e.type&&"string"==typeof e.value&&e.value.startsWith("m#")},isOnlyTypeImport:L,isOnlyTypeExport:function(e){return"type"===e.exportKind},isReferenced:function(e){const t=e.parent;switch(t.type){case"MemberExpression":case"JSXMemberExpression":return t.property===e&&!0===t.computed||t.object===e;case"MetaProperty":case"ImportDefaultSpecifier":case"ImportNamespaceSpecifier":case"ImportSpecifier":case"LabeledStatement":case"RestElement":case"ObjectPattern":case"ArrayPattern":return!1;case"Property":case"MethodDefinition":return t.key===e&&t.computed;case"VariableDeclarator":case"ClassDeclaration":case"ClassExpression":return t.id!==e;case"ArrowFunctionExpression":case"FunctionDeclaration":case"FunctionExpression":for(let n=0;ne.writeExpr));return null!=i?i.writeExpr:null},stripModuleRef:T,uncast:k};var j=t(Object.freeze({__proto__:null,isCommaOrSemiToken:function(e){return"Punctuator"===e.type&&(","===e.value||";"===e.value)}}));const{isCommaOrSemiToken:B}=j;var F={getInlineComments:function(e,t,n=B){const r=e.ast.comments.filter((e=>e.loc.start.line===t.loc.end.line&&e.range[0]>t.range[1])).sort(((e,t)=>e.range[0]-t.range[0])),i=[];let o=t;for(const t of r){const r=e.getTokensBetween(o,t);if(r.length>0){if(!n)break;if(!r.every(n))break}i.push(t),o=t}return i},getLeadingComments:function(e,t,n){const r=e.getCommentsBefore(t),i=[];let o=t;for(let t=r.length-1;t>=0;t-=1){const a=r[t];if(a===n)break;if(a.loc.end.line===o.loc.start.line){i.unshift(a),o=a;continue}if(a.loc.end.line!==o.loc.start.line-1)break;const l=e.getTokenBefore(a);if(l&&l.loc.end.line===a.loc.start.line)break;i.unshift(a),o=a}return i}};var M=function(e){return e.getSourceCode().ast.docblock?.comment};const{getInlineComments:A,getLeadingComments:V}=F,{isCommaOrSemiToken:$}=j;function K(e){return"@"===e[0]||":"===e[0]}const J=/\d{1,3}(\.\d+)?%/;function _(e){switch(typeof e){case"number":return{isSafeNumericString:!0,isPercentage:!1};case"boolean":return{isSafeNumericString:!1,isPercentage:!1}}return isNaN(e)||isNaN(parseFloat(e))?J.test(e)?{isSafeNumericString:!0,isPercentage:!0}:{isSafeNumericString:!1,isPercentage:!1}:{isSafeNumericString:!0,isPercentage:!1}}function X(e){return e.reduce((([e,t],[n,r])=>[Math.min(e,n),Math.max(t,r)]),[Number.MAX_SAFE_INTEGER,0])}var U={compareNames:function(e,t,n=!1){if("number"==typeof e&&"number"==typeof t)return e-t;const r=String(e),i=String(t);if(""===r&&""!==i)return-1;if(""!==r&&""===i)return 1;if(""===r&&""===i)return 0;const{isSafeNumericString:o,isPercentage:a}=_(r),{isSafeNumericString:l,isPercentage:s}=_(i);if(o&&l){const e=Number.parseFloat(r),t=Number.parseFloat(i);if(e===t){if(!a&&s)return-1;if(a&&!s)return 1}return e-t}if(n){const e=K(r),t=K(i);if(!e&&t)return-1;if(e&&!t)return 1}const u=o||r[0].toLowerCase()===r[0].toUpperCase(),c=l||i[0].toLowerCase()===i[0].toUpperCase();if(!u&&c)return 1;if(u&&!c)return-1;if(!u&&!c){const e=r[0].toLowerCase()===r[0],t=i[0].toLowerCase()===i[0];if(!e&&t)return-1;if(e&&!t)return 1}return r.localeCompare(i,"en",{caseFirst:"upper",sensitivity:"base"})},getEncompassingRange:X,getNodeTextWithComments:function(e,t,n,{shouldIncludeNextTokenInRange:r=$,ensureTextFollowsNode:i,inlineCommentIgnoreToken:o}={}){const a=A(e,t,o),l=[...V(e,t,n).map((({range:e})=>e)),t.range,...a.map((({range:e})=>e))],s=e.getTokenAfter(t);s&&!0===r?.(s)&&l.push(s.range);const u=X(l);let c=e.text.slice(u[0],u[1]);const p=t.range[1]-u[0];if(null!=i){e.getTokenAfter(t)?.value!==i&&(c=c.slice(0,p)+i+c.slice(p))}return{range:u,text:c}},isComma:function(e){return"Punctuator"===e.type&&","===e.value}};const z=P,{getInlineComments:G,getLeadingComments:Q}=F,W=M,{compareNames:H}=U,Y=0,Z={default:1,namespace:2,named:3},ee={default:4,namespace:5,named:6},te={default:7,namespace:8,named:9},ne=0,re=1,ie=2,oe=3,ae=99;var le={meta:{fixable:"code",messages:{incorrectOrder:"Requires should be sorted alphabetically"}},create(e){const t=e.getSourceCode(),n=function(e){const t=W(e);if(null!=t)return t;const n=e.getSourceCode().ast,r=n.body.length>0?n.body[0]:n,i=e.getSourceCode().getCommentsBefore(r)[0];return i&&"Block"===i.type?i:null}(e);if(n&&(n.value.includes("* @generated")||n.value.includes("* @partially-generated")))return{};const r=Object.freeze({typeImport:{priority:10,uppercase:[],lowercase:[],tiebreakFunction:s},valueImport:{priority:20,uppercase:[],lowercase:[],tiebreakFunction:s},requiresUsedByOtherRequires:{priority:30,uppercase:[],lowercase:[],tiebreakFunction:u},require:{priority:40,uppercase:[],lowercase:[],tiebreakFunction:u}}),i=[];let o=null,a=null;const l=new Set;return{Program(n){for(const e of n.body)switch(e.type){case"ImportDeclaration":if("type"===e.importKind||"typeof"===e.importKind)g(r.typeImport,e,e.source.value,!0);else{const n=t.getLastToken(e.source,(e=>"from"===e.value));0===e.specifiers.length&&null==n?d(e):g(r.valueImport,e,e.source.value)}break;case"VariableDeclaration":{const t=e.declarations[0]?.init;if(1!==e.declarations.length||null==t){d(e);break}f(t,e);break}default:d(e)}const s=[];for(const e of Object.keys(r)){const t=r[e];s.push({priority:t.priority,nodes:t.uppercase.sort(((e,n)=>c(e,n,t.tiebreakFunction)))}),s.push({priority:t.priority+5,nodes:t.lowercase.sort(((e,n)=>c(e,n,t.tiebreakFunction)))})}function u(e){return[e.leadingComments.length?e.leadingComments.map((e=>t.getText(e))).join("\n")+"\n":"",e.inlineComments.length?" "+e.inlineComments.map((e=>t.getText(e))).join(" "):""]}const p=s.filter((e=>0!==e.nodes.length)).sort(((e,t)=>e.priority-t.priority)).map((e=>e.nodes.map((e=>{const[n,r]=u(e),i=function(e,t){const n=t.node,r=e.getText(n),i=(()=>{if("ImportDeclaration"===n.type&&null!=n.specifiers.find((e=>"ImportSpecifier"===e.type))){const t=e.getFirstToken(n,(e=>"Punctuator"===e.type&&"{"===e.value)),r=e.getFirstToken(n,(e=>"Punctuator"===e.type&&"}"===e.value));return null==t||null==r?null:e.getText().substring(t.range[0],r.range[1])}if("VariableDeclaration"===n.type&&"ObjectPattern"===n.declarations[0].id.type){const t=n.declarations[0].id.typeAnnotation,r=e.getText(n.declarations[0].id);return t?r.substr(0,t.range[0]-n.declarations[0].id.range[0]):r}return null})();if(null==i)return r;let o=[],a=null;"ImportDeclaration"===n.type?o=n.specifiers.map((t=>"ImportDefaultSpecifier"===t.type||"ImportNamespaceSpecifier"===t.type?null:{leadingComments:e.getCommentsBefore(t),name:t.imported.name,node:t})).filter(Boolean):"VariableDeclaration"===n.type&&"ObjectPattern"===n.declarations[0].id.type&&(o=n.declarations[0].id.properties.map((t=>{if("ExperimentalRestProperty"===t.type||"RestElement"===t.type)return a=t,null;const n=t.key,r="Literal"===n.type?String(n.value):"Identifier"===n.type?t.computed?null:n.name:null;return null==r?null:{leadingComments:e.getCommentsBefore(t),name:r,node:t}})).filter(Boolean));if(o.length<=1)return r;const l=i.indexOf("\n")>=0,s=o.sort(((e,t)=>H(e.name,t.name))).map((e=>e.node));null!=a&&s.push(a);const u=s.map((t=>{const n=e.getCommentsBefore(t).map((t=>e.getText(t))),r=n.length?n.join(""):"";return l?(r?" "+r+"\n":"")+" "+e.getText(t):(r?r+" ":"")+e.getText(t)})),c=(()=>{const t=[];if("ImportDeclaration"===n.type){if(t.push(...e.getCommentsBefore(n.source)),l&&null!=n.specifiers.find((e=>"ImportSpecifier"===e.type))){const r=e.getTokenBefore(n.source,(e=>"Punctuator"===e.type&&"}"===e.value));null!=r&&t.push(...e.getCommentsBefore(r))}}else if("VariableDeclaration"===n.type&&"ObjectPattern"===n.declarations[0].id.type){const r=e.getLastToken(n.declarations[0].id);null!=r&&t.push(...e.getCommentsBefore(r))}return t})(),p=l&&c.length?c.map((t=>" "+e.getText(t))).join("\n")+"\n":"",f=l?"\n"+u.map((e=>e.includes("...")?`${e}\n`:`${e},\n`)).join("")+p:u.join(", ");return r.replace(i,(()=>`{${f}}`))}(t,e);return n+i+r})).join("\n"))).join("\n\n"),m=o;if(null==m||null==a)return;const y=m.leadingComments.length?m.leadingComments[0].range[0]:m.node.range[0],h=a.inlineComments.length>0?a.inlineComments[a.inlineComments.length-1].range[1]:a.node.range[1];t.getText(m.node,m.node.range[0]-y,h-m.node.range[1])!==p&&e.report({node:m.node,messageId:"incorrectOrder",fix(e){const n=i.filter((({node:e})=>e.range[0]>=y&&e.range[1]<=h)).map((e=>{const[n,r]=u(e),i=t.getText(e.node);return{range:e.node.range,text:n+i+r}})).flat().concat(t.getAllComments().filter((e=>e.range[0]>=y&&e.range[1]<=h&&!l.has(e))).map((e=>({range:e.range,text:t.getText(e)})))).sort(((e,t)=>e.range[0]-t.range[0]||e.range[1]-t.range[1])).map((({text:e})=>e)).join("\n");return e.replaceTextRange([y,h],[p,n].filter(Boolean).join("\n\n"))}})}};function s(e){if(0===e.specifiers.length)return Y;const t=(()=>{switch(e.importKind){default:case"value":return Z;case"type":return ee;case"typeof":return te}})();return e.specifiers.find((e=>"ImportDefaultSpecifier"===e.type))?t.default:e.specifiers.find((e=>"ImportNamespaceSpecifier"===e.type))?t.namespace:t.named}function u(e){if("ExpressionStatement"===e.type)return ne;switch(e.declarations[0].id.type){case"Identifier":return re;case"ObjectPattern":return ie;case"ArrayPattern":return oe}return ae}function c(e,t,n){const r=H(e.moduleName,t.moduleName);if(0!==r)return r;const i=n(e.node)-n(t.node);return 0!==i?i:e.node.loc.start.line-t.node.loc.start.line}function p(e,t){if(null==e)throw new Error("Missing required module name");return null!=t?`${e}_${t}`:e}function f(e,n,i){const o=z.getRequireModuleName(e);if(z.isRequire(e)){const e=p(o,i);g("requireCond"===e||"requireDeferred"===e||"requireDeferredForDisplay"===e?r.requiresUsedByOtherRequires:r.require,n,p(o,i))}else if(z.isRequireDeferred(e)||z.isRequireDeferredForDisplay(e))g(r.require,n,p(o,i));else{if(z.isRequireCond(e)){if("VariableDeclaration"===n.type){const e=t.getText(n.declarations[0].id);return void g(r.require,n,p(e,i))}}else{if("MemberExpression"===e.type)return void f(e.object,n,p(t.getText(e.property),i));if("CallExpression"===e.type)return void f(e.callee,n,i)}d(n)}}function m(e){e.leadingComments.forEach((e=>l.add(e))),e.inlineComments.forEach((e=>l.add(e)));t.getCommentsInside(e.node).forEach((e=>l.add(e)))}function g(e,r,i,l=!1){const s={inlineComments:G(t,r),leadingComments:Q(t,r,n),moduleName:i,node:r};if(l)e.uppercase.push(s);else{const t=i[0]||"";t.toLowerCase()===t?e.lowercase.push(s):e.uppercase.push(s)}null==o&&(o=s),a=s,m(s)}function d(e){const r={inlineComments:G(t,e),leadingComments:Q(t,e,n),node:e};i.push(r),m(r)}}};const se=le;var ue={...se,create:e=>e.getSourceCode().getText().includes("@generated SignedSource<<")?{}:se.create(e)};module.exports=ue; diff --git a/types/index.d.ts b/types/index.d.ts index 97b34d5d2321db..349efc65a9fc8c 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -115,7 +115,7 @@ export * from '../Libraries/LayoutAnimation/LayoutAnimation'; export * from '../Libraries/Linking/Linking'; export * from '../Libraries/Lists/FlatList'; export * from '../Libraries/Lists/SectionList'; -export * from '../Libraries/Lists/VirtualizedList'; +export * from '@react-native/virtualized-lists'; export * from '../Libraries/LogBox/LogBox'; export * from '../Libraries/Modal/Modal'; export * as Systrace from '../Libraries/Performance/Systrace'; diff --git a/types/modules/globals.d.ts b/types/modules/globals.d.ts index 042fd06cb1f017..3efd94c55fc8d2 100644 --- a/types/modules/globals.d.ts +++ b/types/modules/globals.d.ts @@ -260,11 +260,11 @@ interface XMLHttpRequest extends EventTarget, XMLHttpRequestEventTarget { overrideMimeType(mime: string): void; send(data?: any): void; setRequestHeader(header: string, value: string): void; - readonly DONE: number; - readonly HEADERS_RECEIVED: number; - readonly LOADING: number; - readonly OPENED: number; - readonly UNSENT: number; + readonly DONE: 4; + readonly HEADERS_RECEIVED: 2; + readonly LOADING: 3; + readonly OPENED: 1; + readonly UNSENT: 0; addEventListener( type: K, listener: (this: XMLHttpRequest, ev: XMLHttpRequestEventMap[K]) => any, @@ -280,11 +280,11 @@ interface XMLHttpRequest extends EventTarget, XMLHttpRequestEventTarget { declare var XMLHttpRequest: { prototype: XMLHttpRequest; new (): XMLHttpRequest; - readonly DONE: number; - readonly HEADERS_RECEIVED: number; - readonly LOADING: number; - readonly OPENED: number; - readonly UNSENT: number; + readonly DONE: 4; + readonly HEADERS_RECEIVED: 2; + readonly LOADING: 3; + readonly OPENED: 1; + readonly UNSENT: 0; }; interface XMLHttpRequestEventTargetEventMap { @@ -551,9 +551,9 @@ interface FileReader extends EventTarget { // readAsBinaryString(blob: Blob): void; readAsDataURL(blob: Blob): void; readAsText(blob: Blob, encoding?: string): void; - readonly DONE: number; - readonly EMPTY: number; - readonly LOADING: number; + readonly DONE: 2; + readonly EMPTY: 0; + readonly LOADING: 1; addEventListener( type: K, listener: (this: FileReader, ev: FileReaderEventMap[K]) => any, @@ -571,7 +571,7 @@ interface FileReader extends EventTarget { declare var FileReader: { prototype: FileReader; new (): FileReader; - readonly DONE: number; - readonly EMPTY: number; - readonly LOADING: number; + readonly DONE: 2; + readonly EMPTY: 0; + readonly LOADING: 1; }; diff --git a/yarn.lock b/yarn.lock index b5f311bbfedace..742db74a6ba207 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4399,10 +4399,10 @@ flatted@^3.1.0: resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.2.tgz#64bfed5cb68fe3ca78b3eb214ad97b63bedce561" integrity sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA== -flow-bin@^0.198.2: - version "0.198.2" - resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.198.2.tgz#e601121a411b4ec5889cc3567d2706369cc510a9" - integrity sha512-PML2zhAZVd8EgzDqS9oSJF+OxUtJ+YLEdVVsVO7d1BwnrXCgiVrLjxiQP8/hur820grzC51Xb2CI3J+ohH/bMg== +flow-bin@^0.199.1: + version "0.199.1" + resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.199.1.tgz#678eac2303fa898227f4d103264b6ce49f4430c1" + integrity sha512-Ic0Mp9iZ2exbH0mNj/XhzUWPZa9JylHb6uQARZnnYCTRwumOpjNOP0qwyRTltWrbCpfHjnWngNO9VLaVKHz2aQ== flow-parser@0.*, flow-parser@^0.185.0: version "0.185.0" @@ -5732,10 +5732,10 @@ jsbn@~0.1.0: resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= -jsc-android@^250230.2.1: - version "250230.2.1" - resolved "https://registry.yarnpkg.com/jsc-android/-/jsc-android-250230.2.1.tgz#3790313a970586a03ab0ad47defbc84df54f1b83" - integrity sha512-KmxeBlRjwoqCnBBKGsihFtvsBHyUFlBxJPK4FzeYcIuBfdjv6jFys44JITAgSTbQD+vIdwMEfyZklsuQX0yI1Q== +jsc-android@^250231.0.0: + version "250231.0.0" + resolved "https://registry.yarnpkg.com/jsc-android/-/jsc-android-250231.0.0.tgz#91720f8df382a108872fa4b3f558f33ba5e95262" + integrity sha512-rS46PvsjYmdmuz1OAWXY/1kCYG7pnf1TBqeTiOJr1iDz7s5DLxxC9n/ZMknLDxzYzNVfI7R95MH10emSSG1Wuw== jscodeshift@^0.14.0: version "0.14.0"