diff --git a/.circleci/config.yml b/.circleci/config.yml index 18d5af7b4d9dd6..989546507a67ee 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -724,10 +724,6 @@ jobs: # ------------------------- test_android: executor: reactnativeandroid - parameters: - run_disabled_tests: - type: boolean - default: false steps: - checkout - setup_artifacts @@ -741,18 +737,16 @@ jobs: - report_bundle_size: platform: android + - store_test_results: + path: ~/react-native/packages/react-native-gradle-plugin/build/test-results + + - store_test_results: + path: ~/react-native/packages/react-native/ReactAndroid/build/test-results + - store_artifacts: path: ~/react-native/packages/rn-tester/android/app/build/outputs/apk/ destination: rntester-apk - # Optionally, run disabled tests - - when: - condition: << parameters.run_disabled_tests >> - steps: - - run: echo "Failing tests may be moved here temporarily." - - run_e2e: - platform: android - # ------------------------- # JOBS: Test Android Docker Image # ------------------------- @@ -1602,8 +1596,7 @@ workflows: - build_hermesc_windows - test_js: run_disabled_tests: false - - test_android: - run_disabled_tests: false + - test_android - test_android_docker_image - test_android_template: requires: diff --git a/.eslintrc.js b/.eslintrc.js index 2755223a478e90..622c41bf0d51c0 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -21,7 +21,7 @@ module.exports = { plugins: ['@react-native/eslint-plugin-specs', 'lint'], overrides: [ - // overriding the JS config from eslint-config-react-native-community config to ensure + // overriding the JS config from @react-native/eslint-config to ensure // that we use hermes-eslint for all js files { files: ['*.js'], diff --git a/.flowconfig b/.flowconfig index 3fddc6142a6c00..d7312aeeaf7ec7 100644 --- a/.flowconfig +++ b/.flowconfig @@ -75,4 +75,4 @@ untyped-import untyped-type-import [version] -^0.204.0 +^0.205.1 diff --git a/.flowconfig.android b/.flowconfig.android index e486b3865be378..77b5dcf3bf299c 100644 --- a/.flowconfig.android +++ b/.flowconfig.android @@ -75,4 +75,4 @@ untyped-import untyped-type-import [version] -^0.204.0 +^0.205.1 diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS deleted file mode 100644 index 113169229179c8..00000000000000 --- a/.github/CODEOWNERS +++ /dev/null @@ -1,40 +0,0 @@ -# See https://help.github.com/en/articles/about-code-owners -# to learn more about code owners. -# Order is important; the last matching pattern takes the most -# precedence. You may specify either a GitHub username, or an -# email address if you prefer, as the code owner. - -# Any Markdown file anywhere in the repository -**/*.md @hramos @cpojer - -# GitHub Settings, Bots -/.github/ @hramos -/packages/react-native-bots @hramos - -# Continuous Integration -/.circleci/ @hramos -/.circleci/Dockerfiles @gengjiawen -/.appveyor/ @gengjiawen - -# Internals -React/Base/* @shergin -React/Views/* @shergin -React/Modules/* @shergin -React/CxxBridge/* @mhorowitz - -# Components and APIs -ReactAndroid/src/main/java/com/facebook/react/animated/* @janicduplessis -Libraries/Animated/* @janicduplessis -Libraries/NativeAnimation/* @janicduplessis -Libraries/Image/* @shergin -Libraries/Text/* @shergin - -# Modifications to package.json typically require -# additional effort from a Facebook employee to land -/package.json @hramos @cpojer - -# These should not be modified through a GitHub PR -LICENSE* @hramos @cpojer @yungsters - -# The eslint-config-react-native-community package requires manual publishing after merging -/packages/eslint-config-react-native-community/* @matt-oakes diff --git a/.github/workflow-scripts/actOnLabel.js b/.github/workflow-scripts/actOnLabel.js index 5073523ee46893..78571fd0ac0511 100644 --- a/.github/workflow-scripts/actOnLabel.js +++ b/.github/workflow-scripts/actOnLabel.js @@ -7,7 +7,7 @@ * @format */ -module.exports = async (github, context, label) => { +module.exports = async (github, context, labelWithContext) => { const closeIssue = async () => { await github.rest.issues.update({ issue_number: context.issue.number, @@ -45,7 +45,7 @@ module.exports = async (github, context, label) => { }); }; - switch (label) { + switch (labelWithContext.label) { case 'Type: Invalid': await addComment( `| :warning: | Issue is Invalid |\n` + @@ -102,11 +102,11 @@ module.exports = async (github, context, label) => { ); await requestAuthorFeedback(); return; - case 'Needs: Verify on Latest Version': + case 'Newer Patch Available': await addComment( `| :warning: | Newer Version of React Native is Available! |\n` + `| --- | --- |\n` + - `| :information_source: | You are on a supported minor version, but it looks like there's a newer patch available. Please [upgrade](https://reactnative.dev/docs/upgrading) to the highest patch for your minor or latest and verify if the issue persists (alternatively, create a new project and repro the issue in it). If it does not repro, please let us know so we can close out this issue. This helps us ensure we are looking at issues that still exist in the most recent releases. |`, + `| :information_source: | You are on a supported minor version, but it looks like there's a newer patch available - ${labelWithContext.newestPatch}. Please [upgrade](https://reactnative.dev/docs/upgrading) to the highest patch for your minor or latest and verify if the issue persists (alternatively, create a new project and repro the issue in it). If it does not repro, please let us know so we can close out this issue. This helps us ensure we are looking at issues that still exist in the most recent releases. |`, ); return; case 'Needs: Version Info': @@ -121,7 +121,7 @@ module.exports = async (github, context, label) => { await addComment( `| :warning: | Missing Reproducible Example |\n` + `| --- | --- |\n` + - `| :information_source: | It looks like your issue is missing a reproducible example. Please provide a [Snack](https://snack.expo.dev) or a repository that demonstrates the issue you are reporting in a [minimal, complete, and reproducible](https://stackoverflow.com/help/minimal-reproducible-example) manner. |`, + `| :information_source: | It looks like your issue is missing a reproducible example. Please provide either:
|`, ); await requestAuthorFeedback(); return; diff --git a/.github/workflows/addDescriptiveLabels.js b/.github/workflow-scripts/addDescriptiveLabels.js similarity index 100% rename from .github/workflows/addDescriptiveLabels.js rename to .github/workflow-scripts/addDescriptiveLabels.js diff --git a/.github/workflow-scripts/verifyVersion.js b/.github/workflow-scripts/verifyVersion.js index da66a1f2f0f700..b91efe898eed6e 100644 --- a/.github/workflow-scripts/verifyVersion.js +++ b/.github/workflow-scripts/verifyVersion.js @@ -23,7 +23,7 @@ module.exports = async (github, context) => { if (reportedVersionIsNightly(issueVersionUnparsed, issueVersion)) return; if (!issueVersion) { - return 'Needs: Version Info'; + return {label: 'Needs: Version Info'}; } // Ensure the version matches one we support @@ -43,7 +43,7 @@ module.exports = async (github, context) => { const latestVersion = parseVersionFromString(latestRelease.name); if (!isVersionSupported(issueVersion, latestVersion)) { - return 'Type: Unsupported Version'; + return {label: 'Type: Unsupported Version'}; } // We want to encourage users to repro the issue on the highest available patch for the given minor. @@ -52,7 +52,10 @@ module.exports = async (github, context) => { recentReleases, ); if (latestPatchForVersion > issueVersion.patch) { - return 'Needs: Verify on Latest Version'; + return { + label: 'Newer Patch Available', + newestPatch: `${issueVersion.major}.${issueVersion.minor}.${latestPatchForVersion}`, + }; } }; diff --git a/.github/workflows/on-issue-labeled.yml b/.github/workflows/on-issue-labeled.yml index f4e976bd3d9695..14f9d4e9c5d608 100644 --- a/.github/workflows/on-issue-labeled.yml +++ b/.github/workflows/on-issue-labeled.yml @@ -23,25 +23,25 @@ jobs: with: script: | const verifyVersion = require('./.github/workflow-scripts/verifyVersion.js') - const labelToAdd = await verifyVersion(github, context); + const labelWithContext = await verifyVersion(github, context); - if(labelToAdd) { + if(labelWithContext && labelWithContext.label) { await github.rest.issues.addLabels({ issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, - labels: [labelToAdd] + labels: [labelWithContext.label] }) const actOnLabel = require('./.github/workflow-scripts/actOnLabel.js') - await actOnLabel(github, context, labelToAdd) + await actOnLabel(github, context, labelWithContext) } - name: Add descriptive label uses: actions/github-script@v6 with: script: | - const addDescriptiveLabel = require('./.github/workflows/addDescriptiveLabels.js') + const addDescriptiveLabel = require('./.github/workflow-scripts/addDescriptiveLabels.js') await addDescriptiveLabel(github, context); # Reacts to the label that triggered this workflow (added manually or via other workflows) @@ -54,4 +54,4 @@ jobs: with: script: | const actOnLabel = require('./.github/workflow-scripts/actOnLabel.js') - await actOnLabel(github, context, context.payload.label.name) + await actOnLabel(github, context, {label: context.payload.label.name}) diff --git a/CHANGELOG.md b/CHANGELOG.md index e32dccfb99ad87..315c44efb08823 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## v0.71.8 + +### Fixed + +#### Android specific + +- Read GROUP name in gradle-plugin dependency code ([615d9aefc4](https://github.com/facebook/react-native/commit/615d9aefc4274ed7a193c0410ed7f86e90ad1bff) by [@douglowder](https://github.com/douglowder)) +- Bump RNGP to 0.71.18 ([4bf4c470fe](https://github.com/facebook/react-native/commit/4bf4c470fe4996af02f45c9a9d77c6a790a95362) by [@kelset](https://github.com/kelset)) + +#### iOS specific + +- Do not send extra onChangeText even wnen instantianting multiline TextView ([a804c0f22b](https://github.com/facebook/react-native/commit/a804c0f22b4b11b3d9632dc59a6da14f6c4325e3) by [@dmytrorykun](https://github.com/dmytrorykun)) + ## v0.71.7 ### Fixed @@ -940,6 +953,20 @@ 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.10 + +### Fixed + +#### Android specific + +- Minimize EditText Spans 8/N: CustomStyleSpan ([b384bb613b](https://github.com/facebook/react-native/commit/b384bb613bf533aebf3271ba335c61946fcd3303) by [@NickGerleman](https://github.com/NickGerleman)) +- Minimize EditText Spans 6/N: letterSpacing ([5791cf1f7b](https://github.com/facebook/react-native/commit/5791cf1f7b43aed1d98cad7bcc272d97ab659111) by [@NickGerleman](https://github.com/NickGerleman)) +- Minimize Spans 5/N: Strikethrough and Underline ([0869ea29db](https://github.com/facebook/react-native/commit/0869ea29db6a4ca20b9043d592a2233ae1a0e7a2) by [@NickGerleman](https://github.com/NickGerleman)) +- Minimize Spans 4/N: ReactForegroundColorSpan ([8c9c8ba5ad](https://github.com/facebook/react-native/commit/8c9c8ba5adb59f7f891a5307a0bce7200dd3ac7d) by [@NickGerleman](https://github.com/NickGerleman)) +- Minimize Spans 3/N: ReactBackgroundColorSpan ([cc0ba57ea4](https://github.com/facebook/react-native/commit/cc0ba57ea42d876155b2fd7d9ee78604ff8aa57a) by [@NickGerleman](https://github.com/NickGerleman)) +- Minimize Spans 1/N: Fix precedence ([1743dd7ab4](https://github.com/facebook/react-native/commit/1743dd7ab40998c4d3491e3b2c56c531daf5dc47) by [@NickGerleman](https://github.com/NickGerleman)) +- Fix measurement of uncontrolled TextInput after edit ([8a0fe30591](https://github.com/facebook/react-native/commit/8a0fe30591e21b90a3481c1ef3eeadd4b592f3ed) by [@NickGerleman](https://github.com/NickGerleman)) + ## v0.69.9 ### Changed @@ -1271,6 +1298,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.7 + +### Fixed + +- Use logical operator instead of bit operation in Yoga ([c3ad8](https://github.com/facebook/react-native/commit/c3ad8ec7eb01b7236e0081ac7c7f888630caac21) by [@cuva](https://github.com/cuva)) + +#### Android specific + +- Minimize EditText Spans 8/N: CustomStyleSpan ([b384bb613b](https://github.com/facebook/react-native/commit/b384bb613bf533aebf3271ba335c61946fcd3303) by [@NickGerleman](https://github.com/NickGerleman)) +- Minimize EditText Spans 6/N: letterSpacing ([5791cf1f7b](https://github.com/facebook/react-native/commit/5791cf1f7b43aed1d98cad7bcc272d97ab659111) by [@NickGerleman](https://github.com/NickGerleman)) +- Minimize Spans 5/N: Strikethrough and Underline ([0869ea29db](https://github.com/facebook/react-native/commit/0869ea29db6a4ca20b9043d592a2233ae1a0e7a2) by [@NickGerleman](https://github.com/NickGerleman)) +- Minimize Spans 4/N: ReactForegroundColorSpan ([8c9c8ba5ad](https://github.com/facebook/react-native/commit/8c9c8ba5adb59f7f891a5307a0bce7200dd3ac7d) by [@NickGerleman](https://github.com/NickGerleman)) +- Minimize Spans 3/N: ReactBackgroundColorSpan ([cc0ba57ea4](https://github.com/facebook/react-native/commit/cc0ba57ea42d876155b2fd7d9ee78604ff8aa57a) by [@NickGerleman](https://github.com/NickGerleman)) +- Minimize Spans 1/N: Fix precedence ([1743dd7ab4](https://github.com/facebook/react-native/commit/1743dd7ab40998c4d3491e3b2c56c531daf5dc47) by [@NickGerleman](https://github.com/NickGerleman)) +- Fix measurement of uncontrolled TextInput after edit ([8a0fe30591](https://github.com/facebook/react-native/commit/8a0fe30591e21b90a3481c1ef3eeadd4b592f3ed) by [@NickGerleman](https://github.com/NickGerleman)) + ## v0.68.6 ### Fixed diff --git a/build.gradle.kts b/build.gradle.kts index 6899ccd139409b..1c3ebaccc359de 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -10,7 +10,7 @@ plugins { id("com.android.library") version "7.4.2" apply false id("com.android.application") version "7.4.2" apply false id("de.undercouch.download") version "5.0.1" apply false - kotlin("android") version "1.7.22" apply false + kotlin("android") version "1.8.0" apply false } val reactAndroidProperties = java.util.Properties() diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 943f0cbfa75457..c1962a79e29d3e 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 6ec1567a0f8831..a21c6ebe28b660 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.1-all.zip networkTimeout=10000 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 65dcd68d65c82f..aeb74cbb43e393 100755 --- a/gradlew +++ b/gradlew @@ -85,9 +85,6 @@ done APP_BASE_NAME=${0##*/} APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -144,7 +141,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac @@ -152,7 +149,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -197,6 +194,10 @@ if "$cygwin" || "$msys" ; then done fi + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + # Collect all arguments for the java command; # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of # shell script including quotes and variable substitutions, so put them in diff --git a/package.json b/package.json index 453b96e6e64c79..004d3a8bdec9f0 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,8 @@ "outputName": "js-test-results.xml" }, "scripts": { - "start": "react-native start", + "start": "cd packages/rn-tester && npm run start", + "android": "cd packages/rn-tester && npm run android", "test": "jest", "test-ci": "jest --maxWorkers=2 --ci --reporters=\"default\" --reporters=\"jest-junit\"", "flow": "flow", @@ -57,9 +58,8 @@ "@definitelytyped/dtslint": "^0.0.127", "@jest/create-cache-key-function": "^29.2.1", "@react-native/metro-config": "^0.73.0", - "@reactions/component": "^2.0.2", "@types/react": "^18.0.18", - "@typescript-eslint/parser": "^5.30.5", + "@typescript-eslint/parser": "^5.57.1", "async": "^3.2.2", "babel-plugin-transform-flow-enums": "^0.0.2", "clang-format": "^1.8.0", @@ -78,7 +78,7 @@ "eslint-plugin-react-native": "^4.0.0", "eslint-plugin-redundant-undefined": "^0.4.0", "eslint-plugin-relay": "^1.8.3", - "flow-bin": "^0.204.0", + "flow-bin": "^0.205.1", "hermes-eslint": "0.8.0", "inquirer": "^7.1.0", "jest": "^29.2.1", @@ -94,7 +94,7 @@ "react-test-renderer": "18.2.0", "shelljs": "^0.8.5", "signedsource": "^1.0.0", - "typescript": "4.1.3", + "typescript": "5.0.4", "ws": "^6.2.2" } } diff --git a/packages/assets/README.md b/packages/assets/README.md new file mode 100644 index 00000000000000..407cc5b53de5fd --- /dev/null +++ b/packages/assets/README.md @@ -0,0 +1,21 @@ +# @react-native/assets-registry + +[![Version][version-badge]][package] + +## Installation + +``` +yarn add --dev @react-native/assets-registry +``` + +*Note: We're using `yarn` to install deps. Feel free to change commands to use `npm` 3+ and `npx` if you like* + +[version-badge]: https://img.shields.io/npm/v/@react-native/assets-registry?style=flat-square +[package]: https://www.npmjs.com/package/@react-native/assets-registry + +## Testing + +To run the tests in this package, run the following commands from the React Native root folder: + +1. `yarn` to install the dependencies. You just need to run this once +2. `yarn jest packages/assets`. diff --git a/packages/assets/package.json b/packages/assets/package.json index 1d52c415a5b2bb..cd55b751e227b2 100644 --- a/packages/assets/package.json +++ b/packages/assets/package.json @@ -2,10 +2,16 @@ "name": "@react-native/assets-registry", "version": "0.73.0", "description": "Asset support code for React Native.", + "license": "MIT", "repository": { "type": "git", - "url": "git@github.com:facebook/react-native.git", + "url": "https://github.com/facebook/react-native.git", "directory": "packages/assets" }, - "license": "MIT" + "homepage": "https://github.com/facebook/react-native/tree/HEAD/packages/assets#readme", + "keywords": ["assets", "registry", "react-native", "support"], + "bugs": "https://github.com/facebook/react-native/issues", + "engines": { + "node": ">=16" + } } diff --git a/packages/assets/path-support.js b/packages/assets/path-support.js index a6c30d42375a55..f0a85af33ff98d 100644 --- a/packages/assets/path-support.js +++ b/packages/assets/path-support.js @@ -82,7 +82,7 @@ function getAndroidResourceIdentifier(asset: PackagerAsset): string { function getBasePath(asset: PackagerAsset): string { const basePath = asset.httpServerLocation; - return basePath.startsWith('/') ? basePath.substr(1) : basePath; + return basePath.startsWith('/') ? basePath.slice(1) : basePath; } module.exports = { diff --git a/packages/babel-plugin-codegen/README.md b/packages/babel-plugin-codegen/README.md new file mode 100644 index 00000000000000..34194810ab2bf8 --- /dev/null +++ b/packages/babel-plugin-codegen/README.md @@ -0,0 +1,21 @@ +# @react-native/babel-plugin-codegen + +[![Version][version-badge]][package] + +## Installation + +``` +yarn add --dev @babel/core @react-native/babel-plugin-codegen +``` + +*Note: We're using `yarn` to install deps. Feel free to change commands to use `npm` 3+ and `npx` if you like* + +[version-badge]: https://img.shields.io/npm/v/@react-native/babel-plugin-codegen?style=flat-square +[package]: https://www.npmjs.com/package/@react-native/babel-plugin-codegen + +## Testing + +To run the tests in this package, run the following commands from the React Native root folder: + +1. `yarn` to install the dependencies. You just need to run this once +2. `yarn jest packages/babel-plugin-codegen`. diff --git a/packages/babel-plugin-codegen/package.json b/packages/babel-plugin-codegen/package.json index 5954d420159810..3e3edcdb4ba5c6 100644 --- a/packages/babel-plugin-codegen/package.json +++ b/packages/babel-plugin-codegen/package.json @@ -1,12 +1,19 @@ { - "version": "0.73.0", "name": "@react-native/babel-plugin-codegen", + "version": "0.73.0", "description": "Babel plugin to generate native module and view manager code for React Native.", + "license": "MIT", "repository": { "type": "git", - "url": "git@github.com:facebook/react-native.git", + "url": "https://github.com/facebook/react-native.git", "directory": "packages/babel-plugin-codegen" }, + "homepage": "https://github.com/facebook/react-native/tree/HEAD/packages/babel-plugin-codegen#readme", + "keywords": ["babel", "plugin", "codegen", "react-native", "native-modules", "view-manager"], + "bugs": "https://github.com/facebook/react-native/issues", + "engines": { + "node": ">=16" + }, "files": [ "index.js" ], @@ -15,6 +22,5 @@ }, "devDependencies": { "@babel/core": "^7.20.0" - }, - "license": "MIT" + } } diff --git a/packages/eslint-config-react-native-community/README.md b/packages/eslint-config-react-native/README.md similarity index 100% rename from packages/eslint-config-react-native-community/README.md rename to packages/eslint-config-react-native/README.md diff --git a/packages/eslint-config-react-native-community/index.js b/packages/eslint-config-react-native/index.js similarity index 100% rename from packages/eslint-config-react-native-community/index.js rename to packages/eslint-config-react-native/index.js diff --git a/packages/eslint-config-react-native-community/package.json b/packages/eslint-config-react-native/package.json similarity index 68% rename from packages/eslint-config-react-native-community/package.json rename to packages/eslint-config-react-native/package.json index bb97ff34d9af7f..e42373a8731684 100644 --- a/packages/eslint-config-react-native-community/package.json +++ b/packages/eslint-config-react-native/package.json @@ -2,20 +2,25 @@ "name": "@react-native/eslint-config", "version": "0.73.0", "description": "ESLint config for React Native", - "main": "index.js", "license": "MIT", "repository": { "type": "git", - "url": "git@github.com:facebook/react-native.git", - "directory": "packages/eslint-config-react-native-community" + "url": "https://github.com/facebook/react-native.git", + "directory": "packages/eslint-config-react-native" + }, + "homepage": "https://github.com/facebook/react-native/tree/HEAD/packages/eslint-config-react-native#readme", + "keywords": ["eslint", "config", "react-native"], + "bugs": "https://github.com/facebook/react-native/issues", + "engines": { + "node": ">=16" }, - "homepage": "https://github.com/facebook/react-native/tree/HEAD/packages/eslint-config-react-native-community#readme", + "main": "index.js", "dependencies": { "@babel/core": "^7.20.0", "@babel/eslint-parser": "^7.19.0", "@react-native/eslint-plugin": "^0.73.0", - "@typescript-eslint/eslint-plugin": "^5.30.5", - "@typescript-eslint/parser": "^5.30.5", + "@typescript-eslint/eslint-plugin": "^5.57.1", + "@typescript-eslint/parser": "^5.57.1", "eslint-config-prettier": "^8.5.0", "eslint-plugin-eslint-comments": "^3.2.0", "eslint-plugin-ft-flow": "^2.0.1", diff --git a/packages/eslint-plugin-react-native-community/package.json b/packages/eslint-plugin-react-native-community/package.json deleted file mode 100644 index f6b8de3cd41a8a..00000000000000 --- a/packages/eslint-plugin-react-native-community/package.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "name": "@react-native/eslint-plugin", - "version": "0.73.0", - "description": "ESLint rules for @react-native/eslint-config", - "main": "index.js", - "repository": { - "type": "git", - "url": "git@github.com:facebook/react-native.git", - "directory": "packages/eslint-plugin-react-native-community" - }, - "license": "MIT" -} diff --git a/packages/eslint-plugin-react-native-community/README.md b/packages/eslint-plugin-react-native/README.md similarity index 67% rename from packages/eslint-plugin-react-native-community/README.md rename to packages/eslint-plugin-react-native/README.md index 1cf77b71d421f6..48fc9bcf67c1a0 100644 --- a/packages/eslint-plugin-react-native-community/README.md +++ b/packages/eslint-plugin-react-native/README.md @@ -1,6 +1,6 @@ # @react-native/eslint-plugin -This plugin is intended to be used in [`@react-native/eslint-config`](https://github.com/facebook/react-native/tree/HEAD/packages/eslint-config-react-native-community). You probably want to install that package instead. +This plugin is intended to be used in [`@react-native/eslint-config`](https://github.com/facebook/react-native/tree/HEAD/packages/eslint-config-react-native). You probably want to install that package instead. ## Installation @@ -25,3 +25,10 @@ Add to your eslint config (`.eslintrc`, or `eslintConfig` field in `package.json ### `platform-colors` Enforces that calls to `PlatformColor` and `DynamicColorIOS` are statically analyzable to enable performance optimizations. + +## Testing + +To run the tests in this package, run the following commands from the React Native root folder: + +1. `yarn` to install the dependencies. You just need to run this once +2. `yarn jest packages/eslint-plugin-react-native`. diff --git a/packages/eslint-plugin-react-native-community/__tests__/eslint-tester.js b/packages/eslint-plugin-react-native/__tests__/eslint-tester.js similarity index 100% rename from packages/eslint-plugin-react-native-community/__tests__/eslint-tester.js rename to packages/eslint-plugin-react-native/__tests__/eslint-tester.js diff --git a/packages/eslint-plugin-react-native-community/__tests__/platform-colors-test.js b/packages/eslint-plugin-react-native/__tests__/platform-colors-test.js similarity index 100% rename from packages/eslint-plugin-react-native-community/__tests__/platform-colors-test.js rename to packages/eslint-plugin-react-native/__tests__/platform-colors-test.js diff --git a/packages/eslint-plugin-react-native-community/index.js b/packages/eslint-plugin-react-native/index.js similarity index 100% rename from packages/eslint-plugin-react-native-community/index.js rename to packages/eslint-plugin-react-native/index.js diff --git a/packages/eslint-plugin-react-native/package.json b/packages/eslint-plugin-react-native/package.json new file mode 100644 index 00000000000000..becda76cc32ffc --- /dev/null +++ b/packages/eslint-plugin-react-native/package.json @@ -0,0 +1,18 @@ +{ + "name": "@react-native/eslint-plugin", + "version": "0.73.0", + "description": "ESLint rules for @react-native/eslint-config", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/facebook/react-native.git", + "directory": "packages/eslint-plugin-react-native" + }, + "homepage": "https://github.com/facebook/react-native/tree/HEAD/packages/eslint-plugin-react-native#readme", + "keywords": ["eslint", "rules", "eslint-config", "react-native"], + "bugs": "https://github.com/facebook/react-native/issues", + "engines": { + "node": ">=16" + }, + "main": "index.js" +} diff --git a/packages/eslint-plugin-react-native-community/platform-colors.js b/packages/eslint-plugin-react-native/platform-colors.js similarity index 100% rename from packages/eslint-plugin-react-native-community/platform-colors.js rename to packages/eslint-plugin-react-native/platform-colors.js diff --git a/packages/eslint-plugin-specs/README.md b/packages/eslint-plugin-specs/README.md new file mode 100644 index 00000000000000..824fe031ea64c1 --- /dev/null +++ b/packages/eslint-plugin-specs/README.md @@ -0,0 +1,21 @@ +# @react-native/eslint-plugin-specs + +[![Version][version-badge]][package] + +## Installation + +``` +yarn add --dev @react-native/eslint-plugin-specs +``` + +*Note: We're using `yarn` to install deps. Feel free to change commands to use `npm` 3+ and `npx` if you like* + +[version-badge]: https://img.shields.io/npm/v/@react-native/eslint-plugin-specs?style=flat-square +[package]: https://www.npmjs.com/package/@react-native/eslint-plugin-specs + +## Testing + +To run the tests in this package, run the following commands from the React Native root folder: + +1. `yarn` to install the dependencies. You just need to run this once +2. `yarn jest packages/eslint-plugin-specs`. diff --git a/packages/eslint-plugin-specs/package.json b/packages/eslint-plugin-specs/package.json index 4255aa43ac282c..9d523702fcae95 100644 --- a/packages/eslint-plugin-specs/package.json +++ b/packages/eslint-plugin-specs/package.json @@ -2,12 +2,19 @@ "name": "@react-native/eslint-plugin-specs", "version": "0.73.0", "description": "ESLint rules to validate NativeModule and Component Specs", - "main": "index.js", + "license": "MIT", "repository": { "type": "git", - "url": "git@github.com:facebook/react-native.git", + "url": "https://github.com/facebook/react-native.git", "directory": "packages/eslint-plugin-specs" }, + "homepage": "https://github.com/facebook/react-native/tree/HEAD/packages/eslint-plugin-specs#readme", + "keywords": ["eslint", "rules", "react-native", "native-modules", "components", "specs"], + "bugs": "https://github.com/facebook/react-native/issues", + "engines": { + "node": ">=16" + }, + "main": "index.js", "scripts": { "prepack": "node prepack.js", "postpack": "node postpack.js" @@ -22,6 +29,5 @@ "make-dir": "^2.1.0", "pirates": "^4.0.1", "source-map-support": "0.5.0" - }, - "license": "MIT" + } } diff --git a/packages/hermes-inspector-msggen/README.md b/packages/hermes-inspector-msggen/README.md new file mode 100644 index 00000000000000..b2b98932e32dd4 --- /dev/null +++ b/packages/hermes-inspector-msggen/README.md @@ -0,0 +1,21 @@ +# @react-native/hermes-inspector-msggen + +[![Version][version-badge]][package] + +## Installation + +``` +yarn add --dev @babel/cli @babel/core @babel/preset-env @babel/preset-flow jest @react-native/hermes-inspector-msggen +``` + +*Note: We're using `yarn` to install deps. Feel free to change commands to use `npm` 3+ and `npx` if you like* + +[version-badge]: https://img.shields.io/npm/v/@react-native/hermes-inspector-msggen?style=flat-square +[package]: https://www.npmjs.com/package/@react-native/hermes-inspector-msggen + +## Testing + +To run the tests in this package, run the following commands from the React Native root folder: + +1. `yarn` to install the dependencies. You just need to run this once +2. `yarn jest packages/hermes-inspector-msggen`. diff --git a/packages/hermes-inspector-msggen/__tests__/CommandTest.js b/packages/hermes-inspector-msggen/__tests__/command-test.js similarity index 100% rename from packages/hermes-inspector-msggen/__tests__/CommandTest.js rename to packages/hermes-inspector-msggen/__tests__/command-test.js diff --git a/packages/hermes-inspector-msggen/__tests__/EventTest.js b/packages/hermes-inspector-msggen/__tests__/event-test.js similarity index 100% rename from packages/hermes-inspector-msggen/__tests__/EventTest.js rename to packages/hermes-inspector-msggen/__tests__/event-test.js diff --git a/packages/hermes-inspector-msggen/__tests__/GraphTest.js b/packages/hermes-inspector-msggen/__tests__/graph-test.js similarity index 84% rename from packages/hermes-inspector-msggen/__tests__/GraphTest.js rename to packages/hermes-inspector-msggen/__tests__/graph-test.js index b890c050ea8905..5d4043b80e0017 100644 --- a/packages/hermes-inspector-msggen/__tests__/GraphTest.js +++ b/packages/hermes-inspector-msggen/__tests__/graph-test.js @@ -25,8 +25,8 @@ beforeEach(() => { // checks id1 occurs after id2 in arr function expectOccursAfter(arr, id1, id2) { - let idx1 = arr.indexOf(id1); - let idx2 = arr.indexOf(id2); + const idx1 = arr.indexOf(id1); + const idx2 = arr.indexOf(id2); expect(idx1).not.toBe(-1); expect(idx2).not.toBe(-1); @@ -35,7 +35,9 @@ function expectOccursAfter(arr, id1, id2) { test('detects cycle', () => { graph.addEdge('C2', 'A1'); - expect(() => graph.traverse(['A2'])).toThrow(/^Not a DAG/); + + const {cycles} = graph.traverse(['A2']); + expect(cycles).toContainEqual({from: 'A1', to: 'B1'}); }); test('checks for presence of root', () => { @@ -43,10 +45,10 @@ test('checks for presence of root', () => { }); test('traverses partial graph', () => { - let ids = graph.traverse(['B1', 'A3']); + const {nodes: ids} = graph.traverse(['B1', 'A3']); // Check that expected nodes are there - let sortedIds = ids.slice().sort(); + const sortedIds = ids.slice().sort(); expect(sortedIds).toEqual(['A3', 'B1', 'B2', 'C1', 'C2', 'C3']); // Check that the result is topologically sorted @@ -59,10 +61,10 @@ test('traverses partial graph', () => { }); test('traverses complete graph', () => { - let ids = graph.traverse(['A1', 'A2', 'A3']); + const {nodes: ids} = graph.traverse(['A1', 'A2', 'A3']); // Check that expected nodes are there - let sortedIds = ids.slice().sort(); + const sortedIds = ids.slice().sort(); expect(sortedIds).toEqual(['A1', 'A2', 'A3', 'B1', 'B2', 'C1', 'C2', 'C3']); // Check that the result is topologically sorted diff --git a/packages/hermes-inspector-msggen/__tests__/HeaderWriterTest.js b/packages/hermes-inspector-msggen/__tests__/header-writer-test.js similarity index 95% rename from packages/hermes-inspector-msggen/__tests__/HeaderWriterTest.js rename to packages/hermes-inspector-msggen/__tests__/header-writer-test.js index da8bf0c03a6b50..5ba2bb2a1158b5 100644 --- a/packages/hermes-inspector-msggen/__tests__/HeaderWriterTest.js +++ b/packages/hermes-inspector-msggen/__tests__/header-writer-test.js @@ -40,8 +40,12 @@ test('emits type decl', () => { expectCodeIsEqual(stream.get(), ` struct debugger::Location : public Serializable { Location() = default; + Location(Location&&) = default; + Location(const Location&) = delete; explicit Location(const folly::dynamic &obj); folly::dynamic toDynamic() const override; + Location& operator=(const Location&) = delete; + Location& operator=(Location&&) = default; runtime::ScriptId scriptId{}; int lineNumber{}; diff --git a/packages/hermes-inspector-msggen/__tests__/ImplementationWriterTest.js b/packages/hermes-inspector-msggen/__tests__/implementation-writer-test.js similarity index 100% rename from packages/hermes-inspector-msggen/__tests__/ImplementationWriterTest.js rename to packages/hermes-inspector-msggen/__tests__/implementation-writer-test.js diff --git a/packages/hermes-inspector-msggen/__tests__/PropertyTest.js b/packages/hermes-inspector-msggen/__tests__/property-test.js similarity index 100% rename from packages/hermes-inspector-msggen/__tests__/PropertyTest.js rename to packages/hermes-inspector-msggen/__tests__/property-test.js diff --git a/packages/hermes-inspector-msggen/__tests__/TypeTest.js b/packages/hermes-inspector-msggen/__tests__/type-test.js similarity index 100% rename from packages/hermes-inspector-msggen/__tests__/TypeTest.js rename to packages/hermes-inspector-msggen/__tests__/type-test.js diff --git a/packages/hermes-inspector-msggen/package.json b/packages/hermes-inspector-msggen/package.json index f39c077005dbfd..856d3b59607f15 100644 --- a/packages/hermes-inspector-msggen/package.json +++ b/packages/hermes-inspector-msggen/package.json @@ -1,11 +1,20 @@ { "name": "@react-native/hermes-inspector-msggen", - "private": true, "version": "0.72.0", + "private": true, + "description": "Hermes Inspector Message Generator for React Native", "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/facebook/react-native.git", + "directory": "packages/hermes-inspector-msggen" + }, "bin": { "msggen": "./bin/index.js" }, + "engines": { + "node": ">=16" + }, "scripts": { "flow": "flow", "build": "babel src --out-dir bin --source-maps", diff --git a/packages/hermes-inspector-msggen/src/Converters.js b/packages/hermes-inspector-msggen/src/Converters.js index 8061ef1a41aa24..aa5dbf86552cb6 100644 --- a/packages/hermes-inspector-msggen/src/Converters.js +++ b/packages/hermes-inspector-msggen/src/Converters.js @@ -9,11 +9,11 @@ */ export function toCppNamespace(domain: string): string { - return domain.substr(0, 1).toLowerCase() + domain.substr(1); + return domain.slice(0, 1).toLowerCase() + domain.slice(1); } export function toCppType(type: string): string { - return type.substr(0, 1).toUpperCase() + type.substr(1); + return type.slice(0, 1).toUpperCase() + type.slice(1); } export type JsTypeString = diff --git a/packages/hermes-inspector-msggen/src/Property.js b/packages/hermes-inspector-msggen/src/Property.js index d50df01f50327f..fdad9bc6f7b306 100644 --- a/packages/hermes-inspector-msggen/src/Property.js +++ b/packages/hermes-inspector-msggen/src/Property.js @@ -114,8 +114,8 @@ function toDomainAndId( domain = curDomain; id = absOrRelRef; } else { - domain = absOrRelRef.substr(0, i); - id = absOrRelRef.substr(i + 1); + domain = absOrRelRef.slice(0, i); + id = absOrRelRef.slice(i + 1); } return [domain, id]; diff --git a/packages/metro-config/README.md b/packages/metro-config/README.md new file mode 100644 index 00000000000000..903a3b3a76d3df --- /dev/null +++ b/packages/metro-config/README.md @@ -0,0 +1,21 @@ +# @react-native/metro-config + +[![Version][version-badge]][package] + +## Installation + +``` +yarn add --dev @react-native/js-polyfills metro-config metro-react-native-babel-transformer metro-runtime @react-native/metro-config +``` + +*Note: We're using `yarn` to install deps. Feel free to change commands to use `npm` 3+ and `npx` if you like* + +[version-badge]: https://img.shields.io/npm/v/@react-native/metro-config?style=flat-square +[package]: https://www.npmjs.com/package/@react-native/metro-config + +## Testing + +To run the tests in this package, run the following commands from the React Native root folder: + +1. `yarn` to install the dependencies. You just need to run this once +2. `yarn jest packages/metro-config`. diff --git a/packages/metro-config/package.json b/packages/metro-config/package.json index c95528acb9289c..e86d78e60321ab 100644 --- a/packages/metro-config/package.json +++ b/packages/metro-config/package.json @@ -2,12 +2,18 @@ "name": "@react-native/metro-config", "version": "0.73.0", "description": "Metro configuration for React Native.", + "license": "MIT", "repository": { "type": "git", - "url": "git@github.com:facebook/react-native.git", + "url": "https://github.com/facebook/react-native.git", "directory": "packages/metro-config" }, - "license": "MIT", + "homepage": "https://github.com/facebook/react-native/tree/HEAD/packages/metro-config#readme", + "keywords": ["metro", "config", "react-native"], + "bugs": "https://github.com/facebook/react-native/issues", + "engines": { + "node": ">=16" + }, "exports": "./index.js", "dependencies": { "@react-native/js-polyfills": "^0.73.0", diff --git a/packages/normalize-color/README.md b/packages/normalize-color/README.md new file mode 100644 index 00000000000000..20b618d930a592 --- /dev/null +++ b/packages/normalize-color/README.md @@ -0,0 +1,21 @@ +# @react-native/normalize-colors + +[![Version][version-badge]][package] + +## Installation + +``` +yarn add --dev @react-native/normalize-colors +``` + +*Note: We're using `yarn` to install deps. Feel free to change commands to use `npm` 3+ and `npx` if you like* + +[version-badge]: https://img.shields.io/npm/v/@react-native/normalize-colors?style=flat-square +[package]: https://www.npmjs.com/package/@react-native/normalize-colors + +## Testing + +To run the tests in this package, run the following commands from the React Native root folder: + +1. `yarn` to install the dependencies. You just need to run this once +2. `yarn jest packages/normalize-color`. diff --git a/packages/normalize-color/package.json b/packages/normalize-color/package.json index 71c6740121a691..079c3fe4dabea3 100644 --- a/packages/normalize-color/package.json +++ b/packages/normalize-color/package.json @@ -2,10 +2,16 @@ "name": "@react-native/normalize-colors", "version": "0.73.0", "description": "Color normalization for React Native.", + "license": "MIT", "repository": { "type": "git", - "url": "git@github.com:facebook/react-native.git", + "url": "https://github.com/facebook/react-native.git", "directory": "packages/normalize-color" }, - "license": "MIT" + "homepage": "https://github.com/facebook/react-native/tree/HEAD/packages/normalize-color#readme", + "keywords": ["color", "normalization", "normalize-colors", "react-native"], + "bugs": "https://github.com/facebook/react-native/issues", + "engines": { + "node": ">=16" + } } diff --git a/packages/polyfills/README.md b/packages/polyfills/README.md new file mode 100644 index 00000000000000..91f0b04de013bc --- /dev/null +++ b/packages/polyfills/README.md @@ -0,0 +1,21 @@ +# @react-native/js-polyfills + +[![Version][version-badge]][package] + +## Installation + +``` +yarn add @react-native/js-polyfills +``` + +*Note: We're using `yarn` to install deps. Feel free to change commands to use `npm` 3+ and `npx` if you like* + +[version-badge]: https://img.shields.io/npm/v/@react-native/js-polyfills?style=flat-square +[package]: https://www.npmjs.com/package/@react-native/js-polyfills + +## Testing + +To run the tests in this package, run the following commands from the React Native root folder: + +1. `yarn` to install the dependencies. You just need to run this once +2. `yarn jest packages/polyfills`. diff --git a/packages/polyfills/console.js b/packages/polyfills/console.js index e843f4f74caa3c..338e1590cb3bc7 100644 --- a/packages/polyfills/console.js +++ b/packages/polyfills/console.js @@ -252,7 +252,7 @@ const inspect = (function () { return ' ' + line; }) .join('\n') - .substr(2); + .slice(2); } else { str = '\n' + @@ -274,7 +274,7 @@ const inspect = (function () { } name = JSON.stringify('' + key); if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) { - name = name.substr(1, name.length - 2); + name = name.slice(1, name.length - 1); name = ctx.stylize(name, 'name'); } else { name = name diff --git a/packages/polyfills/package.json b/packages/polyfills/package.json index 1694345b4b2b7e..de11f640d1be8f 100644 --- a/packages/polyfills/package.json +++ b/packages/polyfills/package.json @@ -2,10 +2,16 @@ "name": "@react-native/js-polyfills", "version": "0.73.0", "description": "Polyfills for React Native.", + "license": "MIT", "repository": { "type": "git", - "url": "git@github.com:facebook/react-native.git", + "url": "https://github.com/facebook/react-native.git", "directory": "packages/polyfills" }, - "license": "MIT" + "homepage": "https://github.com/facebook/react-native/tree/HEAD/packages/polyfills#readme", + "keywords": ["polyfill", "polyfills", "js", "js-polyfills", "react-native"], + "bugs": "https://github.com/facebook/react-native/issues", + "engines": { + "node": ">=16" + } } diff --git a/packages/react-native-bots/dangerfile.js b/packages/react-native-bots/dangerfile.js index c14203e4c458d4..0a14b4d0fc2bb0 100644 --- a/packages/react-native-bots/dangerfile.js +++ b/packages/react-native-bots/dangerfile.js @@ -60,19 +60,21 @@ if (!includesTestPlan && !isFromPhabricator) { } // Check if there is a changelog and validate it -const status = validateChangelog(danger.github.pr.body); -const changelogInstructions = - 'See Changelog format'; -if (status === 'missing') { - // Provides advice if a changelog is missing - const title = ':clipboard: Missing Changelog'; - const idea = - 'Please add a Changelog to your PR description. ' + changelogInstructions; - fail(`${title} - ${idea}`); -} else if (status === 'invalid') { - const title = ':clipboard: Verify Changelog Format'; - const idea = changelogInstructions; - fail(`${title} - ${idea}`); +if (!isFromPhabricator) { + const status = validateChangelog(danger.github.pr.body); + const changelogInstructions = + 'See Changelog format'; + if (status === 'missing') { + // Provides advice if a changelog is missing + const title = ':clipboard: Missing Changelog'; + const idea = + 'Please add a Changelog to your PR description. ' + changelogInstructions; + fail(`${title} - ${idea}`); + } else if (status === 'invalid') { + const title = ':clipboard: Verify Changelog Format'; + const idea = changelogInstructions; + fail(`${title} - ${idea}`); + } } // Warns if the PR is opened against stable, as commits need to be cherry picked and tagged by a release maintainer. diff --git a/packages/react-native-bots/package.json b/packages/react-native-bots/package.json index ff5485e29f2aad..5a86115c8a9696 100644 --- a/packages/react-native-bots/package.json +++ b/packages/react-native-bots/package.json @@ -1,7 +1,18 @@ { "name": "@react-native/bots", + "description": "React Native Bots", "version": "0.0.0", "private": true, + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/facebook/react-native.git", + "directory": "packages/react-native-bots" + }, + "homepage": "https://github.com/facebook/react-native/tree/HEAD/packages/react-native-bots#readme", + "engines": { + "node": ">=16" + }, "devDependencies": { "@rnx-kit/rn-changelog-generator": "^0.4.0", "@seadub/danger-plugin-eslint": "^3.0.2", diff --git a/packages/react-native-codegen-typescript-test/package.json b/packages/react-native-codegen-typescript-test/package.json index 7966c5e443a761..dcc795f149d481 100644 --- a/packages/react-native-codegen-typescript-test/package.json +++ b/packages/react-native-codegen-typescript-test/package.json @@ -1,19 +1,22 @@ { "name": "@react-native/codegen-typescript-test", "version": "0.0.1", - "description": "⚛️ TypeScript related unit test for @react-native/codegen", - "homepage": "https://github.com/facebook/react-native/tree/HEAD/packages/react-native-typescript-test", + "description": "TypeScript related unit test for @react-native/codegen", + "license": "MIT", "repository": { "type": "git", - "url": "git@github.com:facebook/react-native.git", + "url": "https://github.com/facebook/react-native.git", "directory": "packages/react-native-codegen-typescript-test" }, + "homepage": "https://github.com/facebook/react-native/tree/HEAD/packages/react-native-typescript-test", + "engines": { + "node": ">=16" + }, "scripts": { "build": "yarn clean && node scripts/build.js --verbose && tsc", "clean": "rimraf lib && rimraf __generated__/*.ts", "prepare": "yarn run build" }, - "license": "MIT", "dependencies": { "@react-native/codegen": "*" }, diff --git a/packages/react-native-codegen/README.md b/packages/react-native-codegen/README.md index 2380d87f716a3a..8f6856b1c8f073 100644 --- a/packages/react-native-codegen/README.md +++ b/packages/react-native-codegen/README.md @@ -15,7 +15,7 @@ yarn add --dev @react-native/codegen ## Testing -To run the tests in this package, run the following commands from the react Native root folder: +To run the tests in this package, run the following commands from the React Native root folder: 1. `yarn` to install the dependencies. You just need to run this once -2. `yarn jest react-native-codegen`. +2. `yarn jest packages/react-native-codegen`. diff --git a/packages/react-native-codegen/e2e/__tests__/components/__snapshots__/GenerateEventEmitterH-test.js.snap b/packages/react-native-codegen/e2e/__tests__/components/__snapshots__/GenerateEventEmitterH-test.js.snap index 876d46a03a124e..57f16617fe96be 100644 --- a/packages/react-native-codegen/e2e/__tests__/components/__snapshots__/GenerateEventEmitterH-test.js.snap +++ b/packages/react-native-codegen/e2e/__tests__/components/__snapshots__/GenerateEventEmitterH-test.js.snap @@ -14,12 +14,11 @@ Object { #pragma once #include -#include namespace facebook { namespace react { -class JSI_EXPORT ArrayPropsNativeComponentViewEventEmitter : public ViewEventEmitter { +class ArrayPropsNativeComponentViewEventEmitter : public ViewEventEmitter { public: using ViewEventEmitter::ViewEventEmitter; @@ -46,12 +45,11 @@ Object { #pragma once #include -#include namespace facebook { namespace react { -class JSI_EXPORT BooleanPropNativeComponentViewEventEmitter : public ViewEventEmitter { +class BooleanPropNativeComponentViewEventEmitter : public ViewEventEmitter { public: using ViewEventEmitter::ViewEventEmitter; @@ -78,12 +76,11 @@ Object { #pragma once #include -#include namespace facebook { namespace react { -class JSI_EXPORT ColorPropNativeComponentViewEventEmitter : public ViewEventEmitter { +class ColorPropNativeComponentViewEventEmitter : public ViewEventEmitter { public: using ViewEventEmitter::ViewEventEmitter; @@ -110,12 +107,11 @@ Object { #pragma once #include -#include namespace facebook { namespace react { -class JSI_EXPORT DimensionPropNativeComponentViewEventEmitter : public ViewEventEmitter { +class DimensionPropNativeComponentViewEventEmitter : public ViewEventEmitter { public: using ViewEventEmitter::ViewEventEmitter; @@ -142,12 +138,11 @@ Object { #pragma once #include -#include namespace facebook { namespace react { -class JSI_EXPORT EdgeInsetsPropNativeComponentViewEventEmitter : public ViewEventEmitter { +class EdgeInsetsPropNativeComponentViewEventEmitter : public ViewEventEmitter { public: using ViewEventEmitter::ViewEventEmitter; @@ -174,12 +169,11 @@ Object { #pragma once #include -#include namespace facebook { namespace react { -class JSI_EXPORT EnumPropNativeComponentViewEventEmitter : public ViewEventEmitter { +class EnumPropNativeComponentViewEventEmitter : public ViewEventEmitter { public: using ViewEventEmitter::ViewEventEmitter; @@ -206,12 +200,11 @@ Object { #pragma once #include -#include namespace facebook { namespace react { -class JSI_EXPORT EventNestedObjectPropsNativeComponentViewEventEmitter : public ViewEventEmitter { +class EventNestedObjectPropsNativeComponentViewEventEmitter : public ViewEventEmitter { public: using ViewEventEmitter::ViewEventEmitter; @@ -250,12 +243,11 @@ Object { #pragma once #include -#include namespace facebook { namespace react { -class JSI_EXPORT EventPropsNativeComponentViewEventEmitter : public ViewEventEmitter { +class EventPropsNativeComponentViewEventEmitter : public ViewEventEmitter { public: using ViewEventEmitter::ViewEventEmitter; @@ -329,12 +321,11 @@ Object { #pragma once #include -#include namespace facebook { namespace react { -class JSI_EXPORT FloatPropsNativeComponentViewEventEmitter : public ViewEventEmitter { +class FloatPropsNativeComponentViewEventEmitter : public ViewEventEmitter { public: using ViewEventEmitter::ViewEventEmitter; @@ -361,12 +352,11 @@ Object { #pragma once #include -#include namespace facebook { namespace react { -class JSI_EXPORT ImagePropNativeComponentViewEventEmitter : public ViewEventEmitter { +class ImagePropNativeComponentViewEventEmitter : public ViewEventEmitter { public: using ViewEventEmitter::ViewEventEmitter; @@ -393,12 +383,11 @@ Object { #pragma once #include -#include namespace facebook { namespace react { -class JSI_EXPORT IntegerPropNativeComponentViewEventEmitter : public ViewEventEmitter { +class IntegerPropNativeComponentViewEventEmitter : public ViewEventEmitter { public: using ViewEventEmitter::ViewEventEmitter; @@ -425,12 +414,11 @@ Object { #pragma once #include -#include namespace facebook { namespace react { -class JSI_EXPORT InterfaceOnlyNativeComponentViewEventEmitter : public ViewEventEmitter { +class InterfaceOnlyNativeComponentViewEventEmitter : public ViewEventEmitter { public: using ViewEventEmitter::ViewEventEmitter; @@ -459,12 +447,11 @@ Object { #pragma once #include -#include namespace facebook { namespace react { -class JSI_EXPORT MixedPropNativeComponentViewEventEmitter : public ViewEventEmitter { +class MixedPropNativeComponentViewEventEmitter : public ViewEventEmitter { public: using ViewEventEmitter::ViewEventEmitter; @@ -491,12 +478,11 @@ Object { #pragma once #include -#include namespace facebook { namespace react { -class JSI_EXPORT MultiNativePropNativeComponentViewEventEmitter : public ViewEventEmitter { +class MultiNativePropNativeComponentViewEventEmitter : public ViewEventEmitter { public: using ViewEventEmitter::ViewEventEmitter; @@ -523,12 +509,11 @@ Object { #pragma once #include -#include namespace facebook { namespace react { -class JSI_EXPORT NoPropsNoEventsNativeComponentViewEventEmitter : public ViewEventEmitter { +class NoPropsNoEventsNativeComponentViewEventEmitter : public ViewEventEmitter { public: using ViewEventEmitter::ViewEventEmitter; @@ -555,12 +540,11 @@ Object { #pragma once #include -#include namespace facebook { namespace react { -class JSI_EXPORT ObjectPropsNativeComponentEventEmitter : public ViewEventEmitter { +class ObjectPropsNativeComponentEventEmitter : public ViewEventEmitter { public: using ViewEventEmitter::ViewEventEmitter; @@ -587,12 +571,11 @@ Object { #pragma once #include -#include namespace facebook { namespace react { -class JSI_EXPORT PointPropNativeComponentViewEventEmitter : public ViewEventEmitter { +class PointPropNativeComponentViewEventEmitter : public ViewEventEmitter { public: using ViewEventEmitter::ViewEventEmitter; @@ -619,12 +602,11 @@ Object { #pragma once #include -#include namespace facebook { namespace react { -class JSI_EXPORT StringPropNativeComponentViewEventEmitter : public ViewEventEmitter { +class StringPropNativeComponentViewEventEmitter : public ViewEventEmitter { public: using ViewEventEmitter::ViewEventEmitter; diff --git a/packages/react-native-codegen/e2e/__tests__/components/__snapshots__/GeneratePropsH-test.js.snap b/packages/react-native-codegen/e2e/__tests__/components/__snapshots__/GeneratePropsH-test.js.snap index ebc4cd23016df7..6bbef39bf4fb9c 100644 --- a/packages/react-native-codegen/e2e/__tests__/components/__snapshots__/GeneratePropsH-test.js.snap +++ b/packages/react-native-codegen/e2e/__tests__/components/__snapshots__/GeneratePropsH-test.js.snap @@ -14,7 +14,6 @@ Object { #pragma once #include -#include #include #include #include @@ -141,7 +140,7 @@ static inline void fromRawValue(const PropsParserContext& context, const RawValu } } -class JSI_EXPORT ArrayPropsNativeComponentViewProps final : public ViewProps { +class ArrayPropsNativeComponentViewProps final : public ViewProps { public: ArrayPropsNativeComponentViewProps() = default; ArrayPropsNativeComponentViewProps(const PropsParserContext& context, const ArrayPropsNativeComponentViewProps &sourceProps, const RawProps &rawProps); @@ -181,14 +180,13 @@ Object { */ #pragma once -#include #include #include namespace facebook { namespace react { -class JSI_EXPORT BooleanPropNativeComponentViewProps final : public ViewProps { +class BooleanPropNativeComponentViewProps final : public ViewProps { public: BooleanPropNativeComponentViewProps() = default; BooleanPropNativeComponentViewProps(const PropsParserContext& context, const BooleanPropNativeComponentViewProps &sourceProps, const RawProps &rawProps); @@ -218,7 +216,6 @@ Object { */ #pragma once -#include #include #include #include @@ -226,7 +223,7 @@ Object { namespace facebook { namespace react { -class JSI_EXPORT ColorPropNativeComponentViewProps final : public ViewProps { +class ColorPropNativeComponentViewProps final : public ViewProps { public: ColorPropNativeComponentViewProps() = default; ColorPropNativeComponentViewProps(const PropsParserContext& context, const ColorPropNativeComponentViewProps &sourceProps, const RawProps &rawProps); @@ -255,7 +252,6 @@ Object { */ #pragma once -#include #include #include #include @@ -263,7 +259,7 @@ Object { namespace facebook { namespace react { -class JSI_EXPORT DimensionPropNativeComponentViewProps final : public ViewProps { +class DimensionPropNativeComponentViewProps final : public ViewProps { public: DimensionPropNativeComponentViewProps() = default; DimensionPropNativeComponentViewProps(const PropsParserContext& context, const DimensionPropNativeComponentViewProps &sourceProps, const RawProps &rawProps); @@ -292,14 +288,13 @@ Object { */ #pragma once -#include #include #include namespace facebook { namespace react { -class JSI_EXPORT EdgeInsetsPropNativeComponentViewProps final : public ViewProps { +class EdgeInsetsPropNativeComponentViewProps final : public ViewProps { public: EdgeInsetsPropNativeComponentViewProps() = default; EdgeInsetsPropNativeComponentViewProps(const PropsParserContext& context, const EdgeInsetsPropNativeComponentViewProps &sourceProps, const RawProps &rawProps); @@ -328,7 +323,6 @@ Object { */ #pragma once -#include #include #include @@ -383,7 +377,7 @@ static inline std::string toString(const EnumPropNativeComponentViewIntervals &v } } -class JSI_EXPORT EnumPropNativeComponentViewProps final : public ViewProps { +class EnumPropNativeComponentViewProps final : public ViewProps { public: EnumPropNativeComponentViewProps() = default; EnumPropNativeComponentViewProps(const PropsParserContext& context, const EnumPropNativeComponentViewProps &sourceProps, const RawProps &rawProps); @@ -413,14 +407,13 @@ Object { */ #pragma once -#include #include #include namespace facebook { namespace react { -class JSI_EXPORT EventNestedObjectPropsNativeComponentViewProps final : public ViewProps { +class EventNestedObjectPropsNativeComponentViewProps final : public ViewProps { public: EventNestedObjectPropsNativeComponentViewProps() = default; EventNestedObjectPropsNativeComponentViewProps(const PropsParserContext& context, const EventNestedObjectPropsNativeComponentViewProps &sourceProps, const RawProps &rawProps); @@ -449,14 +442,13 @@ Object { */ #pragma once -#include #include #include namespace facebook { namespace react { -class JSI_EXPORT EventPropsNativeComponentViewProps final : public ViewProps { +class EventPropsNativeComponentViewProps final : public ViewProps { public: EventPropsNativeComponentViewProps() = default; EventPropsNativeComponentViewProps(const PropsParserContext& context, const EventPropsNativeComponentViewProps &sourceProps, const RawProps &rawProps); @@ -485,14 +477,13 @@ Object { */ #pragma once -#include #include #include namespace facebook { namespace react { -class JSI_EXPORT FloatPropsNativeComponentViewProps final : public ViewProps { +class FloatPropsNativeComponentViewProps final : public ViewProps { public: FloatPropsNativeComponentViewProps() = default; FloatPropsNativeComponentViewProps(const PropsParserContext& context, const FloatPropsNativeComponentViewProps &sourceProps, const RawProps &rawProps); @@ -527,7 +518,6 @@ Object { */ #pragma once -#include #include #include #include @@ -535,7 +525,7 @@ Object { namespace facebook { namespace react { -class JSI_EXPORT ImagePropNativeComponentViewProps final : public ViewProps { +class ImagePropNativeComponentViewProps final : public ViewProps { public: ImagePropNativeComponentViewProps() = default; ImagePropNativeComponentViewProps(const PropsParserContext& context, const ImagePropNativeComponentViewProps &sourceProps, const RawProps &rawProps); @@ -564,14 +554,13 @@ Object { */ #pragma once -#include #include #include namespace facebook { namespace react { -class JSI_EXPORT IntegerPropNativeComponentViewProps final : public ViewProps { +class IntegerPropNativeComponentViewProps final : public ViewProps { public: IntegerPropNativeComponentViewProps() = default; IntegerPropNativeComponentViewProps(const PropsParserContext& context, const IntegerPropNativeComponentViewProps &sourceProps, const RawProps &rawProps); @@ -602,14 +591,13 @@ Object { */ #pragma once -#include #include #include namespace facebook { namespace react { -class JSI_EXPORT InterfaceOnlyNativeComponentViewProps final : public ViewProps { +class InterfaceOnlyNativeComponentViewProps final : public ViewProps { public: InterfaceOnlyNativeComponentViewProps() = default; InterfaceOnlyNativeComponentViewProps(const PropsParserContext& context, const InterfaceOnlyNativeComponentViewProps &sourceProps, const RawProps &rawProps); @@ -638,14 +626,13 @@ Object { */ #pragma once -#include #include #include namespace facebook { namespace react { -class JSI_EXPORT MixedPropNativeComponentViewProps final : public ViewProps { +class MixedPropNativeComponentViewProps final : public ViewProps { public: MixedPropNativeComponentViewProps() = default; MixedPropNativeComponentViewProps(const PropsParserContext& context, const MixedPropNativeComponentViewProps &sourceProps, const RawProps &rawProps); @@ -674,7 +661,6 @@ Object { */ #pragma once -#include #include #include #include @@ -684,7 +670,7 @@ Object { namespace facebook { namespace react { -class JSI_EXPORT MultiNativePropNativeComponentViewProps final : public ViewProps { +class MultiNativePropNativeComponentViewProps final : public ViewProps { public: MultiNativePropNativeComponentViewProps() = default; MultiNativePropNativeComponentViewProps(const PropsParserContext& context, const MultiNativePropNativeComponentViewProps &sourceProps, const RawProps &rawProps); @@ -716,14 +702,13 @@ Object { */ #pragma once -#include #include #include namespace facebook { namespace react { -class JSI_EXPORT NoPropsNoEventsNativeComponentViewProps final : public ViewProps { +class NoPropsNoEventsNativeComponentViewProps final : public ViewProps { public: NoPropsNoEventsNativeComponentViewProps() = default; NoPropsNoEventsNativeComponentViewProps(const PropsParserContext& context, const NoPropsNoEventsNativeComponentViewProps &sourceProps, const RawProps &rawProps); @@ -752,7 +737,6 @@ Object { */ #pragma once -#include #include #include #include @@ -887,7 +871,7 @@ static inline void fromRawValue(const PropsParserContext& context, const RawValu static inline std::string toString(const ObjectPropsNativeComponentObjectPrimitiveRequiredPropStruct &value) { return \\"[Object ObjectPropsNativeComponentObjectPrimitiveRequiredPropStruct]\\"; } -class JSI_EXPORT ObjectPropsNativeComponentProps final : public ViewProps { +class ObjectPropsNativeComponentProps final : public ViewProps { public: ObjectPropsNativeComponentProps() = default; ObjectPropsNativeComponentProps(const PropsParserContext& context, const ObjectPropsNativeComponentProps &sourceProps, const RawProps &rawProps); @@ -918,7 +902,6 @@ Object { */ #pragma once -#include #include #include #include @@ -926,7 +909,7 @@ Object { namespace facebook { namespace react { -class JSI_EXPORT PointPropNativeComponentViewProps final : public ViewProps { +class PointPropNativeComponentViewProps final : public ViewProps { public: PointPropNativeComponentViewProps() = default; PointPropNativeComponentViewProps(const PropsParserContext& context, const PointPropNativeComponentViewProps &sourceProps, const RawProps &rawProps); @@ -955,14 +938,13 @@ Object { */ #pragma once -#include #include #include namespace facebook { namespace react { -class JSI_EXPORT StringPropNativeComponentViewProps final : public ViewProps { +class StringPropNativeComponentViewProps final : public ViewProps { public: StringPropNativeComponentViewProps() = default; StringPropNativeComponentViewProps(const PropsParserContext& context, const StringPropNativeComponentViewProps &sourceProps, const RawProps &rawProps); diff --git a/packages/react-native-codegen/package.json b/packages/react-native-codegen/package.json index d2eeade5d933ab..57412c383f5f88 100644 --- a/packages/react-native-codegen/package.json +++ b/packages/react-native-codegen/package.json @@ -1,19 +1,24 @@ { "name": "@react-native/codegen", "version": "0.73.0", - "description": "⚛️ Code generation tools for React Native", - "homepage": "https://github.com/facebook/react-native/tree/HEAD/packages/react-native-codegen", + "description": "Code generation tools for React Native", + "license": "MIT", "repository": { "type": "git", - "url": "git@github.com:facebook/react-native.git", + "url": "https://github.com/facebook/react-native.git", "directory": "packages/react-native-codegen" }, + "homepage": "https://github.com/facebook/react-native/tree/HEAD/packages/react-native-codegen#readme", + "keywords": ["code", "generation", "codegen", "tools", "react-native"], + "bugs": "https://github.com/facebook/react-native/issues", + "engines": { + "node": ">=16" + }, "scripts": { "build": "yarn clean && node scripts/build.js --verbose", "clean": "rimraf lib", "prepare": "yarn run build" }, - "license": "MIT", "files": [ "lib" ], diff --git a/packages/react-native-codegen/src/CodegenSchema.d.ts b/packages/react-native-codegen/src/CodegenSchema.d.ts index 78db904aa4c404..3482172d99009f 100644 --- a/packages/react-native-codegen/src/CodegenSchema.d.ts +++ b/packages/react-native-codegen/src/CodegenSchema.d.ts @@ -113,7 +113,11 @@ export type EventTypeAnnotation = | FloatTypeAnnotation | Int32TypeAnnotation | StringEnumTypeAnnotation - | ObjectTypeAnnotation; + | ObjectTypeAnnotation + | { + readonly type: 'ArrayTypeAnnotation'; + readonly elementType: EventTypeAnnotation + }; export type PropTypeAnnotation = | { @@ -291,6 +295,7 @@ export interface NativeModuleEnumDeclarationWithMembers { export interface NativeModuleGenericObjectTypeAnnotation { readonly type: 'GenericObjectTypeAnnotation'; + readonly dictionaryValueType?: Nullable | undefined; } export interface NativeModuleTypeAliasTypeAnnotation { @@ -352,4 +357,3 @@ export type NativeModuleReturnOnlyTypeAnnotation = | NativeModuleFunctionTypeAnnotation | NativeModulePromiseTypeAnnotation | VoidTypeAnnotation; - diff --git a/packages/react-native-codegen/src/CodegenSchema.js b/packages/react-native-codegen/src/CodegenSchema.js index 361d54ef75c596..f05a4f2e749ab3 100644 --- a/packages/react-native-codegen/src/CodegenSchema.js +++ b/packages/react-native-codegen/src/CodegenSchema.js @@ -128,7 +128,11 @@ export type EventTypeAnnotation = | Int32TypeAnnotation | MixedTypeAnnotation | StringEnumTypeAnnotation - | ObjectTypeAnnotation; + | ObjectTypeAnnotation + | $ReadOnly<{ + type: 'ArrayTypeAnnotation', + elementType: EventTypeAnnotation, + }>; export type PropTypeAnnotation = | $ReadOnly<{ @@ -324,6 +328,11 @@ export type NativeModuleEnumDeclarationWithMembers = { export type NativeModuleGenericObjectTypeAnnotation = $ReadOnly<{ type: 'GenericObjectTypeAnnotation', + + // a dictionary type is codegen as "Object" + // but we know all its members are in the same type + // when it happens, the following field is non-null + dictionaryValueType?: Nullable, }>; export type NativeModuleTypeAliasTypeAnnotation = $ReadOnly<{ diff --git a/packages/react-native-codegen/src/generators/components/CppHelpers.js b/packages/react-native-codegen/src/generators/components/CppHelpers.js index e1fbfb79dc1d7b..ccecb1bcd08073 100644 --- a/packages/react-native-codegen/src/generators/components/CppHelpers.js +++ b/packages/react-native-codegen/src/generators/components/CppHelpers.js @@ -49,6 +49,42 @@ function getCppTypeForAnnotation( } } +function getCppArrayTypeForAnnotation( + typeElement: EventTypeAnnotation, + structParts?: string[], +): string { + switch (typeElement.type) { + case 'BooleanTypeAnnotation': + case 'StringTypeAnnotation': + case 'DoubleTypeAnnotation': + case 'FloatTypeAnnotation': + case 'Int32TypeAnnotation': + case 'MixedTypeAnnotation': + return `std::vector<${getCppTypeForAnnotation(typeElement.type)}>`; + case 'StringEnumTypeAnnotation': + case 'ObjectTypeAnnotation': + if (!structParts) { + throw new Error( + `Trying to generate the event emitter for an Array of ${typeElement.type} without informations to generate the generic type`, + ); + } + return `std::vector<${generateEventStructName(structParts)}>`; + case 'ArrayTypeAnnotation': + return `std::vector<${getCppArrayTypeForAnnotation( + typeElement.elementType, + structParts, + )}>`; + default: + throw new Error( + `Can't determine array type with typeElement: ${JSON.stringify( + typeElement, + null, + 2, + )}`, + ); + } +} + function getImports( properties: | $ReadOnlyArray> @@ -222,6 +258,7 @@ function convertDefaultTypeToString( module.exports = { convertDefaultTypeToString, + getCppArrayTypeForAnnotation, getCppTypeForAnnotation, getEnumMaskName, getImports, diff --git a/packages/react-native-codegen/src/generators/components/GenerateEventEmitterCpp.js b/packages/react-native-codegen/src/generators/components/GenerateEventEmitterCpp.js index ff478d78feae4b..7a43aea0a2b54e 100644 --- a/packages/react-native-codegen/src/generators/components/GenerateEventEmitterCpp.js +++ b/packages/react-native-codegen/src/generators/components/GenerateEventEmitterCpp.js @@ -102,9 +102,12 @@ function generateSetter( variableName: string, propertyName: string, propertyParts: $ReadOnlyArray, + usingEvent: boolean, valueMapper: string => string = value => value, ) { - const eventChain = `$event.${[...propertyParts, propertyName].join('.')}`; + const eventChain = usingEvent + ? `$event.${[...propertyParts, propertyName].join('.')}` + : [propertyParts, propertyName].join('.'); return `${variableName}.setProperty(runtime, "${propertyName}", ${valueMapper( eventChain, )});`; @@ -116,6 +119,7 @@ function generateObjectSetter( propertyParts: $ReadOnlyArray, typeAnnotation: ObjectTypeAnnotation, extraIncludes: Set, + usingEvent: boolean, ) { return ` { @@ -126,6 +130,7 @@ function generateObjectSetter( typeAnnotation.properties, propertyParts.concat([propertyName]), extraIncludes, + usingEvent, ), 2, )} @@ -134,11 +139,165 @@ function generateObjectSetter( `.trim(); } +function setValueAtIndex( + propertyName: string, + indexVariable: string, + loopLocalVariable: string, + mappingFunction: string => string = value => value, +) { + return `${propertyName}.setValueAtIndex(runtime, ${indexVariable}++, ${mappingFunction( + loopLocalVariable, + )});`; +} + +function generateArraySetter( + variableName: string, + propertyName: string, + propertyParts: $ReadOnlyArray, + elementType: EventTypeAnnotation, + extraIncludes: Set, + usingEvent: boolean, +): string { + const eventChain = usingEvent + ? `$event.${[...propertyParts, propertyName].join('.')}` + : [propertyParts, propertyName].join('.'); + const indexVar = `${propertyName}Index`; + const innerLoopVar = `${propertyName}Value`; + return ` + auto ${propertyName} = jsi::Array(runtime, ${eventChain}.size()); + size_t ${indexVar} = 0; + for (auto ${innerLoopVar} : ${eventChain}) { + ${handleArrayElementType( + elementType, + propertyName, + indexVar, + innerLoopVar, + propertyParts, + extraIncludes, + usingEvent, + )} + } + ${variableName}.setProperty(runtime, "${propertyName}", ${propertyName}); + `; +} + +function handleArrayElementType( + elementType: EventTypeAnnotation, + propertyName: string, + indexVariable: string, + loopLocalVariable: string, + propertyParts: $ReadOnlyArray, + extraIncludes: Set, + usingEvent: boolean, +): string { + switch (elementType.type) { + case 'BooleanTypeAnnotation': + return setValueAtIndex( + propertyName, + indexVariable, + loopLocalVariable, + val => `(bool)${val}`, + ); + case 'StringTypeAnnotation': + case 'Int32TypeAnnotation': + case 'DoubleTypeAnnotation': + case 'FloatTypeAnnotation': + return setValueAtIndex(propertyName, indexVariable, loopLocalVariable); + case 'MixedTypeAnnotation': + return setValueAtIndex( + propertyName, + indexVariable, + loopLocalVariable, + val => `jsi::valueFromDynamic(runtime, ${val})`, + ); + case 'StringEnumTypeAnnotation': + return setValueAtIndex( + propertyName, + indexVariable, + loopLocalVariable, + val => `toString(${val})`, + ); + case 'ObjectTypeAnnotation': + return convertObjectTypeArray( + propertyName, + indexVariable, + loopLocalVariable, + propertyParts, + elementType, + extraIncludes, + ); + case 'ArrayTypeAnnotation': + return convertArrayTypeArray( + propertyName, + indexVariable, + loopLocalVariable, + propertyParts, + elementType, + extraIncludes, + usingEvent, + ); + default: + throw new Error( + `Received invalid elementType for array ${elementType.type}`, + ); + } +} + +function convertObjectTypeArray( + propertyName: string, + indexVariable: string, + loopLocalVariable: string, + propertyParts: $ReadOnlyArray, + objectTypeAnnotation: ObjectTypeAnnotation, + extraIncludes: Set, +): string { + return `auto ${propertyName}Object = jsi::Object(runtime); + ${generateSetters( + `${propertyName}Object`, + objectTypeAnnotation.properties, + [].concat([loopLocalVariable]), + extraIncludes, + false, + )} + ${setValueAtIndex(propertyName, indexVariable, `${propertyName}Object`)}`; +} + +function convertArrayTypeArray( + propertyName: string, + indexVariable: string, + loopLocalVariable: string, + propertyParts: $ReadOnlyArray, + eventTypeAnnotation: EventTypeAnnotation, + extraIncludes: Set, + usingEvent: boolean, +): string { + if (eventTypeAnnotation.type !== 'ArrayTypeAnnotation') { + throw new Error( + `Inconsistent eventTypeAnnotation received. Expected type = 'ArrayTypeAnnotation'; received = ${eventTypeAnnotation.type}`, + ); + } + return `auto ${propertyName}Array = jsi::Array(runtime, ${loopLocalVariable}.size()); + size_t ${indexVariable}Internal = 0; + for (auto ${loopLocalVariable}Internal : ${loopLocalVariable}) { + ${handleArrayElementType( + eventTypeAnnotation.elementType, + `${propertyName}Array`, + `${indexVariable}Internal`, + `${loopLocalVariable}Internal`, + propertyParts, + extraIncludes, + usingEvent, + )} + } + ${setValueAtIndex(propertyName, indexVariable, `${propertyName}Array`)}`; +} + function generateSetters( parentPropertyName: string, properties: $ReadOnlyArray>, propertyParts: $ReadOnlyArray, extraIncludes: Set, + usingEvent: boolean = true, ): string { const propSetters = properties .map(eventProperty => { @@ -153,6 +312,7 @@ function generateSetters( parentPropertyName, eventProperty.name, propertyParts, + usingEvent, ); case 'MixedTypeAnnotation': extraIncludes.add('#include '); @@ -160,6 +320,7 @@ function generateSetters( parentPropertyName, eventProperty.name, propertyParts, + usingEvent, prop => `jsi::valueFromDynamic(runtime, ${prop})`, ); case 'StringEnumTypeAnnotation': @@ -167,6 +328,7 @@ function generateSetters( parentPropertyName, eventProperty.name, propertyParts, + usingEvent, prop => `toString(${prop})`, ); case 'ObjectTypeAnnotation': @@ -176,6 +338,16 @@ function generateSetters( propertyParts, typeAnnotation, extraIncludes, + usingEvent, + ); + case 'ArrayTypeAnnotation': + return generateArraySetter( + parentPropertyName, + eventProperty.name, + propertyParts, + typeAnnotation.elementType, + extraIncludes, + usingEvent, ); default: (typeAnnotation.type: empty); diff --git a/packages/react-native-codegen/src/generators/components/GenerateEventEmitterH.js b/packages/react-native-codegen/src/generators/components/GenerateEventEmitterH.js index fcb082d74b8c9b..b5d55033f063b4 100644 --- a/packages/react-native-codegen/src/generators/components/GenerateEventEmitterH.js +++ b/packages/react-native-codegen/src/generators/components/GenerateEventEmitterH.js @@ -14,6 +14,7 @@ const nullthrows = require('nullthrows'); const { getImports, + getCppArrayTypeForAnnotation, getCppTypeForAnnotation, generateEventStructName, } = require('./CppHelpers'); @@ -54,7 +55,6 @@ const FileTemplate = ({ #pragma once #include -#include ${[...extraIncludes].join('\n')} namespace facebook { @@ -74,7 +74,7 @@ const ComponentTemplate = ({ events: string, }) => ` -class JSI_EXPORT ${className}EventEmitter : public ViewEventEmitter { +class ${className}EventEmitter : public ViewEventEmitter { public: using ViewEventEmitter::ViewEventEmitter; @@ -134,6 +134,17 @@ function getNativeTypeFromAnnotation( case 'StringEnumTypeAnnotation': case 'ObjectTypeAnnotation': return generateEventStructName([...nameParts, eventProperty.name]); + case 'ArrayTypeAnnotation': + const eventTypeAnnotation = eventProperty.typeAnnotation; + if (eventTypeAnnotation.type !== 'ArrayTypeAnnotation') { + throw new Error( + "Inconsistent Codegen state: type was ArrayTypeAnnotation at the beginning of the body and now it isn't", + ); + } + return getCppArrayTypeForAnnotation(eventTypeAnnotation.elementType, [ + ...nameParts, + eventProperty.name, + ]); default: (type: empty); throw new Error(`Received invalid event property type ${type}`); @@ -166,6 +177,33 @@ function generateEnum( ); } +function handleGenerateStructForArray( + structs: StructsMap, + name: string, + componentName: string, + elementType: EventTypeAnnotation, + nameParts: $ReadOnlyArray, +): void { + if (elementType.type === 'ObjectTypeAnnotation') { + generateStruct( + structs, + componentName, + nameParts.concat([name]), + nullthrows(elementType.properties), + ); + } else if (elementType.type === 'StringEnumTypeAnnotation') { + generateEnum(structs, elementType.options, nameParts.concat([name])); + } else if (elementType.type === 'ArrayTypeAnnotation') { + handleGenerateStructForArray( + structs, + name, + componentName, + elementType.elementType, + nameParts, + ); + } +} + function generateStruct( structs: StructsMap, componentName: string, @@ -195,6 +233,15 @@ function generateStruct( case 'FloatTypeAnnotation': case 'MixedTypeAnnotation': return; + case 'ArrayTypeAnnotation': + handleGenerateStructForArray( + structs, + name, + componentName, + typeAnnotation.elementType, + nameParts, + ); + return; case 'ObjectTypeAnnotation': generateStruct( structs, @@ -272,7 +319,7 @@ module.exports = { .map(moduleName => { const module = schema.modules[moduleName]; if (module.type !== 'Component') { - return; + return null; } const {components} = module; diff --git a/packages/react-native-codegen/src/generators/components/GeneratePropsH.js b/packages/react-native-codegen/src/generators/components/GeneratePropsH.js index 684153b23b5ea5..b8d4f91d550804 100644 --- a/packages/react-native-codegen/src/generators/components/GeneratePropsH.js +++ b/packages/react-native-codegen/src/generators/components/GeneratePropsH.js @@ -80,7 +80,7 @@ const ClassTemplate = ({ ` ${enums} ${structs} -class JSI_EXPORT ${className} final${extendClasses} { +class ${className} final${extendClasses} { public: ${className}() = default; ${className}(const PropsParserContext& context, const ${className} &sourceProps, const RawProps &rawProps); @@ -478,7 +478,6 @@ function getExtendsImports( const imports: Set = new Set(); imports.add('#include '); - imports.add('#include '); extendsProps.forEach(extendProps => { switch (extendProps.type) { diff --git a/packages/react-native-codegen/src/generators/components/__test_fixtures__/fixtures.js b/packages/react-native-codegen/src/generators/components/__test_fixtures__/fixtures.js index e5401bb4e7146c..65f7a46d25ba2c 100644 --- a/packages/react-native-codegen/src/generators/components/__test_fixtures__/fixtures.js +++ b/packages/react-native-codegen/src/generators/components/__test_fixtures__/fixtures.js @@ -1206,6 +1206,99 @@ const EVENT_PROPS: SchemaType = { }, }, }, + { + name: 'onArrayEventType', + optional: true, + bubblingType: 'bubble', + typeAnnotation: { + type: 'EventTypeAnnotation', + argument: { + type: 'ObjectTypeAnnotation', + properties: [ + { + name: 'bool_array_event_prop', + optional: false, + typeAnnotation: { + type: 'ArrayTypeAnnotation', + elementType: { + type: 'BooleanTypeAnnotation', + }, + }, + }, + { + name: 'string_enum_event_prop', + optional: false, + typeAnnotation: { + type: 'ArrayTypeAnnotation', + elementType: { + type: 'StringEnumTypeAnnotation', + options: ['YES', 'NO'], + }, + }, + }, + { + name: 'array_array_event_prop', + optional: false, + typeAnnotation: { + type: 'ArrayTypeAnnotation', + elementType: { + type: 'ArrayTypeAnnotation', + elementType: { + type: 'StringTypeAnnotation', + }, + }, + }, + }, + { + name: 'array_object_event_prop', + optional: false, + typeAnnotation: { + type: 'ArrayTypeAnnotation', + elementType: { + type: 'ObjectTypeAnnotation', + properties: [ + { + name: 'lat', + optional: false, + typeAnnotation: { + type: 'DoubleTypeAnnotation', + }, + }, + { + name: 'lon', + optional: false, + typeAnnotation: { + type: 'DoubleTypeAnnotation', + }, + }, + { + name: 'names', + optional: false, + typeAnnotation: { + type: 'ArrayTypeAnnotation', + elementType: { + type: 'StringTypeAnnotation', + }, + }, + }, + ], + }, + }, + }, + { + name: 'array_mixed_event_prop', + optional: false, + typeAnnotation: { + type: 'ArrayTypeAnnotation', + elementType: { + type: 'MixedTypeAnnotation', + }, + }, + }, + ], + }, + }, + }, { name: 'onEventDirect', optional: true, diff --git a/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GenerateEventEmitterCpp-test.js.snap b/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GenerateEventEmitterCpp-test.js.snap index 68fc88ff7a1818..2ec6051506eab0 100644 --- a/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GenerateEventEmitterCpp-test.js.snap +++ b/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GenerateEventEmitterCpp-test.js.snap @@ -264,6 +264,70 @@ $payload.setProperty(runtime, \\"scale\\", $event.scale); } +void EventsNativeComponentEventEmitter::onArrayEventType(OnArrayEventType $event) const { + dispatchEvent(\\"arrayEventType\\", [$event=std::move($event)](jsi::Runtime &runtime) { + auto $payload = jsi::Object(runtime); + + auto bool_array_event_prop = jsi::Array(runtime, $event.bool_array_event_prop.size()); + size_t bool_array_event_propIndex = 0; + for (auto bool_array_event_propValue : $event.bool_array_event_prop) { + bool_array_event_prop.setValueAtIndex(runtime, bool_array_event_propIndex++, (bool)bool_array_event_propValue); + } + $payload.setProperty(runtime, \\"bool_array_event_prop\\", bool_array_event_prop); + + + auto string_enum_event_prop = jsi::Array(runtime, $event.string_enum_event_prop.size()); + size_t string_enum_event_propIndex = 0; + for (auto string_enum_event_propValue : $event.string_enum_event_prop) { + string_enum_event_prop.setValueAtIndex(runtime, string_enum_event_propIndex++, toString(string_enum_event_propValue)); + } + $payload.setProperty(runtime, \\"string_enum_event_prop\\", string_enum_event_prop); + + + auto array_array_event_prop = jsi::Array(runtime, $event.array_array_event_prop.size()); + size_t array_array_event_propIndex = 0; + for (auto array_array_event_propValue : $event.array_array_event_prop) { + auto array_array_event_propArray = jsi::Array(runtime, array_array_event_propValue.size()); + size_t array_array_event_propIndexInternal = 0; + for (auto array_array_event_propValueInternal : array_array_event_propValue) { + array_array_event_propArray.setValueAtIndex(runtime, array_array_event_propIndexInternal++, array_array_event_propValueInternal); + } + array_array_event_prop.setValueAtIndex(runtime, array_array_event_propIndex++, array_array_event_propArray); + } + $payload.setProperty(runtime, \\"array_array_event_prop\\", array_array_event_prop); + + + auto array_object_event_prop = jsi::Array(runtime, $event.array_object_event_prop.size()); + size_t array_object_event_propIndex = 0; + for (auto array_object_event_propValue : $event.array_object_event_prop) { + auto array_object_event_propObject = jsi::Object(runtime); + array_object_event_propObject.setProperty(runtime, \\"lat\\", array_object_event_propValue.lat); +array_object_event_propObject.setProperty(runtime, \\"lon\\", array_object_event_propValue.lon); + + auto names = jsi::Array(runtime, array_object_event_propValue.names.size()); + size_t namesIndex = 0; + for (auto namesValue : array_object_event_propValue.names) { + names.setValueAtIndex(runtime, namesIndex++, namesValue); + } + array_object_event_propObject.setProperty(runtime, \\"names\\", names); + + array_object_event_prop.setValueAtIndex(runtime, array_object_event_propIndex++, array_object_event_propObject); + } + $payload.setProperty(runtime, \\"array_object_event_prop\\", array_object_event_prop); + + + auto array_mixed_event_prop = jsi::Array(runtime, $event.array_mixed_event_prop.size()); + size_t array_mixed_event_propIndex = 0; + for (auto array_mixed_event_propValue : $event.array_mixed_event_prop) { + array_mixed_event_prop.setValueAtIndex(runtime, array_mixed_event_propIndex++, jsi::valueFromDynamic(runtime, array_mixed_event_propValue)); + } + $payload.setProperty(runtime, \\"array_mixed_event_prop\\", array_mixed_event_prop); + + return $payload; + }); +} + + void EventsNativeComponentEventEmitter::onEventDirect(OnEventDirect $event) const { dispatchEvent(\\"eventDirect\\", [$event=std::move($event)](jsi::Runtime &runtime) { auto $payload = jsi::Object(runtime); diff --git a/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GenerateEventEmitterH-test.js.snap b/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GenerateEventEmitterH-test.js.snap index e3f05af240c2d9..ca4237ab4d7474 100644 --- a/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GenerateEventEmitterH-test.js.snap +++ b/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GenerateEventEmitterH-test.js.snap @@ -14,12 +14,11 @@ Map { #pragma once #include -#include namespace facebook { namespace react { -class JSI_EXPORT ArrayPropsNativeComponentEventEmitter : public ViewEventEmitter { +class ArrayPropsNativeComponentEventEmitter : public ViewEventEmitter { public: using ViewEventEmitter::ViewEventEmitter; @@ -46,12 +45,11 @@ Map { #pragma once #include -#include namespace facebook { namespace react { -class JSI_EXPORT ArrayPropsNativeComponentEventEmitter : public ViewEventEmitter { +class ArrayPropsNativeComponentEventEmitter : public ViewEventEmitter { public: using ViewEventEmitter::ViewEventEmitter; @@ -78,12 +76,11 @@ Map { #pragma once #include -#include namespace facebook { namespace react { -class JSI_EXPORT BooleanPropNativeComponentEventEmitter : public ViewEventEmitter { +class BooleanPropNativeComponentEventEmitter : public ViewEventEmitter { public: using ViewEventEmitter::ViewEventEmitter; @@ -110,12 +107,11 @@ Map { #pragma once #include -#include namespace facebook { namespace react { -class JSI_EXPORT ColorPropNativeComponentEventEmitter : public ViewEventEmitter { +class ColorPropNativeComponentEventEmitter : public ViewEventEmitter { public: using ViewEventEmitter::ViewEventEmitter; @@ -142,12 +138,11 @@ Map { #pragma once #include -#include namespace facebook { namespace react { -class JSI_EXPORT CommandNativeComponentEventEmitter : public ViewEventEmitter { +class CommandNativeComponentEventEmitter : public ViewEventEmitter { public: using ViewEventEmitter::ViewEventEmitter; @@ -174,12 +169,11 @@ Map { #pragma once #include -#include namespace facebook { namespace react { -class JSI_EXPORT CommandNativeComponentEventEmitter : public ViewEventEmitter { +class CommandNativeComponentEventEmitter : public ViewEventEmitter { public: using ViewEventEmitter::ViewEventEmitter; @@ -206,12 +200,11 @@ Map { #pragma once #include -#include namespace facebook { namespace react { -class JSI_EXPORT DimensionPropNativeComponentEventEmitter : public ViewEventEmitter { +class DimensionPropNativeComponentEventEmitter : public ViewEventEmitter { public: using ViewEventEmitter::ViewEventEmitter; @@ -238,12 +231,11 @@ Map { #pragma once #include -#include namespace facebook { namespace react { -class JSI_EXPORT DoublePropNativeComponentEventEmitter : public ViewEventEmitter { +class DoublePropNativeComponentEventEmitter : public ViewEventEmitter { public: using ViewEventEmitter::ViewEventEmitter; @@ -270,12 +262,11 @@ Map { #pragma once #include -#include namespace facebook { namespace react { -class JSI_EXPORT EventsNestedObjectNativeComponentEventEmitter : public ViewEventEmitter { +class EventsNestedObjectNativeComponentEventEmitter : public ViewEventEmitter { public: using ViewEventEmitter::ViewEventEmitter; @@ -314,12 +305,11 @@ Map { #pragma once #include -#include #include namespace facebook { namespace react { -class JSI_EXPORT EventsNativeComponentEventEmitter : public ViewEventEmitter { +class EventsNativeComponentEventEmitter : public ViewEventEmitter { public: using ViewEventEmitter::ViewEventEmitter; @@ -330,6 +320,32 @@ class JSI_EXPORT EventsNativeComponentEventEmitter : public ViewEventEmitter { Float scale; }; + enum class OnArrayEventTypeString_enum_event_prop { + YES, + NO + }; + + static char const *toString(const OnArrayEventTypeString_enum_event_prop value) { + switch (value) { + case OnArrayEventTypeString_enum_event_prop::YES: return \\"YES\\"; + case OnArrayEventTypeString_enum_event_prop::NO: return \\"NO\\"; + } + } + + struct OnArrayEventTypeArray_object_event_prop { + double lat; + double lon; + std::vector names; + }; + + struct OnArrayEventType { + std::vector bool_array_event_prop; + std::vector string_enum_event_prop; + std::vector> array_array_event_prop; + std::vector array_object_event_prop; + std::vector array_mixed_event_prop; + }; + struct OnEventDirect { bool value; }; @@ -355,6 +371,8 @@ class JSI_EXPORT EventsNativeComponentEventEmitter : public ViewEventEmitter { }; void onChange(OnChange value) const; + void onArrayEventType(OnArrayEventType value) const; + void onEventDirect(OnEventDirect value) const; void onOrientationChange(OnOrientationChange value) const; @@ -383,12 +401,11 @@ Map { #pragma once #include -#include namespace facebook { namespace react { -class JSI_EXPORT InterfaceOnlyComponentEventEmitter : public ViewEventEmitter { +class InterfaceOnlyComponentEventEmitter : public ViewEventEmitter { public: using ViewEventEmitter::ViewEventEmitter; @@ -423,12 +440,11 @@ Map { #pragma once #include -#include namespace facebook { namespace react { -class JSI_EXPORT ExcludedAndroidComponentEventEmitter : public ViewEventEmitter { +class ExcludedAndroidComponentEventEmitter : public ViewEventEmitter { public: using ViewEventEmitter::ViewEventEmitter; @@ -455,12 +471,11 @@ Map { #pragma once #include -#include namespace facebook { namespace react { -class JSI_EXPORT ExcludedAndroidIosComponentEventEmitter : public ViewEventEmitter { +class ExcludedAndroidIosComponentEventEmitter : public ViewEventEmitter { public: using ViewEventEmitter::ViewEventEmitter; @@ -487,19 +502,18 @@ Map { #pragma once #include -#include namespace facebook { namespace react { -class JSI_EXPORT ExcludedIosComponentEventEmitter : public ViewEventEmitter { +class ExcludedIosComponentEventEmitter : public ViewEventEmitter { public: using ViewEventEmitter::ViewEventEmitter; }; -class JSI_EXPORT MultiFileIncludedNativeComponentEventEmitter : public ViewEventEmitter { +class MultiFileIncludedNativeComponentEventEmitter : public ViewEventEmitter { public: using ViewEventEmitter::ViewEventEmitter; @@ -526,12 +540,11 @@ Map { #pragma once #include -#include namespace facebook { namespace react { -class JSI_EXPORT FloatPropNativeComponentEventEmitter : public ViewEventEmitter { +class FloatPropNativeComponentEventEmitter : public ViewEventEmitter { public: using ViewEventEmitter::ViewEventEmitter; @@ -558,12 +571,11 @@ Map { #pragma once #include -#include namespace facebook { namespace react { -class JSI_EXPORT ImagePropNativeComponentEventEmitter : public ViewEventEmitter { +class ImagePropNativeComponentEventEmitter : public ViewEventEmitter { public: using ViewEventEmitter::ViewEventEmitter; @@ -590,12 +602,11 @@ Map { #pragma once #include -#include namespace facebook { namespace react { -class JSI_EXPORT InsetsPropNativeComponentEventEmitter : public ViewEventEmitter { +class InsetsPropNativeComponentEventEmitter : public ViewEventEmitter { public: using ViewEventEmitter::ViewEventEmitter; @@ -622,12 +633,11 @@ Map { #pragma once #include -#include namespace facebook { namespace react { -class JSI_EXPORT Int32EnumPropsNativeComponentEventEmitter : public ViewEventEmitter { +class Int32EnumPropsNativeComponentEventEmitter : public ViewEventEmitter { public: using ViewEventEmitter::ViewEventEmitter; @@ -654,12 +664,11 @@ Map { #pragma once #include -#include namespace facebook { namespace react { -class JSI_EXPORT IntegerPropNativeComponentEventEmitter : public ViewEventEmitter { +class IntegerPropNativeComponentEventEmitter : public ViewEventEmitter { public: using ViewEventEmitter::ViewEventEmitter; @@ -686,12 +695,11 @@ Map { #pragma once #include -#include namespace facebook { namespace react { -class JSI_EXPORT InterfaceOnlyComponentEventEmitter : public ViewEventEmitter { +class InterfaceOnlyComponentEventEmitter : public ViewEventEmitter { public: using ViewEventEmitter::ViewEventEmitter; @@ -720,12 +728,11 @@ Map { #pragma once #include -#include namespace facebook { namespace react { -class JSI_EXPORT MixedPropNativeComponentEventEmitter : public ViewEventEmitter { +class MixedPropNativeComponentEventEmitter : public ViewEventEmitter { public: using ViewEventEmitter::ViewEventEmitter; @@ -752,12 +759,11 @@ Map { #pragma once #include -#include namespace facebook { namespace react { -class JSI_EXPORT ImageColorPropNativeComponentEventEmitter : public ViewEventEmitter { +class ImageColorPropNativeComponentEventEmitter : public ViewEventEmitter { public: using ViewEventEmitter::ViewEventEmitter; @@ -784,12 +790,11 @@ Map { #pragma once #include -#include namespace facebook { namespace react { -class JSI_EXPORT NoPropsNoEventsComponentEventEmitter : public ViewEventEmitter { +class NoPropsNoEventsComponentEventEmitter : public ViewEventEmitter { public: using ViewEventEmitter::ViewEventEmitter; @@ -816,12 +821,11 @@ Map { #pragma once #include -#include namespace facebook { namespace react { -class JSI_EXPORT ObjectPropsEventEmitter : public ViewEventEmitter { +class ObjectPropsEventEmitter : public ViewEventEmitter { public: using ViewEventEmitter::ViewEventEmitter; @@ -848,12 +852,11 @@ Map { #pragma once #include -#include namespace facebook { namespace react { -class JSI_EXPORT PointPropNativeComponentEventEmitter : public ViewEventEmitter { +class PointPropNativeComponentEventEmitter : public ViewEventEmitter { public: using ViewEventEmitter::ViewEventEmitter; @@ -880,12 +883,11 @@ Map { #pragma once #include -#include namespace facebook { namespace react { -class JSI_EXPORT StringEnumPropsNativeComponentEventEmitter : public ViewEventEmitter { +class StringEnumPropsNativeComponentEventEmitter : public ViewEventEmitter { public: using ViewEventEmitter::ViewEventEmitter; @@ -912,12 +914,11 @@ Map { #pragma once #include -#include namespace facebook { namespace react { -class JSI_EXPORT StringPropComponentEventEmitter : public ViewEventEmitter { +class StringPropComponentEventEmitter : public ViewEventEmitter { public: using ViewEventEmitter::ViewEventEmitter; @@ -944,19 +945,18 @@ Map { #pragma once #include -#include namespace facebook { namespace react { -class JSI_EXPORT MultiFile1NativeComponentEventEmitter : public ViewEventEmitter { +class MultiFile1NativeComponentEventEmitter : public ViewEventEmitter { public: using ViewEventEmitter::ViewEventEmitter; }; -class JSI_EXPORT MultiFile2NativeComponentEventEmitter : public ViewEventEmitter { +class MultiFile2NativeComponentEventEmitter : public ViewEventEmitter { public: using ViewEventEmitter::ViewEventEmitter; @@ -983,19 +983,18 @@ Map { #pragma once #include -#include namespace facebook { namespace react { -class JSI_EXPORT MultiComponent1NativeComponentEventEmitter : public ViewEventEmitter { +class MultiComponent1NativeComponentEventEmitter : public ViewEventEmitter { public: using ViewEventEmitter::ViewEventEmitter; }; -class JSI_EXPORT MultiComponent2NativeComponentEventEmitter : public ViewEventEmitter { +class MultiComponent2NativeComponentEventEmitter : public ViewEventEmitter { public: using ViewEventEmitter::ViewEventEmitter; diff --git a/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsH-test.js.snap b/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsH-test.js.snap index 7260cdda760c1b..04a92df053eec9 100644 --- a/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsH-test.js.snap +++ b/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsH-test.js.snap @@ -14,7 +14,6 @@ Map { #pragma once #include -#include #include #include #include @@ -193,7 +192,7 @@ static inline void fromRawValue(const PropsParserContext& context, const RawValu } } -class JSI_EXPORT ArrayPropsNativeComponentProps final : public ViewProps { +class ArrayPropsNativeComponentProps final : public ViewProps { public: ArrayPropsNativeComponentProps() = default; ArrayPropsNativeComponentProps(const PropsParserContext& context, const ArrayPropsNativeComponentProps &sourceProps, const RawProps &rawProps); @@ -233,7 +232,6 @@ Map { */ #pragma once -#include #include #include #include @@ -282,7 +280,7 @@ static inline void fromRawValue(const PropsParserContext& context, const RawValu } } -class JSI_EXPORT ArrayPropsNativeComponentProps final : public ViewProps { +class ArrayPropsNativeComponentProps final : public ViewProps { public: ArrayPropsNativeComponentProps() = default; ArrayPropsNativeComponentProps(const PropsParserContext& context, const ArrayPropsNativeComponentProps &sourceProps, const RawProps &rawProps); @@ -311,14 +309,13 @@ Map { */ #pragma once -#include #include #include namespace facebook { namespace react { -class JSI_EXPORT BooleanPropNativeComponentProps final : public ViewProps { +class BooleanPropNativeComponentProps final : public ViewProps { public: BooleanPropNativeComponentProps() = default; BooleanPropNativeComponentProps(const PropsParserContext& context, const BooleanPropNativeComponentProps &sourceProps, const RawProps &rawProps); @@ -347,7 +344,6 @@ Map { */ #pragma once -#include #include #include #include @@ -355,7 +351,7 @@ Map { namespace facebook { namespace react { -class JSI_EXPORT ColorPropNativeComponentProps final : public ViewProps { +class ColorPropNativeComponentProps final : public ViewProps { public: ColorPropNativeComponentProps() = default; ColorPropNativeComponentProps(const PropsParserContext& context, const ColorPropNativeComponentProps &sourceProps, const RawProps &rawProps); @@ -384,14 +380,13 @@ Map { */ #pragma once -#include #include #include namespace facebook { namespace react { -class JSI_EXPORT CommandNativeComponentProps final : public ViewProps { +class CommandNativeComponentProps final : public ViewProps { public: CommandNativeComponentProps() = default; CommandNativeComponentProps(const PropsParserContext& context, const CommandNativeComponentProps &sourceProps, const RawProps &rawProps); @@ -420,14 +415,13 @@ Map { */ #pragma once -#include #include #include namespace facebook { namespace react { -class JSI_EXPORT CommandNativeComponentProps final : public ViewProps { +class CommandNativeComponentProps final : public ViewProps { public: CommandNativeComponentProps() = default; CommandNativeComponentProps(const PropsParserContext& context, const CommandNativeComponentProps &sourceProps, const RawProps &rawProps); @@ -456,7 +450,6 @@ Map { */ #pragma once -#include #include #include #include @@ -464,7 +457,7 @@ Map { namespace facebook { namespace react { -class JSI_EXPORT DimensionPropNativeComponentProps final : public ViewProps { +class DimensionPropNativeComponentProps final : public ViewProps { public: DimensionPropNativeComponentProps() = default; DimensionPropNativeComponentProps(const PropsParserContext& context, const DimensionPropNativeComponentProps &sourceProps, const RawProps &rawProps); @@ -493,14 +486,13 @@ Map { */ #pragma once -#include #include #include namespace facebook { namespace react { -class JSI_EXPORT DoublePropNativeComponentProps final : public ViewProps { +class DoublePropNativeComponentProps final : public ViewProps { public: DoublePropNativeComponentProps() = default; DoublePropNativeComponentProps(const PropsParserContext& context, const DoublePropNativeComponentProps &sourceProps, const RawProps &rawProps); @@ -534,14 +526,13 @@ Map { */ #pragma once -#include #include #include namespace facebook { namespace react { -class JSI_EXPORT EventsNestedObjectNativeComponentProps final : public ViewProps { +class EventsNestedObjectNativeComponentProps final : public ViewProps { public: EventsNestedObjectNativeComponentProps() = default; EventsNestedObjectNativeComponentProps(const PropsParserContext& context, const EventsNestedObjectNativeComponentProps &sourceProps, const RawProps &rawProps); @@ -570,14 +561,13 @@ Map { */ #pragma once -#include #include #include namespace facebook { namespace react { -class JSI_EXPORT EventsNativeComponentProps final : public ViewProps { +class EventsNativeComponentProps final : public ViewProps { public: EventsNativeComponentProps() = default; EventsNativeComponentProps(const PropsParserContext& context, const EventsNativeComponentProps &sourceProps, const RawProps &rawProps); @@ -606,14 +596,13 @@ Map { */ #pragma once -#include #include #include namespace facebook { namespace react { -class JSI_EXPORT InterfaceOnlyComponentProps final : public ViewProps { +class InterfaceOnlyComponentProps final : public ViewProps { public: InterfaceOnlyComponentProps() = default; InterfaceOnlyComponentProps(const PropsParserContext& context, const InterfaceOnlyComponentProps &sourceProps, const RawProps &rawProps); @@ -642,14 +631,13 @@ Map { */ #pragma once -#include #include #include namespace facebook { namespace react { -class JSI_EXPORT ExcludedAndroidComponentProps final : public ViewProps { +class ExcludedAndroidComponentProps final : public ViewProps { public: ExcludedAndroidComponentProps() = default; ExcludedAndroidComponentProps(const PropsParserContext& context, const ExcludedAndroidComponentProps &sourceProps, const RawProps &rawProps); @@ -678,14 +666,13 @@ Map { */ #pragma once -#include #include #include namespace facebook { namespace react { -class JSI_EXPORT ExcludedAndroidIosComponentProps final : public ViewProps { +class ExcludedAndroidIosComponentProps final : public ViewProps { public: ExcludedAndroidIosComponentProps() = default; ExcludedAndroidIosComponentProps(const PropsParserContext& context, const ExcludedAndroidIosComponentProps &sourceProps, const RawProps &rawProps); @@ -714,14 +701,13 @@ Map { */ #pragma once -#include #include #include namespace facebook { namespace react { -class JSI_EXPORT ExcludedIosComponentProps final : public ViewProps { +class ExcludedIosComponentProps final : public ViewProps { public: ExcludedIosComponentProps() = default; ExcludedIosComponentProps(const PropsParserContext& context, const ExcludedIosComponentProps &sourceProps, const RawProps &rawProps); @@ -731,7 +717,7 @@ class JSI_EXPORT ExcludedIosComponentProps final : public ViewProps { }; -class JSI_EXPORT MultiFileIncludedNativeComponentProps final : public ViewProps { +class MultiFileIncludedNativeComponentProps final : public ViewProps { public: MultiFileIncludedNativeComponentProps() = default; MultiFileIncludedNativeComponentProps(const PropsParserContext& context, const MultiFileIncludedNativeComponentProps &sourceProps, const RawProps &rawProps); @@ -760,14 +746,13 @@ Map { */ #pragma once -#include #include #include namespace facebook { namespace react { -class JSI_EXPORT FloatPropNativeComponentProps final : public ViewProps { +class FloatPropNativeComponentProps final : public ViewProps { public: FloatPropNativeComponentProps() = default; FloatPropNativeComponentProps(const PropsParserContext& context, const FloatPropNativeComponentProps &sourceProps, const RawProps &rawProps); @@ -801,7 +786,6 @@ Map { */ #pragma once -#include #include #include #include @@ -809,7 +793,7 @@ Map { namespace facebook { namespace react { -class JSI_EXPORT ImagePropNativeComponentProps final : public ViewProps { +class ImagePropNativeComponentProps final : public ViewProps { public: ImagePropNativeComponentProps() = default; ImagePropNativeComponentProps(const PropsParserContext& context, const ImagePropNativeComponentProps &sourceProps, const RawProps &rawProps); @@ -838,7 +822,6 @@ Map { */ #pragma once -#include #include #include #include @@ -846,7 +829,7 @@ Map { namespace facebook { namespace react { -class JSI_EXPORT InsetsPropNativeComponentProps final : public ViewProps { +class InsetsPropNativeComponentProps final : public ViewProps { public: InsetsPropNativeComponentProps() = default; InsetsPropNativeComponentProps(const PropsParserContext& context, const InsetsPropNativeComponentProps &sourceProps, const RawProps &rawProps); @@ -875,7 +858,6 @@ Map { */ #pragma once -#include #include #include @@ -909,7 +891,7 @@ static inline std::string toString(const Int32EnumPropsNativeComponentMaxInterva } } -class JSI_EXPORT Int32EnumPropsNativeComponentProps final : public ViewProps { +class Int32EnumPropsNativeComponentProps final : public ViewProps { public: Int32EnumPropsNativeComponentProps() = default; Int32EnumPropsNativeComponentProps(const PropsParserContext& context, const Int32EnumPropsNativeComponentProps &sourceProps, const RawProps &rawProps); @@ -938,14 +920,13 @@ Map { */ #pragma once -#include #include #include namespace facebook { namespace react { -class JSI_EXPORT IntegerPropNativeComponentProps final : public ViewProps { +class IntegerPropNativeComponentProps final : public ViewProps { public: IntegerPropNativeComponentProps() = default; IntegerPropNativeComponentProps(const PropsParserContext& context, const IntegerPropNativeComponentProps &sourceProps, const RawProps &rawProps); @@ -976,14 +957,13 @@ Map { */ #pragma once -#include #include #include namespace facebook { namespace react { -class JSI_EXPORT InterfaceOnlyComponentProps final : public ViewProps { +class InterfaceOnlyComponentProps final : public ViewProps { public: InterfaceOnlyComponentProps() = default; InterfaceOnlyComponentProps(const PropsParserContext& context, const InterfaceOnlyComponentProps &sourceProps, const RawProps &rawProps); @@ -1012,14 +992,13 @@ Map { */ #pragma once -#include #include #include namespace facebook { namespace react { -class JSI_EXPORT MixedPropNativeComponentProps final : public ViewProps { +class MixedPropNativeComponentProps final : public ViewProps { public: MixedPropNativeComponentProps() = default; MixedPropNativeComponentProps(const PropsParserContext& context, const MixedPropNativeComponentProps &sourceProps, const RawProps &rawProps); @@ -1048,7 +1027,6 @@ Map { */ #pragma once -#include #include #include #include @@ -1058,7 +1036,7 @@ Map { namespace facebook { namespace react { -class JSI_EXPORT ImageColorPropNativeComponentProps final : public ViewProps { +class ImageColorPropNativeComponentProps final : public ViewProps { public: ImageColorPropNativeComponentProps() = default; ImageColorPropNativeComponentProps(const PropsParserContext& context, const ImageColorPropNativeComponentProps &sourceProps, const RawProps &rawProps); @@ -1090,14 +1068,13 @@ Map { */ #pragma once -#include #include #include namespace facebook { namespace react { -class JSI_EXPORT NoPropsNoEventsComponentProps final : public ViewProps { +class NoPropsNoEventsComponentProps final : public ViewProps { public: NoPropsNoEventsComponentProps() = default; NoPropsNoEventsComponentProps(const PropsParserContext& context, const NoPropsNoEventsComponentProps &sourceProps, const RawProps &rawProps); @@ -1126,7 +1103,6 @@ Map { */ #pragma once -#include #include #include #include @@ -1353,7 +1329,7 @@ static inline void fromRawValue(const PropsParserContext& context, const RawValu static inline std::string toString(const ObjectPropsObjectPropStruct &value) { return \\"[Object ObjectPropsObjectPropStruct]\\"; } -class JSI_EXPORT ObjectPropsProps final : public ViewProps { +class ObjectPropsProps final : public ViewProps { public: ObjectPropsProps() = default; ObjectPropsProps(const PropsParserContext& context, const ObjectPropsProps &sourceProps, const RawProps &rawProps); @@ -1382,7 +1358,6 @@ Map { */ #pragma once -#include #include #include #include @@ -1390,7 +1365,7 @@ Map { namespace facebook { namespace react { -class JSI_EXPORT PointPropNativeComponentProps final : public ViewProps { +class PointPropNativeComponentProps final : public ViewProps { public: PointPropNativeComponentProps() = default; PointPropNativeComponentProps(const PropsParserContext& context, const PointPropNativeComponentProps &sourceProps, const RawProps &rawProps); @@ -1419,7 +1394,6 @@ Map { */ #pragma once -#include #include #include @@ -1444,7 +1418,7 @@ static inline std::string toString(const StringEnumPropsNativeComponentAlignment } } -class JSI_EXPORT StringEnumPropsNativeComponentProps final : public ViewProps { +class StringEnumPropsNativeComponentProps final : public ViewProps { public: StringEnumPropsNativeComponentProps() = default; StringEnumPropsNativeComponentProps(const PropsParserContext& context, const StringEnumPropsNativeComponentProps &sourceProps, const RawProps &rawProps); @@ -1473,14 +1447,13 @@ Map { */ #pragma once -#include #include #include namespace facebook { namespace react { -class JSI_EXPORT StringPropComponentProps final : public ViewProps { +class StringPropComponentProps final : public ViewProps { public: StringPropComponentProps() = default; StringPropComponentProps(const PropsParserContext& context, const StringPropComponentProps &sourceProps, const RawProps &rawProps); @@ -1510,14 +1483,13 @@ Map { */ #pragma once -#include #include #include namespace facebook { namespace react { -class JSI_EXPORT MultiFile1NativeComponentProps final : public ViewProps { +class MultiFile1NativeComponentProps final : public ViewProps { public: MultiFile1NativeComponentProps() = default; MultiFile1NativeComponentProps(const PropsParserContext& context, const MultiFile1NativeComponentProps &sourceProps, const RawProps &rawProps); @@ -1527,7 +1499,7 @@ class JSI_EXPORT MultiFile1NativeComponentProps final : public ViewProps { bool disabled{false}; }; -class JSI_EXPORT MultiFile2NativeComponentProps final : public ViewProps { +class MultiFile2NativeComponentProps final : public ViewProps { public: MultiFile2NativeComponentProps() = default; MultiFile2NativeComponentProps(const PropsParserContext& context, const MultiFile2NativeComponentProps &sourceProps, const RawProps &rawProps); @@ -1556,14 +1528,13 @@ Map { */ #pragma once -#include #include #include namespace facebook { namespace react { -class JSI_EXPORT MultiComponent1NativeComponentProps final : public ViewProps { +class MultiComponent1NativeComponentProps final : public ViewProps { public: MultiComponent1NativeComponentProps() = default; MultiComponent1NativeComponentProps(const PropsParserContext& context, const MultiComponent1NativeComponentProps &sourceProps, const RawProps &rawProps); @@ -1573,7 +1544,7 @@ class JSI_EXPORT MultiComponent1NativeComponentProps final : public ViewProps { bool disabled{false}; }; -class JSI_EXPORT MultiComponent2NativeComponentProps final : public ViewProps { +class MultiComponent2NativeComponentProps final : public ViewProps { public: MultiComponent2NativeComponentProps() = default; MultiComponent2NativeComponentProps(const PropsParserContext& context, const MultiComponent2NativeComponentProps &sourceProps, const RawProps &rawProps); diff --git a/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GenerateViewConfigJs-test.js.snap b/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GenerateViewConfigJs-test.js.snap index bc616a220e0b6a..e88cd1abe901cc 100644 --- a/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GenerateViewConfigJs-test.js.snap +++ b/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GenerateViewConfigJs-test.js.snap @@ -394,6 +394,13 @@ export const __INTERNAL_VIEW_CONFIG = { }, }, + topArrayEventType: { + phasedRegistrationNames: { + captured: 'onArrayEventTypeCapture', + bubbled: 'onArrayEventType', + }, + }, + topEnd: { phasedRegistrationNames: { captured: 'onEndCapture', @@ -421,6 +428,7 @@ export const __INTERNAL_VIEW_CONFIG = { ...ConditionallyIgnoredEventHandlers({ onChange: true, + onArrayEventType: true, onEventDirect: true, onOrientationChange: true, onEnd: true, diff --git a/packages/react-native-codegen/src/parsers/__tests__/error-utils-test.js b/packages/react-native-codegen/src/parsers/__tests__/error-utils-test.js index 4806672ad7c8ae..49174e96ca69c5 100644 --- a/packages/react-native-codegen/src/parsers/__tests__/error-utils-test.js +++ b/packages/react-native-codegen/src/parsers/__tests__/error-utils-test.js @@ -33,6 +33,8 @@ const { throwIfPartialNotAnnotatingTypeParameter, throwIfPartialWithMoreParameter, throwIfMoreThanOneCodegenNativecommands, + throwIfEventHasNoName, + throwIfBubblingTypeIsNull, } = require('../error-utils'); const { UnsupportedModulePropertyParserError, @@ -905,3 +907,69 @@ describe('throwIfMoreThanOneConfig', () => { }).not.toThrow(); }); }); + +describe('throwIfEventHasNoName', () => { + const flowParser = new FlowParser(); + const typescriptParser = new TypeScriptParser(); + + it('throws an error if typeAnnotation of event have no name in Flow', () => { + const typeAnnotation = {}; + expect(() => { + throwIfEventHasNoName(typeAnnotation, flowParser); + }).toThrowError(`typeAnnotation of event doesn't have a name`); + }); + + it('does not throw an error if typeAnnotation of event have a name in Flow', () => { + const typeAnnotation = { + id: { + name: 'BubblingEventHandler', + }, + }; + + expect(() => { + throwIfEventHasNoName(typeAnnotation, flowParser); + }).not.toThrow(); + }); + + it('throws an error if typeAnnotation of event have no name in TypeScript', () => { + const typeAnnotation = {}; + + expect(() => { + throwIfEventHasNoName(typeAnnotation, typescriptParser); + }).toThrowError(`typeAnnotation of event doesn't have a name`); + }); + + it('does not throw an error if typeAnnotation of event have a name in TypeScript', () => { + const typeAnnotation = { + typeName: { + name: 'BubblingEventHandler', + }, + }; + + expect(() => { + throwIfEventHasNoName(typeAnnotation, typescriptParser); + }).not.toThrow(); + }); +}); + +describe('throwIfBubblingTypeIsNull', () => { + it('throw an error if unable to determine event bubbling type', () => { + const bubblingType = null; + const eventName = 'Event'; + + expect(() => { + throwIfBubblingTypeIsNull(bubblingType, eventName); + }).toThrowError( + `Unable to determine event bubbling type for "${eventName}"`, + ); + }); + + it('does not throw an error if able to determine event bubbling type', () => { + const bubblingType = 'direct'; + const eventName = 'Event'; + + expect(() => { + throwIfBubblingTypeIsNull(bubblingType, eventName); + }).not.toThrow(); + }); +}); diff --git a/packages/react-native-codegen/src/parsers/__tests__/parsers-test.js b/packages/react-native-codegen/src/parsers/__tests__/parsers-test.js index 9418c0539e8831..9339a4529b4173 100644 --- a/packages/react-native-codegen/src/parsers/__tests__/parsers-test.js +++ b/packages/react-native-codegen/src/parsers/__tests__/parsers-test.js @@ -270,6 +270,41 @@ describe('FlowParser', () => { ).toEqual(expected); }); }); + + describe('isOptionalProperty', () => { + it('when property is optional', () => { + const property = { + value: { + type: 'TypeAnnotation', + }, + optional: true, + }; + + expect(parser.isOptionalProperty(property)).toEqual(true); + }); + + it('when property is not optional', () => { + const property = { + value: { + type: 'TypeAnnotation', + }, + optional: false, + }; + + expect(parser.isOptionalProperty(property)).toEqual(false); + }); + + it('when property value type is NullableTypeAnnotation', () => { + const property = { + value: { + type: 'NullableTypeAnnotation', + }, + optional: false, + }; + + expect(parser.isOptionalProperty(property)).toEqual(true); + }); + }); }); describe('TypeScriptParser', () => { @@ -531,4 +566,20 @@ describe('TypeScriptParser', () => { ).toEqual(expected); }); }); + + describe('isOptionalProperty', () => { + it('when property is optional', () => { + const property = { + optional: true, + }; + expect(parser.isOptionalProperty(property)).toEqual(true); + }); + + it('when property is undefined or not optional', () => { + const property = { + optional: false, + }; + expect(parser.isOptionalProperty(property)).toEqual(false); + }); + }); }); diff --git a/packages/react-native-codegen/src/parsers/error-utils.js b/packages/react-native-codegen/src/parsers/error-utils.js index 87adc6a7af1bee..df9fe1bd47db5e 100644 --- a/packages/react-native-codegen/src/parsers/error-utils.js +++ b/packages/react-native-codegen/src/parsers/error-utils.js @@ -310,6 +310,26 @@ function throwIfMoreThanOneConfig(foundConfigs: Array<{[string]: string}>) { } } +function throwIfEventHasNoName(typeAnnotation: $FlowFixMe, parser: Parser) { + const name = + parser.language() === 'Flow' ? typeAnnotation.id : typeAnnotation.typeName; + + if (!name) { + throw new Error("typeAnnotation of event doesn't have a name"); + } +} + +function throwIfBubblingTypeIsNull( + bubblingType: ?('direct' | 'bubble'), + eventName: string, +) { + if (!bubblingType) { + throw new Error( + `Unable to determine event bubbling type for "${eventName}"`, + ); + } +} + module.exports = { throwIfModuleInterfaceIsMisnamed, throwIfUnsupportedFunctionReturnTypeAnnotationParserError, @@ -330,4 +350,6 @@ module.exports = { throwIfMoreThanOneCodegenNativecommands, throwIfConfigNotfound, throwIfMoreThanOneConfig, + throwIfEventHasNoName, + throwIfBubblingTypeIsNull, }; diff --git a/packages/react-native-codegen/src/parsers/flow/components/__test_fixtures__/fixtures.js b/packages/react-native-codegen/src/parsers/flow/components/__test_fixtures__/fixtures.js index 3a724b3411172b..64cefa676f6bf9 100644 --- a/packages/react-native-codegen/src/parsers/flow/components/__test_fixtures__/fixtures.js +++ b/packages/react-native-codegen/src/parsers/flow/components/__test_fixtures__/fixtures.js @@ -84,6 +84,57 @@ const EVENT_DEFINITION = ` object_readonly_optional_both?: ?$ReadOnly<{ int32_optional_both?: ?Int32, }>, + + boolean_array_required: $ReadOnlyArray, + boolean_array_optional_key?: boolean[], + boolean_array_optional_value: ?$ReadOnlyArray, + boolean_array_optional_both?: ?boolean[], + + string_array_required: $ReadOnlyArray, + string_array_optional_key?: string[], + string_array_optional_value: ?$ReadOnlyArray, + string_array_optional_both?: ?string[], + + double_array_required: $ReadOnlyArray, + double_array_optional_key?: Double[], + double_array_optional_value: ?$ReadOnlyArray, + double_array_optional_both?: ?Double[], + + float_array_required: $ReadOnlyArray, + float_array_optional_key?: Float[], + float_array_optional_value: ?$ReadOnlyArray, + float_array_optional_both?: ?Float[], + + int32_array_required: $ReadOnlyArray, + int32_array_optional_key?: Int32[], + int32_array_optional_value: ?$ReadOnlyArray, + int32_array_optional_both?: ?Int32[], + + enum_array_required: $ReadOnlyArray<('small' | 'large')>, + enum_array_optional_key?: ('small' | 'large')[], + enum_array_optional_value: ?$ReadOnlyArray<('small' | 'large')>, + enum_array_optional_both?: ?('small' | 'large')[], + + object_array_required: $ReadOnlyArray<{ + boolean_required: boolean, + }>, + + object_array_optional_key?: { + string_optional_key?: string, + }[], + + object_array_optional_value: ?$ReadOnlyArray<{ + float_optional_value: ?Float, + }>, + + object_array_optional_both?: ?{ + int32_optional_both?: ?Int32, + }[], + + int32_array_array_required: $ReadOnlyArray<$ReadOnlyArray>, + int32_array_array_optional_key?: Int32[][], + int32_array_array_optional_value: ?$ReadOnlyArray<$ReadOnlyArray>, + int32_array_array_optional_both?: ?Int32[][], `; const ONE_OF_EACH_PROP_EVENT_DEFAULT_AND_OPTIONS = ` diff --git a/packages/react-native-codegen/src/parsers/flow/components/__tests__/__snapshots__/component-parser-test.js.snap b/packages/react-native-codegen/src/parsers/flow/components/__tests__/__snapshots__/component-parser-test.js.snap index f3ec2606cfc16c..dbcae681e81b9a 100644 --- a/packages/react-native-codegen/src/parsers/flow/components/__tests__/__snapshots__/component-parser-test.js.snap +++ b/packages/react-native-codegen/src/parsers/flow/components/__tests__/__snapshots__/component-parser-test.js.snap @@ -1843,384 +1843,389 @@ exports[`RN Codegen Flow Parser can generate fixture COMMANDS_EVENTS_TYPES_EXPOR } ] } - } - ] - } - } - }, - { - 'name': 'onBubblingEventDefinedInlineWithPaperName', - 'optional': false, - 'bubblingType': 'bubble', - 'paperTopLevelNameDeprecated': 'paperBubblingEventDefinedInlineWithPaperName', - 'typeAnnotation': { - 'type': 'EventTypeAnnotation', - 'argument': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ + }, { - 'name': 'boolean_required', + 'name': 'boolean_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'boolean_optional_key', + 'name': 'boolean_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'boolean_optional_value', + 'name': 'boolean_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'boolean_optional_both', + 'name': 'boolean_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'string_required', + 'name': 'string_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'string_optional_key', + 'name': 'string_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'string_optional_value', + 'name': 'string_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'string_optional_both', + 'name': 'string_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'double_required', + 'name': 'double_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } } }, { - 'name': 'double_optional_key', + 'name': 'double_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } } }, { - 'name': 'double_optional_value', + 'name': 'double_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } } }, { - 'name': 'double_optional_both', + 'name': 'double_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } } }, { - 'name': 'float_required', + 'name': 'float_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'float_optional_key', + 'name': 'float_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'float_optional_value', + 'name': 'float_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'float_optional_both', + 'name': 'float_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'int32_required', + 'name': 'int32_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'int32_optional_key', + 'name': 'int32_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'int32_optional_value', + 'name': 'int32_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'int32_optional_both', + 'name': 'int32_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'enum_required', + 'name': 'enum_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } } }, { - 'name': 'enum_optional_key', + 'name': 'enum_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } } }, { - 'name': 'enum_optional_value', + 'name': 'enum_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } } }, { - 'name': 'enum_optional_both', + 'name': 'enum_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } } }, { - 'name': 'object_required', + 'name': 'object_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'boolean_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_optional_key', + 'name': 'object_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'string_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_optional_value', + 'name': 'object_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'float_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_optional_both', + 'name': 'object_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'int32_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_required_nested_2_layers', + 'name': 'int32_array_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'object_optional_nested_1_layer', - 'optional': true, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'boolean_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } - }, - { - 'name': 'string_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation' - } - }, - { - 'name': 'double_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' - } - }, - { - 'name': 'float_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' - } - }, - { - 'name': 'int32_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } - } - ] - } - } - ] - } - }, - { - 'name': 'object_readonly_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'boolean_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] + } } }, { - 'name': 'object_readonly_optional_key', + 'name': 'int32_array_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'string_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] + } } }, { - 'name': 'object_readonly_optional_value', + 'name': 'int32_array_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'float_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] + } } }, { - 'name': 'object_readonly_optional_both', + 'name': 'int32_array_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'int32_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] + } } } ] @@ -2228,9 +2233,10 @@ exports[`RN Codegen Flow Parser can generate fixture COMMANDS_EVENTS_TYPES_EXPOR } }, { - 'name': 'onDirectEventDefinedInline', + 'name': 'onBubblingEventDefinedInlineWithPaperName', 'optional': false, - 'bubblingType': 'direct', + 'bubblingType': 'bubble', + 'paperTopLevelNameDeprecated': 'paperBubblingEventDefinedInlineWithPaperName', 'typeAnnotation': { 'type': 'EventTypeAnnotation', 'argument': { @@ -2600,641 +2606,399 @@ exports[`RN Codegen Flow Parser can generate fixture COMMANDS_EVENTS_TYPES_EXPOR } ] } - } - ] - } - } - }, - { - 'name': 'onDirectEventDefinedInlineWithPaperName', - 'optional': false, - 'bubblingType': 'direct', - 'paperTopLevelNameDeprecated': 'paperDirectEventDefinedInlineWithPaperName', - 'typeAnnotation': { - 'type': 'EventTypeAnnotation', - 'argument': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ + }, { - 'name': 'boolean_required', + 'name': 'boolean_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'boolean_optional_key', + 'name': 'boolean_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'boolean_optional_value', + 'name': 'boolean_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'boolean_optional_both', + 'name': 'boolean_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'string_required', + 'name': 'string_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'string_optional_key', + 'name': 'string_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'string_optional_value', + 'name': 'string_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'string_optional_both', + 'name': 'string_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'double_required', + 'name': 'double_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } } }, { - 'name': 'double_optional_key', + 'name': 'double_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } } }, { - 'name': 'double_optional_value', + 'name': 'double_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } } }, { - 'name': 'double_optional_both', + 'name': 'double_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } } }, { - 'name': 'float_required', + 'name': 'float_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'float_optional_key', + 'name': 'float_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'float_optional_value', + 'name': 'float_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'float_optional_both', + 'name': 'float_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'int32_required', + 'name': 'int32_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'int32_optional_key', + 'name': 'int32_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'int32_optional_value', + 'name': 'int32_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'int32_optional_both', + 'name': 'int32_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'enum_required', + 'name': 'enum_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } } }, { - 'name': 'enum_optional_key', + 'name': 'enum_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } } }, { - 'name': 'enum_optional_value', + 'name': 'enum_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } } }, { - 'name': 'enum_optional_both', + 'name': 'enum_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } } }, { - 'name': 'object_required', + 'name': 'object_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'boolean_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' - } - } - ] - } - }, - { - 'name': 'object_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'string_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_optional_value', + 'name': 'object_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'float_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_optional_both', + 'name': 'object_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'int32_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_required_nested_2_layers', - 'optional': false, + 'name': 'object_array_optional_both', + 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'object_optional_nested_1_layer', - 'optional': true, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'boolean_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } - }, - { - 'name': 'string_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation' - } - }, - { - 'name': 'double_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' - } - }, - { - 'name': 'float_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' - } - }, - { - 'name': 'int32_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } - } - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_readonly_required', + 'name': 'int32_array_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'boolean_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] + } } }, { - 'name': 'object_readonly_optional_key', + 'name': 'int32_array_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'string_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] + } } }, { - 'name': 'object_readonly_optional_value', + 'name': 'int32_array_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'float_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] + } } }, { - 'name': 'object_readonly_optional_both', + 'name': 'int32_array_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'int32_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] + } } } ] } } - } - ], - 'props': [], - 'commands': [ - { - 'name': 'scrollTo', - 'optional': false, - 'typeAnnotation': { - 'type': 'FunctionTypeAnnotation', - 'params': [ - { - 'name': 'y', - 'optional': false, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } - }, - { - 'name': 'animated', - 'optional': false, - 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' - } - } - ], - 'returnTypeAnnotation': { - 'type': 'VoidTypeAnnotation' - } - } - } - ] - } - } - } - } -}" -`; - -exports[`RN Codegen Flow Parser can generate fixture COMMANDS_WITH_EXTERNAL_TYPES 1`] = ` -"{ - 'modules': { - 'Module': { - 'type': 'Component', - 'components': { - 'Module': { - 'extendsProps': [ - { - 'type': 'ReactNativeBuiltInType', - 'knownTypeName': 'ReactNativeCoreViewProps' - } - ], - 'events': [], - 'props': [], - 'commands': [ + }, { - 'name': 'scrollTo', + 'name': 'onDirectEventDefinedInline', 'optional': false, - 'typeAnnotation': { - 'type': 'FunctionTypeAnnotation', - 'params': [ - { - 'name': 'y', - 'optional': false, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } - }, - { - 'name': 'animated', - 'optional': false, - 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' - } - } - ], - 'returnTypeAnnotation': { - 'type': 'VoidTypeAnnotation' - } - } - } - ] - } - } - } - } -}" -`; - -exports[`RN Codegen Flow Parser can generate fixture EVENTS_DEFINED_AS_NULL_INLINE 1`] = ` -"{ - 'modules': { - 'Module': { - 'type': 'Component', - 'components': { - 'Module': { - 'extendsProps': [ - { - 'type': 'ReactNativeBuiltInType', - 'knownTypeName': 'ReactNativeCoreViewProps' - } - ], - 'events': [ - { - 'name': 'onDirectEventDefinedInlineNull', - 'optional': false, - 'bubblingType': 'direct', - 'typeAnnotation': { - 'type': 'EventTypeAnnotation', - 'argument': { - 'type': 'ObjectTypeAnnotation', - 'properties': [] - } - } - }, - { - 'name': 'onDirectEventDefinedInlineNullOptionalKey', - 'optional': true, - 'bubblingType': 'direct', - 'typeAnnotation': { - 'type': 'EventTypeAnnotation', - 'argument': { - 'type': 'ObjectTypeAnnotation', - 'properties': [] - } - } - }, - { - 'name': 'onDirectEventDefinedInlineNullOptionalValue', - 'optional': true, - 'bubblingType': 'direct', - 'typeAnnotation': { - 'type': 'EventTypeAnnotation', - 'argument': { - 'type': 'ObjectTypeAnnotation', - 'properties': [] - } - } - }, - { - 'name': 'onDirectEventDefinedInlineNullOptionalBoth', - 'optional': true, - 'bubblingType': 'direct', - 'typeAnnotation': { - 'type': 'EventTypeAnnotation', - 'argument': { - 'type': 'ObjectTypeAnnotation', - 'properties': [] - } - } - }, - { - 'name': 'onDirectEventDefinedInlineNullWithPaperName', - 'optional': true, - 'bubblingType': 'direct', - 'paperTopLevelNameDeprecated': 'paperDirectEventDefinedInlineNullWithPaperName', - 'typeAnnotation': { - 'type': 'EventTypeAnnotation', - 'argument': { - 'type': 'ObjectTypeAnnotation', - 'properties': [] - } - } - }, - { - 'name': 'onBubblingEventDefinedInlineNull', - 'optional': false, - 'bubblingType': 'bubble', - 'typeAnnotation': { - 'type': 'EventTypeAnnotation', - 'argument': { - 'type': 'ObjectTypeAnnotation', - 'properties': [] - } - } - }, - { - 'name': 'onBubblingEventDefinedInlineNullOptionalKey', - 'optional': true, - 'bubblingType': 'bubble', - 'typeAnnotation': { - 'type': 'EventTypeAnnotation', - 'argument': { - 'type': 'ObjectTypeAnnotation', - 'properties': [] - } - } - }, - { - 'name': 'onBubblingEventDefinedInlineNullOptionalValue', - 'optional': true, - 'bubblingType': 'bubble', - 'typeAnnotation': { - 'type': 'EventTypeAnnotation', - 'argument': { - 'type': 'ObjectTypeAnnotation', - 'properties': [] - } - } - }, - { - 'name': 'onBubblingEventDefinedInlineNullOptionalBoth', - 'optional': true, - 'bubblingType': 'bubble', - 'typeAnnotation': { - 'type': 'EventTypeAnnotation', - 'argument': { - 'type': 'ObjectTypeAnnotation', - 'properties': [] - } - } - }, - { - 'name': 'onBubblingEventDefinedInlineNullWithPaperName', - 'optional': true, - 'bubblingType': 'bubble', - 'paperTopLevelNameDeprecated': 'paperBubblingEventDefinedInlineNullWithPaperName', - 'typeAnnotation': { - 'type': 'EventTypeAnnotation', - 'argument': { - 'type': 'ObjectTypeAnnotation', - 'properties': [] - } - } - } - ], - 'props': [], - 'commands': [] - } - } - } - } -}" -`; - -exports[`RN Codegen Flow Parser can generate fixture EVENTS_DEFINED_INLINE_WITH_ALL_TYPES 1`] = ` -"{ - 'modules': { - 'Module': { - 'type': 'Component', - 'components': { - 'Module': { - 'extendsProps': [ - { - 'type': 'ReactNativeBuiltInType', - 'knownTypeName': 'ReactNativeCoreViewProps' - } - ], - 'events': [ - { - 'name': 'onDirectEventDefinedInline', - 'optional': false, - 'bubblingType': 'direct', + 'bubblingType': 'direct', 'typeAnnotation': { 'type': 'EventTypeAnnotation', 'argument': { @@ -3604,383 +3368,389 @@ exports[`RN Codegen Flow Parser can generate fixture EVENTS_DEFINED_INLINE_WITH_ } ] } - } - ] - } - } - }, - { - 'name': 'onDirectEventDefinedInlineOptionalKey', - 'optional': true, - 'bubblingType': 'direct', - 'typeAnnotation': { - 'type': 'EventTypeAnnotation', - 'argument': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ + }, { - 'name': 'boolean_required', + 'name': 'boolean_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'boolean_optional_key', + 'name': 'boolean_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'boolean_optional_value', + 'name': 'boolean_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'boolean_optional_both', + 'name': 'boolean_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'string_required', + 'name': 'string_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'string_optional_key', + 'name': 'string_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'string_optional_value', + 'name': 'string_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'string_optional_both', + 'name': 'string_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'double_required', + 'name': 'double_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } } }, { - 'name': 'double_optional_key', + 'name': 'double_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } } }, { - 'name': 'double_optional_value', + 'name': 'double_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } } }, { - 'name': 'double_optional_both', + 'name': 'double_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } } }, { - 'name': 'float_required', + 'name': 'float_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'float_optional_key', + 'name': 'float_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'float_optional_value', + 'name': 'float_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'float_optional_both', + 'name': 'float_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'int32_required', + 'name': 'int32_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'int32_optional_key', + 'name': 'int32_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'int32_optional_value', + 'name': 'int32_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'int32_optional_both', + 'name': 'int32_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'enum_required', + 'name': 'enum_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } } }, { - 'name': 'enum_optional_key', + 'name': 'enum_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } } }, { - 'name': 'enum_optional_value', + 'name': 'enum_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } } }, { - 'name': 'enum_optional_both', + 'name': 'enum_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } } }, { - 'name': 'object_required', + 'name': 'object_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'boolean_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_optional_key', + 'name': 'object_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'string_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_optional_value', + 'name': 'object_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'float_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_optional_both', + 'name': 'object_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'int32_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } - } - ] - } - }, - { - 'name': 'object_required_nested_2_layers', - 'optional': false, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'object_optional_nested_1_layer', - 'optional': true, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'boolean_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } - }, - { - 'name': 'string_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation' - } - }, - { - 'name': 'double_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' - } - }, - { - 'name': 'float_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' - } - }, - { - 'name': 'int32_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } - } - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_readonly_required', + 'name': 'int32_array_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'boolean_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] + } } }, { - 'name': 'object_readonly_optional_key', + 'name': 'int32_array_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'string_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] + } } }, { - 'name': 'object_readonly_optional_value', + 'name': 'int32_array_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'float_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] + } } }, { - 'name': 'object_readonly_optional_both', + 'name': 'int32_array_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'int32_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] + } } } ] @@ -3988,9 +3758,10 @@ exports[`RN Codegen Flow Parser can generate fixture EVENTS_DEFINED_INLINE_WITH_ } }, { - 'name': 'onDirectEventDefinedInlineOptionalValue', - 'optional': true, + 'name': 'onDirectEventDefinedInlineWithPaperName', + 'optional': false, 'bubblingType': 'direct', + 'paperTopLevelNameDeprecated': 'paperDirectEventDefinedInlineWithPaperName', 'typeAnnotation': { 'type': 'EventTypeAnnotation', 'argument': { @@ -4360,447 +4131,699 @@ exports[`RN Codegen Flow Parser can generate fixture EVENTS_DEFINED_INLINE_WITH_ } ] } - } - ] - } - } - }, - { - 'name': 'onDirectEventDefinedInlineOptionalBoth', - 'optional': true, - 'bubblingType': 'direct', - 'typeAnnotation': { - 'type': 'EventTypeAnnotation', - 'argument': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ + }, { - 'name': 'boolean_required', + 'name': 'boolean_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'boolean_optional_key', + 'name': 'boolean_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'boolean_optional_value', + 'name': 'boolean_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'boolean_optional_both', + 'name': 'boolean_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'string_required', + 'name': 'string_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'string_optional_key', + 'name': 'string_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'string_optional_value', + 'name': 'string_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'string_optional_both', + 'name': 'string_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'double_required', + 'name': 'double_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } } }, { - 'name': 'double_optional_key', + 'name': 'double_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } } }, { - 'name': 'double_optional_value', + 'name': 'double_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } } }, { - 'name': 'double_optional_both', + 'name': 'double_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } } }, { - 'name': 'float_required', + 'name': 'float_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'float_optional_key', + 'name': 'float_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'float_optional_value', + 'name': 'float_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'float_optional_both', + 'name': 'float_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'int32_required', + 'name': 'int32_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'int32_optional_key', + 'name': 'int32_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'int32_optional_value', + 'name': 'int32_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'int32_optional_both', + 'name': 'int32_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'enum_required', + 'name': 'enum_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } } }, { - 'name': 'enum_optional_key', + 'name': 'enum_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } } }, { - 'name': 'enum_optional_value', + 'name': 'enum_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } } }, { - 'name': 'enum_optional_both', + 'name': 'enum_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } } }, { - 'name': 'object_required', + 'name': 'object_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'boolean_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_optional_key', + 'name': 'object_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'string_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_optional_value', + 'name': 'object_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'float_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_optional_both', + 'name': 'object_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'int32_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_required_nested_2_layers', + 'name': 'int32_array_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'object_optional_nested_1_layer', - 'optional': true, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'boolean_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } - }, - { - 'name': 'string_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation' - } - }, - { - 'name': 'double_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' - } - }, - { - 'name': 'float_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' - } - }, - { - 'name': 'int32_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } - } - ] - } - } - ] - } - }, - { - 'name': 'object_readonly_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'boolean_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] + } } }, { - 'name': 'object_readonly_optional_key', + 'name': 'int32_array_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'string_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] + } } }, { - 'name': 'object_readonly_optional_value', + 'name': 'int32_array_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'float_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] + } } }, { - 'name': 'object_readonly_optional_both', + 'name': 'int32_array_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'int32_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] + } } } ] } } + } + ], + 'props': [], + 'commands': [ + { + 'name': 'scrollTo', + 'optional': false, + 'typeAnnotation': { + 'type': 'FunctionTypeAnnotation', + 'params': [ + { + 'name': 'y', + 'optional': false, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'animated', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ], + 'returnTypeAnnotation': { + 'type': 'VoidTypeAnnotation' + } + } + } + ] + } + } + } + } +}" +`; + +exports[`RN Codegen Flow Parser can generate fixture COMMANDS_WITH_EXTERNAL_TYPES 1`] = ` +"{ + 'modules': { + 'Module': { + 'type': 'Component', + 'components': { + 'Module': { + 'extendsProps': [ + { + 'type': 'ReactNativeBuiltInType', + 'knownTypeName': 'ReactNativeCoreViewProps' + } + ], + 'events': [], + 'props': [], + 'commands': [ + { + 'name': 'scrollTo', + 'optional': false, + 'typeAnnotation': { + 'type': 'FunctionTypeAnnotation', + 'params': [ + { + 'name': 'y', + 'optional': false, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'animated', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ], + 'returnTypeAnnotation': { + 'type': 'VoidTypeAnnotation' + } + } + } + ] + } + } + } + } +}" +`; + +exports[`RN Codegen Flow Parser can generate fixture EVENTS_DEFINED_AS_NULL_INLINE 1`] = ` +"{ + 'modules': { + 'Module': { + 'type': 'Component', + 'components': { + 'Module': { + 'extendsProps': [ + { + 'type': 'ReactNativeBuiltInType', + 'knownTypeName': 'ReactNativeCoreViewProps' + } + ], + 'events': [ + { + 'name': 'onDirectEventDefinedInlineNull', + 'optional': false, + 'bubblingType': 'direct', + 'typeAnnotation': { + 'type': 'EventTypeAnnotation', + 'argument': { + 'type': 'ObjectTypeAnnotation', + 'properties': [] + } + } }, { - 'name': 'onDirectEventDefinedInlineWithPaperName', + 'name': 'onDirectEventDefinedInlineNullOptionalKey', 'optional': true, 'bubblingType': 'direct', - 'paperTopLevelNameDeprecated': 'paperDirectEventDefinedInlineWithPaperName', 'typeAnnotation': { 'type': 'EventTypeAnnotation', 'argument': { 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'boolean_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' - } - }, - { - 'name': 'boolean_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' - } - }, - { - 'name': 'boolean_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' - } - }, - { - 'name': 'boolean_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' - } - }, - { - 'name': 'string_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation' - } - }, - { - 'name': 'string_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation' - } - }, - { - 'name': 'string_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation' - } + 'properties': [] + } + } + }, + { + 'name': 'onDirectEventDefinedInlineNullOptionalValue', + 'optional': true, + 'bubblingType': 'direct', + 'typeAnnotation': { + 'type': 'EventTypeAnnotation', + 'argument': { + 'type': 'ObjectTypeAnnotation', + 'properties': [] + } + } + }, + { + 'name': 'onDirectEventDefinedInlineNullOptionalBoth', + 'optional': true, + 'bubblingType': 'direct', + 'typeAnnotation': { + 'type': 'EventTypeAnnotation', + 'argument': { + 'type': 'ObjectTypeAnnotation', + 'properties': [] + } + } + }, + { + 'name': 'onDirectEventDefinedInlineNullWithPaperName', + 'optional': true, + 'bubblingType': 'direct', + 'paperTopLevelNameDeprecated': 'paperDirectEventDefinedInlineNullWithPaperName', + 'typeAnnotation': { + 'type': 'EventTypeAnnotation', + 'argument': { + 'type': 'ObjectTypeAnnotation', + 'properties': [] + } + } + }, + { + 'name': 'onBubblingEventDefinedInlineNull', + 'optional': false, + 'bubblingType': 'bubble', + 'typeAnnotation': { + 'type': 'EventTypeAnnotation', + 'argument': { + 'type': 'ObjectTypeAnnotation', + 'properties': [] + } + } + }, + { + 'name': 'onBubblingEventDefinedInlineNullOptionalKey', + 'optional': true, + 'bubblingType': 'bubble', + 'typeAnnotation': { + 'type': 'EventTypeAnnotation', + 'argument': { + 'type': 'ObjectTypeAnnotation', + 'properties': [] + } + } + }, + { + 'name': 'onBubblingEventDefinedInlineNullOptionalValue', + 'optional': true, + 'bubblingType': 'bubble', + 'typeAnnotation': { + 'type': 'EventTypeAnnotation', + 'argument': { + 'type': 'ObjectTypeAnnotation', + 'properties': [] + } + } + }, + { + 'name': 'onBubblingEventDefinedInlineNullOptionalBoth', + 'optional': true, + 'bubblingType': 'bubble', + 'typeAnnotation': { + 'type': 'EventTypeAnnotation', + 'argument': { + 'type': 'ObjectTypeAnnotation', + 'properties': [] + } + } + }, + { + 'name': 'onBubblingEventDefinedInlineNullWithPaperName', + 'optional': true, + 'bubblingType': 'bubble', + 'paperTopLevelNameDeprecated': 'paperBubblingEventDefinedInlineNullWithPaperName', + 'typeAnnotation': { + 'type': 'EventTypeAnnotation', + 'argument': { + 'type': 'ObjectTypeAnnotation', + 'properties': [] + } + } + } + ], + 'props': [], + 'commands': [] + } + } + } + } +}" +`; + +exports[`RN Codegen Flow Parser can generate fixture EVENTS_DEFINED_INLINE_WITH_ALL_TYPES 1`] = ` +"{ + 'modules': { + 'Module': { + 'type': 'Component', + 'components': { + 'Module': { + 'extendsProps': [ + { + 'type': 'ReactNativeBuiltInType', + 'knownTypeName': 'ReactNativeCoreViewProps' + } + ], + 'events': [ + { + 'name': 'onDirectEventDefinedInline', + 'optional': false, + 'bubblingType': 'direct', + 'typeAnnotation': { + 'type': 'EventTypeAnnotation', + 'argument': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'boolean_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'boolean_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'boolean_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'string_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'string_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } }, { 'name': 'string_optional_both', @@ -5117,383 +5140,389 @@ exports[`RN Codegen Flow Parser can generate fixture EVENTS_DEFINED_INLINE_WITH_ } ] } - } - ] - } - } - }, - { - 'name': 'onBubblingEventDefinedInline', - 'optional': false, - 'bubblingType': 'bubble', - 'typeAnnotation': { - 'type': 'EventTypeAnnotation', - 'argument': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ + }, { - 'name': 'boolean_required', + 'name': 'boolean_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'boolean_optional_key', + 'name': 'boolean_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'boolean_optional_value', + 'name': 'boolean_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'boolean_optional_both', + 'name': 'boolean_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'string_required', + 'name': 'string_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'string_optional_key', + 'name': 'string_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'string_optional_value', + 'name': 'string_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'string_optional_both', + 'name': 'string_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'double_required', + 'name': 'double_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } } }, { - 'name': 'double_optional_key', + 'name': 'double_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } } }, { - 'name': 'double_optional_value', + 'name': 'double_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } } }, { - 'name': 'double_optional_both', + 'name': 'double_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } }, { - 'name': 'float_required', + 'name': 'float_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'float_optional_key', + 'name': 'float_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'float_optional_value', + 'name': 'float_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'float_optional_both', + 'name': 'float_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'int32_required', + 'name': 'int32_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'int32_optional_key', + 'name': 'int32_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'int32_optional_value', + 'name': 'int32_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'int32_optional_both', + 'name': 'int32_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'enum_required', + 'name': 'enum_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } } }, { - 'name': 'enum_optional_key', + 'name': 'enum_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } } }, { - 'name': 'enum_optional_value', + 'name': 'enum_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } } }, { - 'name': 'enum_optional_both', + 'name': 'enum_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } } }, { - 'name': 'object_required', + 'name': 'object_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'boolean_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_optional_key', + 'name': 'object_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'string_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_optional_value', + 'name': 'object_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'float_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_optional_both', + 'name': 'object_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'int32_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_required_nested_2_layers', + 'name': 'int32_array_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'object_optional_nested_1_layer', - 'optional': true, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'boolean_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } - }, - { - 'name': 'string_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation' - } - }, - { - 'name': 'double_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' - } - }, - { - 'name': 'float_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' - } - }, - { - 'name': 'int32_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } - } - ] - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] + } } }, { - 'name': 'object_readonly_required', - 'optional': false, + 'name': 'int32_array_array_optional_key', + 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'boolean_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] + } } }, { - 'name': 'object_readonly_optional_key', + 'name': 'int32_array_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'string_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] + } } }, { - 'name': 'object_readonly_optional_value', + 'name': 'int32_array_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'float_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] - } - }, - { - 'name': 'object_readonly_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'int32_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } - } - ] + } } } ] @@ -5501,9 +5530,9 @@ exports[`RN Codegen Flow Parser can generate fixture EVENTS_DEFINED_INLINE_WITH_ } }, { - 'name': 'onBubblingEventDefinedInlineOptionalKey', + 'name': 'onDirectEventDefinedInlineOptionalKey', 'optional': true, - 'bubblingType': 'bubble', + 'bubblingType': 'direct', 'typeAnnotation': { 'type': 'EventTypeAnnotation', 'argument': { @@ -5873,383 +5902,389 @@ exports[`RN Codegen Flow Parser can generate fixture EVENTS_DEFINED_INLINE_WITH_ } ] } - } - ] - } - } - }, - { - 'name': 'onBubblingEventDefinedInlineOptionalValue', - 'optional': true, - 'bubblingType': 'bubble', - 'typeAnnotation': { - 'type': 'EventTypeAnnotation', - 'argument': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ + }, { - 'name': 'boolean_required', + 'name': 'boolean_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'boolean_optional_key', + 'name': 'boolean_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'boolean_optional_value', + 'name': 'boolean_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'boolean_optional_both', + 'name': 'boolean_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'string_required', + 'name': 'string_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'string_optional_key', + 'name': 'string_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'string_optional_value', + 'name': 'string_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'string_optional_both', + 'name': 'string_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'double_required', + 'name': 'double_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } } }, { - 'name': 'double_optional_key', + 'name': 'double_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } } }, { - 'name': 'double_optional_value', + 'name': 'double_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } } }, { - 'name': 'double_optional_both', + 'name': 'double_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } } }, { - 'name': 'float_required', + 'name': 'float_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'float_optional_key', + 'name': 'float_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'float_optional_value', + 'name': 'float_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'float_optional_both', + 'name': 'float_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'int32_required', + 'name': 'int32_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'int32_optional_key', + 'name': 'int32_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'int32_optional_value', + 'name': 'int32_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'int32_optional_both', + 'name': 'int32_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'enum_required', + 'name': 'enum_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } } }, { - 'name': 'enum_optional_key', + 'name': 'enum_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } } }, { - 'name': 'enum_optional_value', + 'name': 'enum_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } } }, { - 'name': 'enum_optional_both', + 'name': 'enum_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } } }, { - 'name': 'object_required', + 'name': 'object_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'boolean_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_optional_key', + 'name': 'object_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'string_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_optional_value', + 'name': 'object_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'float_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_optional_both', + 'name': 'object_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'int32_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_required_nested_2_layers', + 'name': 'int32_array_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'object_optional_nested_1_layer', - 'optional': true, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'boolean_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } - }, - { - 'name': 'string_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation' - } - }, - { - 'name': 'double_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' - } - }, - { - 'name': 'float_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' - } - }, - { - 'name': 'int32_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } - } - ] - } - } - ] - } - }, - { - 'name': 'object_readonly_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'boolean_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] + } } }, { - 'name': 'object_readonly_optional_key', + 'name': 'int32_array_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'string_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] + } } }, { - 'name': 'object_readonly_optional_value', + 'name': 'int32_array_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'float_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] + } } }, { - 'name': 'object_readonly_optional_both', + 'name': 'int32_array_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'int32_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] + } } } ] @@ -6257,9 +6292,9 @@ exports[`RN Codegen Flow Parser can generate fixture EVENTS_DEFINED_INLINE_WITH_ } }, { - 'name': 'onBubblingEventDefinedInlineOptionalBoth', + 'name': 'onDirectEventDefinedInlineOptionalValue', 'optional': true, - 'bubblingType': 'bubble', + 'bubblingType': 'direct', 'typeAnnotation': { 'type': 'EventTypeAnnotation', 'argument': { @@ -6629,720 +6664,6231 @@ exports[`RN Codegen Flow Parser can generate fixture EVENTS_DEFINED_INLINE_WITH_ } ] } - } - ] - } - } - }, - { - 'name': 'onBubblingEventDefinedInlineWithPaperName', - 'optional': true, - 'bubblingType': 'bubble', - 'paperTopLevelNameDeprecated': 'paperBubblingEventDefinedInlineWithPaperName', - 'typeAnnotation': { - 'type': 'EventTypeAnnotation', - 'argument': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ + }, { - 'name': 'boolean_required', + 'name': 'boolean_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'boolean_optional_key', + 'name': 'boolean_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'boolean_optional_value', + 'name': 'boolean_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'boolean_optional_both', + 'name': 'boolean_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'string_required', + 'name': 'string_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'string_optional_key', + 'name': 'string_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'string_optional_value', + 'name': 'string_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'string_optional_both', + 'name': 'string_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'double_required', + 'name': 'double_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } } }, { - 'name': 'double_optional_key', + 'name': 'double_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } } }, { - 'name': 'double_optional_value', + 'name': 'double_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } } }, { - 'name': 'double_optional_both', + 'name': 'double_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } } }, { - 'name': 'float_required', + 'name': 'float_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'float_optional_key', + 'name': 'float_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'float_optional_value', + 'name': 'float_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'float_optional_both', + 'name': 'float_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'int32_required', + 'name': 'int32_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'int32_optional_key', + 'name': 'int32_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'int32_optional_value', + 'name': 'int32_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'int32_optional_both', + 'name': 'int32_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'enum_required', + 'name': 'enum_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } } }, { - 'name': 'enum_optional_key', + 'name': 'enum_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } } }, { - 'name': 'enum_optional_value', + 'name': 'enum_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } } }, { - 'name': 'enum_optional_both', + 'name': 'enum_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } } }, { - 'name': 'object_required', + 'name': 'object_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'boolean_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_optional_key', + 'name': 'object_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'string_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_optional_value', + 'name': 'object_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'float_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_optional_both', + 'name': 'object_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'int32_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } - } - ] - } - }, - { - 'name': 'object_required_nested_2_layers', - 'optional': false, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'object_optional_nested_1_layer', - 'optional': true, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'boolean_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } - }, - { - 'name': 'string_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation' - } - }, - { - 'name': 'double_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' - } - }, - { - 'name': 'float_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' - } - }, - { - 'name': 'int32_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } - } - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_readonly_required', + 'name': 'int32_array_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'boolean_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] + } } }, { - 'name': 'object_readonly_optional_key', + 'name': 'int32_array_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'string_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] + } } }, { - 'name': 'object_readonly_optional_value', + 'name': 'int32_array_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'float_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] + } } }, { - 'name': 'object_readonly_optional_both', + 'name': 'int32_array_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'int32_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] + } } } ] } } - } - ], - 'props': [], - 'commands': [] - } - } - } - } -}" -`; - -exports[`RN Codegen Flow Parser can generate fixture NO_PROPS_EVENTS_ONLY_DEPRECATED_VIEW_CONFIG_NAME_OPTION 1`] = ` -"{ - 'modules': { - 'Module': { - 'type': 'Component', - 'components': { - 'Module': { - 'deprecatedViewConfigName': 'DeprecateModuleName', - 'extendsProps': [ - { - 'type': 'ReactNativeBuiltInType', - 'knownTypeName': 'ReactNativeCoreViewProps' - } - ], - 'events': [], - 'props': [], - 'commands': [] - } - } - } - } -}" -`; - -exports[`RN Codegen Flow Parser can generate fixture OBJECT_PROP_TYPES_NO_EVENTS 1`] = ` -"{ - 'modules': { - 'Module': { - 'type': 'Component', - 'components': { - 'Module': { - 'extendsProps': [ - { - 'type': 'ReactNativeBuiltInType', - 'knownTypeName': 'ReactNativeCoreViewProps' - } - ], - 'events': [], - 'props': [ + }, { - 'name': 'boolean_required', - 'optional': false, + 'name': 'onDirectEventDefinedInlineOptionalBoth', + 'optional': true, + 'bubblingType': 'direct', 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'prop', - 'optional': false, - 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation', - 'default': false - } - } - ] - } - }, - { - 'name': 'boolean_optional', - 'optional': false, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'prop', - 'optional': true, - 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation', - 'default': false - } - } - ] - } - }, - { - 'name': 'string_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'prop', - 'optional': false, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation', - 'default': null - } - } - ] - } - }, - { - 'name': 'string_optional', - 'optional': false, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'prop', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation', - 'default': '' - } - } - ] - } - }, - { - 'name': 'double_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'prop', - 'optional': false, - 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation', - 'default': 0 - } - } - ] - } - }, - { - 'name': 'double_optional', - 'optional': false, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'prop', - 'optional': true, - 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation', - 'default': 0 - } - } - ] - } - }, - { - 'name': 'float_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'prop', - 'optional': false, - 'typeAnnotation': { - 'type': 'FloatTypeAnnotation', - 'default': 0 - } - } - ] - } - }, - { - 'name': 'float_optional', - 'optional': false, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'prop', - 'optional': true, - 'typeAnnotation': { - 'type': 'FloatTypeAnnotation', - 'default': 0 - } - } - ] - } - }, - { - 'name': 'int_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'prop', - 'optional': false, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation', - 'default': 0 - } - } - ] - } - }, - { - 'name': 'int_optional', - 'optional': false, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'prop', - 'optional': true, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation', - 'default': 0 - } - } - ] - } - }, - { - 'name': 'enum_optional', - 'optional': false, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'prop', - 'optional': true, - 'typeAnnotation': { - 'type': 'ArrayTypeAnnotation', - 'elementType': { - 'type': 'StringEnumTypeAnnotation', - 'default': 'small', - 'options': [ - 'small', - 'large' - ] + 'type': 'EventTypeAnnotation', + 'argument': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' } - } - } - ] - } - }, - { - 'name': 'image_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'prop', - 'optional': false, - 'typeAnnotation': { - 'type': 'ReservedPropTypeAnnotation', - 'name': 'ImageSourcePrimitive' - } - } - ] - } - }, - { - 'name': 'image_optional_key', - 'optional': false, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'prop', - 'optional': true, - 'typeAnnotation': { - 'type': 'ReservedPropTypeAnnotation', - 'name': 'ImageSourcePrimitive' - } - } - ] - } - }, - { - 'name': 'image_optional_value', - 'optional': false, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'prop', - 'optional': true, - 'typeAnnotation': { - 'type': 'ReservedPropTypeAnnotation', - 'name': 'ImageSourcePrimitive' - } - } - ] - } - }, - { - 'name': 'image_optional_both', - 'optional': false, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'prop', - 'optional': true, - 'typeAnnotation': { - 'type': 'ReservedPropTypeAnnotation', - 'name': 'ImageSourcePrimitive' - } - } - ] + }, + { + 'name': 'boolean_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'boolean_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'boolean_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'string_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'string_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'string_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'double_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'double_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'double_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'double_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'float_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'float_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'float_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'int32_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'int32_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'int32_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'enum_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'enum_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'enum_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'enum_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'object_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_required_nested_2_layers', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'object_optional_nested_1_layer', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'double_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + } + ] + } + }, + { + 'name': 'object_readonly_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_readonly_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_readonly_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_readonly_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + }, + { + 'name': 'boolean_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'boolean_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'boolean_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'boolean_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'string_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'string_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'string_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'string_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'double_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'double_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'double_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'double_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'float_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'float_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'float_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'float_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'int32_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'int32_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'int32_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'int32_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'enum_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'enum_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'enum_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'enum_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'object_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ] + } + } + }, + { + 'name': 'object_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + } + ] + } + } + }, + { + 'name': 'object_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + } + ] + } + } + }, + { + 'name': 'object_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + } + }, + { + 'name': 'int32_array_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + } + }, + { + 'name': 'int32_array_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + } + }, + { + 'name': 'int32_array_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + } + }, + { + 'name': 'int32_array_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + } + } + ] + } + } + }, + { + 'name': 'onDirectEventDefinedInlineWithPaperName', + 'optional': true, + 'bubblingType': 'direct', + 'paperTopLevelNameDeprecated': 'paperDirectEventDefinedInlineWithPaperName', + 'typeAnnotation': { + 'type': 'EventTypeAnnotation', + 'argument': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'boolean_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'boolean_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'boolean_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'string_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'string_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'string_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'double_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'double_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'double_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'double_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'float_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'float_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'float_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'int32_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'int32_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'int32_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'enum_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'enum_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'enum_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'enum_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'object_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_required_nested_2_layers', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'object_optional_nested_1_layer', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'double_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + } + ] + } + }, + { + 'name': 'object_readonly_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_readonly_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_readonly_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_readonly_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + }, + { + 'name': 'boolean_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'boolean_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'boolean_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'boolean_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'string_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'string_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'string_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'string_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'double_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'double_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'double_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'double_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'float_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'float_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'float_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'float_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'int32_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'int32_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'int32_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'int32_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'enum_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'enum_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'enum_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'enum_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'object_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ] + } + } + }, + { + 'name': 'object_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + } + ] + } + } + }, + { + 'name': 'object_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + } + ] + } + } + }, + { + 'name': 'object_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + } + }, + { + 'name': 'int32_array_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + } + }, + { + 'name': 'int32_array_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + } + }, + { + 'name': 'int32_array_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + } + }, + { + 'name': 'int32_array_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + } + } + ] + } + } + }, + { + 'name': 'onBubblingEventDefinedInline', + 'optional': false, + 'bubblingType': 'bubble', + 'typeAnnotation': { + 'type': 'EventTypeAnnotation', + 'argument': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'boolean_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'boolean_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'boolean_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'string_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'string_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'string_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'double_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'double_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'double_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'double_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'float_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'float_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'float_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'int32_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'int32_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'int32_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'enum_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'enum_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'enum_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'enum_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'object_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_required_nested_2_layers', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'object_optional_nested_1_layer', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'double_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + } + ] + } + }, + { + 'name': 'object_readonly_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_readonly_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_readonly_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_readonly_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + }, + { + 'name': 'boolean_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'boolean_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'boolean_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'boolean_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'string_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'string_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'string_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'string_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'double_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'double_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'double_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'double_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'float_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'float_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'float_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'float_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'int32_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'int32_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'int32_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'int32_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'enum_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'enum_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'enum_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'enum_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'object_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ] + } + } + }, + { + 'name': 'object_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + } + ] + } + } + }, + { + 'name': 'object_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + } + ] + } + } + }, + { + 'name': 'object_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + } + }, + { + 'name': 'int32_array_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + } + }, + { + 'name': 'int32_array_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + } + }, + { + 'name': 'int32_array_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + } + }, + { + 'name': 'int32_array_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + } + } + ] + } + } + }, + { + 'name': 'onBubblingEventDefinedInlineOptionalKey', + 'optional': true, + 'bubblingType': 'bubble', + 'typeAnnotation': { + 'type': 'EventTypeAnnotation', + 'argument': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'boolean_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'boolean_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'boolean_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'string_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'string_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'string_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'double_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'double_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'double_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'double_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'float_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'float_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'float_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'int32_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'int32_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'int32_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'enum_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'enum_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'enum_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'enum_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'object_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_required_nested_2_layers', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'object_optional_nested_1_layer', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'double_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + } + ] + } + }, + { + 'name': 'object_readonly_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_readonly_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_readonly_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_readonly_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + }, + { + 'name': 'boolean_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'boolean_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'boolean_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'boolean_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'string_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'string_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'string_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'string_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'double_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'double_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'double_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'double_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'float_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'float_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'float_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'float_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'int32_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'int32_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'int32_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'int32_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'enum_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'enum_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'enum_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'enum_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'object_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ] + } + } + }, + { + 'name': 'object_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + } + ] + } + } + }, + { + 'name': 'object_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + } + ] + } + } + }, + { + 'name': 'object_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + } + }, + { + 'name': 'int32_array_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + } + }, + { + 'name': 'int32_array_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + } + }, + { + 'name': 'int32_array_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + } + }, + { + 'name': 'int32_array_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + } + } + ] + } + } + }, + { + 'name': 'onBubblingEventDefinedInlineOptionalValue', + 'optional': true, + 'bubblingType': 'bubble', + 'typeAnnotation': { + 'type': 'EventTypeAnnotation', + 'argument': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'boolean_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'boolean_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'boolean_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'string_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'string_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'string_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'double_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'double_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'double_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'double_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'float_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'float_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'float_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'int32_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'int32_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'int32_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'enum_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'enum_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'enum_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'enum_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'object_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_required_nested_2_layers', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'object_optional_nested_1_layer', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'double_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + } + ] + } + }, + { + 'name': 'object_readonly_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_readonly_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_readonly_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_readonly_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + }, + { + 'name': 'boolean_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'boolean_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'boolean_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'boolean_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'string_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'string_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'string_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'string_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'double_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'double_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'double_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'double_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'float_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'float_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'float_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'float_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'int32_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'int32_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'int32_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'int32_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'enum_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'enum_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'enum_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'enum_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'object_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ] + } + } + }, + { + 'name': 'object_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + } + ] + } + } + }, + { + 'name': 'object_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + } + ] + } + } + }, + { + 'name': 'object_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + } + }, + { + 'name': 'int32_array_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + } + }, + { + 'name': 'int32_array_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + } + }, + { + 'name': 'int32_array_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + } + }, + { + 'name': 'int32_array_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + } + } + ] + } + } + }, + { + 'name': 'onBubblingEventDefinedInlineOptionalBoth', + 'optional': true, + 'bubblingType': 'bubble', + 'typeAnnotation': { + 'type': 'EventTypeAnnotation', + 'argument': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'boolean_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'boolean_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'boolean_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'string_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'string_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'string_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'double_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'double_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'double_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'double_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'float_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'float_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'float_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'int32_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'int32_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'int32_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'enum_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'enum_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'enum_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'enum_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'object_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_required_nested_2_layers', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'object_optional_nested_1_layer', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'double_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + } + ] + } + }, + { + 'name': 'object_readonly_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_readonly_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_readonly_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_readonly_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + }, + { + 'name': 'boolean_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'boolean_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'boolean_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'boolean_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'string_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'string_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'string_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'string_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'double_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'double_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'double_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'double_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'float_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'float_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'float_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'float_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'int32_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'int32_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'int32_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'int32_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'enum_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'enum_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'enum_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'enum_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'object_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ] + } + } + }, + { + 'name': 'object_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + } + ] + } + } + }, + { + 'name': 'object_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + } + ] + } + } + }, + { + 'name': 'object_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + } + }, + { + 'name': 'int32_array_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + } + }, + { + 'name': 'int32_array_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + } + }, + { + 'name': 'int32_array_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + } + }, + { + 'name': 'int32_array_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + } + } + ] + } + } + }, + { + 'name': 'onBubblingEventDefinedInlineWithPaperName', + 'optional': true, + 'bubblingType': 'bubble', + 'paperTopLevelNameDeprecated': 'paperBubblingEventDefinedInlineWithPaperName', + 'typeAnnotation': { + 'type': 'EventTypeAnnotation', + 'argument': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'boolean_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'boolean_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'boolean_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'string_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'string_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'string_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'double_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'double_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'double_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'double_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'float_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'float_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'float_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'int32_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'int32_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'int32_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'enum_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'enum_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'enum_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'enum_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'object_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_required_nested_2_layers', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'object_optional_nested_1_layer', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'double_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + } + ] + } + }, + { + 'name': 'object_readonly_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_readonly_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_readonly_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_readonly_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + }, + { + 'name': 'boolean_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'boolean_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'boolean_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'boolean_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'string_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'string_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'string_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'string_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'double_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'double_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'double_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'double_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'float_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'float_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'float_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'float_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'int32_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'int32_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'int32_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'int32_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'enum_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'enum_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'enum_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'enum_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'object_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ] + } + } + }, + { + 'name': 'object_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + } + ] + } + } + }, + { + 'name': 'object_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + } + ] + } + } + }, + { + 'name': 'object_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + } + }, + { + 'name': 'int32_array_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + } + }, + { + 'name': 'int32_array_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + } + }, + { + 'name': 'int32_array_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + } + }, + { + 'name': 'int32_array_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + } + } + ] + } + } + } + ], + 'props': [], + 'commands': [] + } + } + } + } +}" +`; + +exports[`RN Codegen Flow Parser can generate fixture NO_PROPS_EVENTS_ONLY_DEPRECATED_VIEW_CONFIG_NAME_OPTION 1`] = ` +"{ + 'modules': { + 'Module': { + 'type': 'Component', + 'components': { + 'Module': { + 'deprecatedViewConfigName': 'DeprecateModuleName', + 'extendsProps': [ + { + 'type': 'ReactNativeBuiltInType', + 'knownTypeName': 'ReactNativeCoreViewProps' + } + ], + 'events': [], + 'props': [], + 'commands': [] + } + } + } + } +}" +`; + +exports[`RN Codegen Flow Parser can generate fixture OBJECT_PROP_TYPES_NO_EVENTS 1`] = ` +"{ + 'modules': { + 'Module': { + 'type': 'Component', + 'components': { + 'Module': { + 'extendsProps': [ + { + 'type': 'ReactNativeBuiltInType', + 'knownTypeName': 'ReactNativeCoreViewProps' + } + ], + 'events': [], + 'props': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation', + 'default': false + } + } + ] + } + }, + { + 'name': 'boolean_optional', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation', + 'default': false + } + } + ] + } + }, + { + 'name': 'string_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation', + 'default': null + } + } + ] + } + }, + { + 'name': 'string_optional', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation', + 'default': '' + } + } + ] + } + }, + { + 'name': 'double_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': false, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation', + 'default': 0 + } + } + ] + } + }, + { + 'name': 'double_optional', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation', + 'default': 0 + } + } + ] + } + }, + { + 'name': 'float_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': false, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation', + 'default': 0 + } + } + ] + } + }, + { + 'name': 'float_optional', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation', + 'default': 0 + } + } + ] + } + }, + { + 'name': 'int_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': false, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation', + 'default': 0 + } + } + ] + } + }, + { + 'name': 'int_optional', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation', + 'default': 0 + } + } + ] + } + }, + { + 'name': 'enum_optional', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'default': 'small', + 'options': [ + 'small', + 'large' + ] + } + } + } + ] + } + }, + { + 'name': 'image_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': false, + 'typeAnnotation': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ImageSourcePrimitive' + } + } + ] + } + }, + { + 'name': 'image_optional_key', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': true, + 'typeAnnotation': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ImageSourcePrimitive' + } + } + ] + } + }, + { + 'name': 'image_optional_value', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': true, + 'typeAnnotation': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ImageSourcePrimitive' + } + } + ] + } + }, + { + 'name': 'image_optional_both', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': true, + 'typeAnnotation': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ImageSourcePrimitive' + } + } + ] + } + }, + { + 'name': 'color_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': false, + 'typeAnnotation': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ColorPrimitive' + } + } + ] + } + }, + { + 'name': 'color_optional_key', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': true, + 'typeAnnotation': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ColorPrimitive' + } + } + ] + } + }, + { + 'name': 'color_optional_value', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': true, + 'typeAnnotation': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ColorPrimitive' + } + } + ] + } + }, + { + 'name': 'color_optional_both', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': true, + 'typeAnnotation': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ColorPrimitive' + } + } + ] + } + }, + { + 'name': 'processed_color_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': false, + 'typeAnnotation': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ColorPrimitive' + } + } + ] + } + }, + { + 'name': 'processed_color_optional_key', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': true, + 'typeAnnotation': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ColorPrimitive' + } + } + ] + } + }, + { + 'name': 'processed_color_optional_value', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': true, + 'typeAnnotation': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ColorPrimitive' + } + } + ] + } + }, + { + 'name': 'processed_color_optional_both', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': true, + 'typeAnnotation': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ColorPrimitive' + } + } + ] + } + }, + { + 'name': 'point_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': false, + 'typeAnnotation': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'PointPrimitive' + } + } + ] + } + }, + { + 'name': 'point_optional_key', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': true, + 'typeAnnotation': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'PointPrimitive' + } + } + ] } }, { - 'name': 'color_required', + 'name': 'point_optional_value', 'optional': false, 'typeAnnotation': { 'type': 'ObjectTypeAnnotation', 'properties': [ { 'name': 'prop', - 'optional': false, + 'optional': true, 'typeAnnotation': { 'type': 'ReservedPropTypeAnnotation', - 'name': 'ColorPrimitive' + 'name': 'PointPrimitive' } } ] } }, { - 'name': 'color_optional_key', + 'name': 'point_optional_both', 'optional': false, 'typeAnnotation': { 'type': 'ObjectTypeAnnotation', @@ -7352,31 +12898,31 @@ exports[`RN Codegen Flow Parser can generate fixture OBJECT_PROP_TYPES_NO_EVENTS 'optional': true, 'typeAnnotation': { 'type': 'ReservedPropTypeAnnotation', - 'name': 'ColorPrimitive' + 'name': 'PointPrimitive' } } ] } }, { - 'name': 'color_optional_value', + 'name': 'insets_required', 'optional': false, 'typeAnnotation': { 'type': 'ObjectTypeAnnotation', 'properties': [ { 'name': 'prop', - 'optional': true, + 'optional': false, 'typeAnnotation': { 'type': 'ReservedPropTypeAnnotation', - 'name': 'ColorPrimitive' + 'name': 'EdgeInsetsPrimitive' } } ] } }, { - 'name': 'color_optional_both', + 'name': 'insets_optional_key', 'optional': false, 'typeAnnotation': { 'type': 'ObjectTypeAnnotation', @@ -7386,31 +12932,31 @@ exports[`RN Codegen Flow Parser can generate fixture OBJECT_PROP_TYPES_NO_EVENTS 'optional': true, 'typeAnnotation': { 'type': 'ReservedPropTypeAnnotation', - 'name': 'ColorPrimitive' + 'name': 'EdgeInsetsPrimitive' } } ] } }, { - 'name': 'processed_color_required', + 'name': 'insets_optional_value', 'optional': false, 'typeAnnotation': { 'type': 'ObjectTypeAnnotation', 'properties': [ { 'name': 'prop', - 'optional': false, + 'optional': true, 'typeAnnotation': { 'type': 'ReservedPropTypeAnnotation', - 'name': 'ColorPrimitive' + 'name': 'EdgeInsetsPrimitive' } } ] } }, { - 'name': 'processed_color_optional_key', + 'name': 'insets_optional_both', 'optional': false, 'typeAnnotation': { 'type': 'ObjectTypeAnnotation', @@ -7420,31 +12966,31 @@ exports[`RN Codegen Flow Parser can generate fixture OBJECT_PROP_TYPES_NO_EVENTS 'optional': true, 'typeAnnotation': { 'type': 'ReservedPropTypeAnnotation', - 'name': 'ColorPrimitive' + 'name': 'EdgeInsetsPrimitive' } } ] } }, { - 'name': 'processed_color_optional_value', + 'name': 'dimension_required', 'optional': false, 'typeAnnotation': { 'type': 'ObjectTypeAnnotation', 'properties': [ { 'name': 'prop', - 'optional': true, + 'optional': false, 'typeAnnotation': { 'type': 'ReservedPropTypeAnnotation', - 'name': 'ColorPrimitive' + 'name': 'DimensionPrimitive' } } ] } }, { - 'name': 'processed_color_optional_both', + 'name': 'dimension_optional_key', 'optional': false, 'typeAnnotation': { 'type': 'ObjectTypeAnnotation', @@ -7454,31 +13000,31 @@ exports[`RN Codegen Flow Parser can generate fixture OBJECT_PROP_TYPES_NO_EVENTS 'optional': true, 'typeAnnotation': { 'type': 'ReservedPropTypeAnnotation', - 'name': 'ColorPrimitive' + 'name': 'DimensionPrimitive' } } ] } }, { - 'name': 'point_required', + 'name': 'dimension_optional_value', 'optional': false, 'typeAnnotation': { 'type': 'ObjectTypeAnnotation', 'properties': [ { 'name': 'prop', - 'optional': false, + 'optional': true, 'typeAnnotation': { 'type': 'ReservedPropTypeAnnotation', - 'name': 'PointPrimitive' + 'name': 'DimensionPrimitive' } } ] } }, { - 'name': 'point_optional_key', + 'name': 'dimension_optional_both', 'optional': false, 'typeAnnotation': { 'type': 'ObjectTypeAnnotation', @@ -7488,551 +13034,1906 @@ exports[`RN Codegen Flow Parser can generate fixture OBJECT_PROP_TYPES_NO_EVENTS 'optional': true, 'typeAnnotation': { 'type': 'ReservedPropTypeAnnotation', - 'name': 'PointPrimitive' + 'name': 'DimensionPrimitive' } } ] } }, { - 'name': 'point_optional_value', + 'name': 'object_required', 'optional': false, 'typeAnnotation': { 'type': 'ObjectTypeAnnotation', 'properties': [ { 'name': 'prop', - 'optional': true, + 'optional': false, 'typeAnnotation': { - 'type': 'ReservedPropTypeAnnotation', - 'name': 'PointPrimitive' + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'nestedProp', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation', + 'default': null + } + } + ] } } ] } }, { - 'name': 'point_optional_both', - 'optional': false, + 'name': 'object_optional_key', + 'optional': true, 'typeAnnotation': { 'type': 'ObjectTypeAnnotation', 'properties': [ { 'name': 'prop', - 'optional': true, + 'optional': false, 'typeAnnotation': { - 'type': 'ReservedPropTypeAnnotation', - 'name': 'PointPrimitive' + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'nestedProp', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation', + 'default': null + } + } + ] + } + } + ] + } + }, + { + 'name': 'object_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'nestedProp', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation', + 'default': null + } + } + ] + } + } + ] + } + }, + { + 'name': 'object_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'nestedProp', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation', + 'default': null + } + } + ] } } ] } - }, + } + ], + 'commands': [] + } + } + } + } +}" +`; + +exports[`RN Codegen Flow Parser can generate fixture ONE_OF_EACH_PROP_EVENT_DEFAULT_AND_OPTIONS 1`] = ` +"{ + 'modules': { + 'Module': { + 'type': 'Component', + 'components': { + 'Module': { + 'interfaceOnly': true, + 'paperComponentName': 'RCTModule', + 'extendsProps': [ + { + 'type': 'ReactNativeBuiltInType', + 'knownTypeName': 'ReactNativeCoreViewProps' + } + ], + 'events': [ + { + 'name': 'onDirectEventDefinedInlineNull', + 'optional': false, + 'bubblingType': 'direct', + 'typeAnnotation': { + 'type': 'EventTypeAnnotation', + 'argument': { + 'type': 'ObjectTypeAnnotation', + 'properties': [] + } + } + }, + { + 'name': 'onBubblingEventDefinedInlineNull', + 'optional': false, + 'bubblingType': 'bubble', + 'typeAnnotation': { + 'type': 'EventTypeAnnotation', + 'argument': { + 'type': 'ObjectTypeAnnotation', + 'properties': [] + } + } + } + ], + 'props': [ + { + 'name': 'boolean_default_true_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation', + 'default': true + } + } + ], + 'commands': [] + } + } + } + } +}" +`; + +exports[`RN Codegen Flow Parser can generate fixture ONE_OF_EACH_PROP_EVENT_DEFAULT_AND_OPTIONS_NO_CAST 1`] = ` +"{ + 'modules': { + 'Module': { + 'type': 'Component', + 'components': { + 'Module': { + 'interfaceOnly': true, + 'excludedPlatforms': [ + 'android' + ], + 'paperComponentName': 'RCTModule', + 'extendsProps': [ + { + 'type': 'ReactNativeBuiltInType', + 'knownTypeName': 'ReactNativeCoreViewProps' + } + ], + 'events': [ + { + 'name': 'onDirectEventDefinedInlineNull', + 'optional': false, + 'bubblingType': 'direct', + 'typeAnnotation': { + 'type': 'EventTypeAnnotation', + 'argument': { + 'type': 'ObjectTypeAnnotation', + 'properties': [] + } + } + }, + { + 'name': 'onBubblingEventDefinedInlineNull', + 'optional': false, + 'bubblingType': 'bubble', + 'typeAnnotation': { + 'type': 'EventTypeAnnotation', + 'argument': { + 'type': 'ObjectTypeAnnotation', + 'properties': [] + } + } + } + ], + 'props': [ + { + 'name': 'boolean_default_true_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation', + 'default': true + } + } + ], + 'commands': [] + } + } + } + } +}" +`; + +exports[`RN Codegen Flow Parser can generate fixture PROPS_ALIASED_LOCALLY 1`] = ` +"{ + 'modules': { + 'Module': { + 'type': 'Component', + 'components': { + 'Module': { + 'extendsProps': [ { - 'name': 'insets_required', + 'type': 'ReactNativeBuiltInType', + 'knownTypeName': 'ReactNativeCoreViewProps' + } + ], + 'events': [], + 'props': [ + { + 'name': 'otherStringProp', 'optional': false, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'prop', - 'optional': false, - 'typeAnnotation': { - 'type': 'ReservedPropTypeAnnotation', - 'name': 'EdgeInsetsPrimitive' - } - } - ] + 'type': 'StringTypeAnnotation', + 'default': null } }, { - 'name': 'insets_optional_key', + 'name': 'isEnabled', 'optional': false, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'prop', - 'optional': true, - 'typeAnnotation': { - 'type': 'ReservedPropTypeAnnotation', - 'name': 'EdgeInsetsPrimitive' - } - } - ] + 'type': 'BooleanTypeAnnotation', + 'default': false } }, { - 'name': 'insets_optional_value', + 'name': 'label', 'optional': false, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'prop', - 'optional': true, - 'typeAnnotation': { - 'type': 'ReservedPropTypeAnnotation', - 'name': 'EdgeInsetsPrimitive' - } - } - ] + 'type': 'StringTypeAnnotation', + 'default': null } }, { - 'name': 'insets_optional_both', + 'name': 'localType', 'optional': false, 'typeAnnotation': { 'type': 'ObjectTypeAnnotation', 'properties': [ { - 'name': 'prop', - 'optional': true, + 'name': 'otherStringProp', + 'optional': false, 'typeAnnotation': { - 'type': 'ReservedPropTypeAnnotation', - 'name': 'EdgeInsetsPrimitive' + 'type': 'StringTypeAnnotation', + 'default': null } - } - ] - } - }, - { - 'name': 'dimension_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ + }, { - 'name': 'prop', + 'name': 'isEnabled', 'optional': false, 'typeAnnotation': { - 'type': 'ReservedPropTypeAnnotation', - 'name': 'DimensionPrimitive' + 'type': 'BooleanTypeAnnotation', + 'default': false } - } - ] - } - }, - { - 'name': 'dimension_optional_key', - 'optional': false, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ + }, { - 'name': 'prop', - 'optional': true, + 'name': 'label', + 'optional': false, 'typeAnnotation': { - 'type': 'ReservedPropTypeAnnotation', - 'name': 'DimensionPrimitive' + 'type': 'StringTypeAnnotation', + 'default': null } } ] } }, { - 'name': 'dimension_optional_value', + 'name': 'localArr', 'optional': false, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'prop', - 'optional': true, - 'typeAnnotation': { - 'type': 'ReservedPropTypeAnnotation', - 'name': 'DimensionPrimitive' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'otherStringProp', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation', + 'default': null + } + }, + { + 'name': 'isEnabled', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation', + 'default': false + } + }, + { + 'name': 'label', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation', + 'default': null + } } - } - ] + ] + } } - }, + } + ], + 'commands': [] + } + } + } + } +}" +`; + +exports[`RN Codegen Flow Parser can generate fixture PROPS_AND_EVENTS_TYPES_EXPORTED 1`] = ` +"{ + 'modules': { + 'Module': { + 'type': 'Component', + 'components': { + 'Module': { + 'extendsProps': [ { - 'name': 'dimension_optional_both', + 'type': 'ReactNativeBuiltInType', + 'knownTypeName': 'ReactNativeCoreViewProps' + } + ], + 'events': [ + { + 'name': 'onBubblingEventDefinedInline', 'optional': false, + 'bubblingType': 'bubble', 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'prop', - 'optional': true, - 'typeAnnotation': { - 'type': 'ReservedPropTypeAnnotation', - 'name': 'DimensionPrimitive' + 'type': 'EventTypeAnnotation', + 'argument': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'boolean_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'boolean_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'boolean_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'string_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'string_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'string_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'double_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'double_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'double_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'double_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'float_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'float_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'float_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'int32_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'int32_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'int32_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'enum_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'enum_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'enum_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'enum_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'object_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_required_nested_2_layers', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'object_optional_nested_1_layer', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'double_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + } + ] + } + }, + { + 'name': 'object_readonly_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_readonly_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_readonly_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_readonly_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + }, + { + 'name': 'boolean_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'boolean_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'boolean_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'boolean_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'string_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'string_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'string_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'string_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'double_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'double_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'double_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'double_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'float_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'float_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'float_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'float_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'int32_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'int32_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'int32_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'int32_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'enum_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'enum_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'enum_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'enum_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'object_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ] + } + } + }, + { + 'name': 'object_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + } + ] + } + } + }, + { + 'name': 'object_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + } + ] + } + } + }, + { + 'name': 'object_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + } + }, + { + 'name': 'int32_array_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + } + }, + { + 'name': 'int32_array_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + } + }, + { + 'name': 'int32_array_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + } + }, + { + 'name': 'int32_array_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + } } - } - ] + ] + } } }, { - 'name': 'object_required', + 'name': 'onBubblingEventDefinedInlineWithPaperName', 'optional': false, + 'bubblingType': 'bubble', + 'paperTopLevelNameDeprecated': 'paperBubblingEventDefinedInlineWithPaperName', 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'prop', - 'optional': false, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'nestedProp', - 'optional': false, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation', - 'default': null + 'type': 'EventTypeAnnotation', + 'argument': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'boolean_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'boolean_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'boolean_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'string_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'string_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'string_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'double_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'double_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'double_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'double_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'float_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'float_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'float_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'int32_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'int32_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'int32_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'enum_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'enum_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'enum_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'enum_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'object_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_required_nested_2_layers', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'object_optional_nested_1_layer', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'double_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + } + ] + } + }, + { + 'name': 'object_readonly_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_readonly_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_readonly_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_readonly_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } } + ] + } + }, + { + 'name': 'boolean_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'boolean_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'boolean_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'boolean_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' } - ] - } - } - ] - } - }, - { - 'name': 'object_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'prop', - 'optional': false, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'nestedProp', - 'optional': false, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation', - 'default': null - } + } + }, + { + 'name': 'string_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' } - ] - } - } - ] - } - }, - { - 'name': 'object_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'prop', - 'optional': false, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'nestedProp', - 'optional': false, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation', - 'default': null - } + } + }, + { + 'name': 'string_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' } - ] - } - } - ] - } - }, - { - 'name': 'object_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'prop', - 'optional': false, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'nestedProp', - 'optional': false, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation', - 'default': null - } + } + }, + { + 'name': 'string_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'string_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'double_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'double_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'double_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'double_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'float_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'float_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'float_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'float_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'int32_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'int32_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'int32_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'int32_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'enum_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'enum_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'enum_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'enum_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'object_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ] + } + } + }, + { + 'name': 'object_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + } + ] } - ] - } - } - ] - } - } - ], - 'commands': [] - } - } - } - } -}" -`; - -exports[`RN Codegen Flow Parser can generate fixture ONE_OF_EACH_PROP_EVENT_DEFAULT_AND_OPTIONS 1`] = ` -"{ - 'modules': { - 'Module': { - 'type': 'Component', - 'components': { - 'Module': { - 'interfaceOnly': true, - 'paperComponentName': 'RCTModule', - 'extendsProps': [ - { - 'type': 'ReactNativeBuiltInType', - 'knownTypeName': 'ReactNativeCoreViewProps' - } - ], - 'events': [ - { - 'name': 'onDirectEventDefinedInlineNull', - 'optional': false, - 'bubblingType': 'direct', - 'typeAnnotation': { - 'type': 'EventTypeAnnotation', - 'argument': { - 'type': 'ObjectTypeAnnotation', - 'properties': [] - } - } - }, - { - 'name': 'onBubblingEventDefinedInlineNull', - 'optional': false, - 'bubblingType': 'bubble', - 'typeAnnotation': { - 'type': 'EventTypeAnnotation', - 'argument': { - 'type': 'ObjectTypeAnnotation', - 'properties': [] - } - } - } - ], - 'props': [ - { - 'name': 'boolean_default_true_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation', - 'default': true - } - } - ], - 'commands': [] - } - } - } - } -}" -`; - -exports[`RN Codegen Flow Parser can generate fixture ONE_OF_EACH_PROP_EVENT_DEFAULT_AND_OPTIONS_NO_CAST 1`] = ` -"{ - 'modules': { - 'Module': { - 'type': 'Component', - 'components': { - 'Module': { - 'interfaceOnly': true, - 'excludedPlatforms': [ - 'android' - ], - 'paperComponentName': 'RCTModule', - 'extendsProps': [ - { - 'type': 'ReactNativeBuiltInType', - 'knownTypeName': 'ReactNativeCoreViewProps' - } - ], - 'events': [ - { - 'name': 'onDirectEventDefinedInlineNull', - 'optional': false, - 'bubblingType': 'direct', - 'typeAnnotation': { - 'type': 'EventTypeAnnotation', - 'argument': { - 'type': 'ObjectTypeAnnotation', - 'properties': [] - } - } - }, - { - 'name': 'onBubblingEventDefinedInlineNull', - 'optional': false, - 'bubblingType': 'bubble', - 'typeAnnotation': { - 'type': 'EventTypeAnnotation', - 'argument': { - 'type': 'ObjectTypeAnnotation', - 'properties': [] - } - } - } - ], - 'props': [ - { - 'name': 'boolean_default_true_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation', - 'default': true - } - } - ], - 'commands': [] - } - } - } - } -}" -`; - -exports[`RN Codegen Flow Parser can generate fixture PROPS_ALIASED_LOCALLY 1`] = ` -"{ - 'modules': { - 'Module': { - 'type': 'Component', - 'components': { - 'Module': { - 'extendsProps': [ - { - 'type': 'ReactNativeBuiltInType', - 'knownTypeName': 'ReactNativeCoreViewProps' - } - ], - 'events': [], - 'props': [ - { - 'name': 'otherStringProp', - 'optional': false, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation', - 'default': null - } - }, - { - 'name': 'isEnabled', - 'optional': false, - 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation', - 'default': false - } - }, - { - 'name': 'label', - 'optional': false, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation', - 'default': null - } - }, - { - 'name': 'localType', - 'optional': false, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'otherStringProp', - 'optional': false, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation', - 'default': null - } - }, - { - 'name': 'isEnabled', - 'optional': false, - 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation', - 'default': false - } - }, - { - 'name': 'label', - 'optional': false, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation', - 'default': null - } - } - ] - } - }, - { - 'name': 'localArr', - 'optional': false, - 'typeAnnotation': { - 'type': 'ArrayTypeAnnotation', - 'elementType': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ + } + }, + { + 'name': 'object_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + } + ] + } + } + }, + { + 'name': 'object_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + } + }, { - 'name': 'otherStringProp', + 'name': 'int32_array_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'StringTypeAnnotation', - 'default': null + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } } }, { - 'name': 'isEnabled', - 'optional': false, + 'name': 'int32_array_array_optional_key', + 'optional': true, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation', - 'default': false + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } } }, { - 'name': 'label', - 'optional': false, + 'name': 'int32_array_array_optional_value', + 'optional': true, 'typeAnnotation': { - 'type': 'StringTypeAnnotation', - 'default': null + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + } + }, + { + 'name': 'int32_array_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } } } ] } } - } - ], - 'commands': [] - } - } - } - } -}" -`; - -exports[`RN Codegen Flow Parser can generate fixture PROPS_AND_EVENTS_TYPES_EXPORTED 1`] = ` -"{ - 'modules': { - 'Module': { - 'type': 'Component', - 'components': { - 'Module': { - 'extendsProps': [ - { - 'type': 'ReactNativeBuiltInType', - 'knownTypeName': 'ReactNativeCoreViewProps' - } - ], - 'events': [ + }, { - 'name': 'onBubblingEventDefinedInline', + 'name': 'onDirectEventDefinedInline', 'optional': false, - 'bubblingType': 'bubble', + 'bubblingType': 'direct', 'typeAnnotation': { 'type': 'EventTypeAnnotation', 'argument': { @@ -8402,384 +15303,389 @@ exports[`RN Codegen Flow Parser can generate fixture PROPS_AND_EVENTS_TYPES_EXPO } ] } - } - ] - } - } - }, - { - 'name': 'onBubblingEventDefinedInlineWithPaperName', - 'optional': false, - 'bubblingType': 'bubble', - 'paperTopLevelNameDeprecated': 'paperBubblingEventDefinedInlineWithPaperName', - 'typeAnnotation': { - 'type': 'EventTypeAnnotation', - 'argument': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ + }, { - 'name': 'boolean_required', + 'name': 'boolean_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'boolean_optional_key', + 'name': 'boolean_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'boolean_optional_value', + 'name': 'boolean_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'boolean_optional_both', + 'name': 'boolean_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'string_required', + 'name': 'string_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'string_optional_key', + 'name': 'string_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'string_optional_value', + 'name': 'string_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'string_optional_both', + 'name': 'string_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'double_required', + 'name': 'double_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } } }, { - 'name': 'double_optional_key', + 'name': 'double_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } } }, { - 'name': 'double_optional_value', + 'name': 'double_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } } }, { - 'name': 'double_optional_both', + 'name': 'double_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } } }, { - 'name': 'float_required', + 'name': 'float_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'float_optional_key', + 'name': 'float_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'float_optional_value', + 'name': 'float_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'float_optional_both', + 'name': 'float_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'int32_required', + 'name': 'int32_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'int32_optional_key', + 'name': 'int32_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'int32_optional_value', + 'name': 'int32_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'int32_optional_both', + 'name': 'int32_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'enum_required', + 'name': 'enum_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] - } - }, - { - 'name': 'enum_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } } }, { - 'name': 'enum_optional_value', + 'name': 'enum_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } } }, { - 'name': 'enum_optional_both', + 'name': 'enum_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] - } - }, - { - 'name': 'object_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'boolean_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' - } - } - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } } }, { - 'name': 'object_optional_key', + 'name': 'enum_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'string_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'object_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_optional_value', + 'name': 'object_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'float_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_optional_both', + 'name': 'object_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'int32_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_required_nested_2_layers', - 'optional': false, + 'name': 'object_array_optional_both', + 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'object_optional_nested_1_layer', - 'optional': true, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'boolean_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } - }, - { - 'name': 'string_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation' - } - }, - { - 'name': 'double_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' - } - }, - { - 'name': 'float_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' - } - }, - { - 'name': 'int32_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } - } - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_readonly_required', + 'name': 'int32_array_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'boolean_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] + } } }, { - 'name': 'object_readonly_optional_key', + 'name': 'int32_array_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'string_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] + } } }, { - 'name': 'object_readonly_optional_value', + 'name': 'int32_array_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'float_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] + } } }, { - 'name': 'object_readonly_optional_both', + 'name': 'int32_array_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'int32_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] + } } } ] @@ -8787,9 +15693,10 @@ exports[`RN Codegen Flow Parser can generate fixture PROPS_AND_EVENTS_TYPES_EXPO } }, { - 'name': 'onDirectEventDefinedInline', + 'name': 'onDirectEventDefinedInlineWithPaperName', 'optional': false, 'bubblingType': 'direct', + 'paperTopLevelNameDeprecated': 'paperDirectEventDefinedInlineWithPaperName', 'typeAnnotation': { 'type': 'EventTypeAnnotation', 'argument': { @@ -9159,384 +16066,389 @@ exports[`RN Codegen Flow Parser can generate fixture PROPS_AND_EVENTS_TYPES_EXPO } ] } - } - ] - } - } - }, - { - 'name': 'onDirectEventDefinedInlineWithPaperName', - 'optional': false, - 'bubblingType': 'direct', - 'paperTopLevelNameDeprecated': 'paperDirectEventDefinedInlineWithPaperName', - 'typeAnnotation': { - 'type': 'EventTypeAnnotation', - 'argument': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ + }, { - 'name': 'boolean_required', + 'name': 'boolean_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'boolean_optional_key', + 'name': 'boolean_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'boolean_optional_value', + 'name': 'boolean_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'boolean_optional_both', + 'name': 'boolean_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'string_required', + 'name': 'string_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'string_optional_key', + 'name': 'string_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'string_optional_value', + 'name': 'string_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'string_optional_both', + 'name': 'string_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'double_required', + 'name': 'double_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } } }, { - 'name': 'double_optional_key', + 'name': 'double_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } } }, { - 'name': 'double_optional_value', + 'name': 'double_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } } }, { - 'name': 'double_optional_both', + 'name': 'double_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } } }, { - 'name': 'float_required', + 'name': 'float_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'float_optional_key', + 'name': 'float_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'float_optional_value', + 'name': 'float_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'float_optional_both', + 'name': 'float_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'int32_required', + 'name': 'int32_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'int32_optional_key', + 'name': 'int32_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'int32_optional_value', + 'name': 'int32_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'int32_optional_both', + 'name': 'int32_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'enum_required', + 'name': 'enum_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } } }, { - 'name': 'enum_optional_key', + 'name': 'enum_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } } }, { - 'name': 'enum_optional_value', + 'name': 'enum_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } } }, { - 'name': 'enum_optional_both', + 'name': 'enum_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } } }, { - 'name': 'object_required', + 'name': 'object_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'boolean_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_optional_key', + 'name': 'object_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'string_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_optional_value', + 'name': 'object_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'float_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_optional_both', + 'name': 'object_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'int32_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } - } - ] - } - }, - { - 'name': 'object_required_nested_2_layers', - 'optional': false, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'object_optional_nested_1_layer', - 'optional': true, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'boolean_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } - }, - { - 'name': 'string_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation' - } - }, - { - 'name': 'double_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' - } - }, - { - 'name': 'float_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' - } - }, - { - 'name': 'int32_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } - } - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_readonly_required', + 'name': 'int32_array_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'boolean_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] + } } }, { - 'name': 'object_readonly_optional_key', + 'name': 'int32_array_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'string_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] + } } }, { - 'name': 'object_readonly_optional_value', + 'name': 'int32_array_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'float_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] + } } }, { - 'name': 'object_readonly_optional_both', + 'name': 'int32_array_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'int32_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] + } } } ] diff --git a/packages/react-native-codegen/src/parsers/flow/components/componentsUtils.js b/packages/react-native-codegen/src/parsers/flow/components/componentsUtils.js index d694fe2f795e3a..7497c702579868 100644 --- a/packages/react-native-codegen/src/parsers/flow/components/componentsUtils.js +++ b/packages/react-native-codegen/src/parsers/flow/components/componentsUtils.js @@ -10,10 +10,10 @@ 'use strict'; -import type {ASTNode} from '../utils'; import type {NamedShape} from '../../../CodegenSchema.js'; const {getValueFromTypes} = require('../utils.js'); -import type {TypeDeclarationMap} from '../../utils'; +import type {TypeDeclarationMap, PropAST, ASTNode} from '../../utils'; +import type {BuildSchemaFN, Parser} from '../../parser'; function getProperties( typeName: string, @@ -34,7 +34,8 @@ function getTypeAnnotationForArray<+T>( typeAnnotation: $FlowFixMe, defaultValue: $FlowFixMe | null, types: TypeDeclarationMap, - buildSchema: (property: PropAST, types: TypeDeclarationMap) => ?NamedShape, + parser: Parser, + buildSchema: BuildSchemaFN, ): $FlowFixMe { const extractedTypeAnnotation = getValueFromTypes(typeAnnotation, types); if (extractedTypeAnnotation.type === 'NullableTypeAnnotation') { @@ -63,7 +64,7 @@ function getTypeAnnotationForArray<+T>( objectType.typeParameters.params[0].properties, types, ) - .map(prop => buildSchema(prop, types)) + .map(prop => buildSchema(prop, types, parser)) .filter(Boolean), }; } @@ -84,7 +85,7 @@ function getTypeAnnotationForArray<+T>( nestedObjectType.typeParameters.params[0].properties, types, ) - .map(prop => buildSchema(prop, types)) + .map(prop => buildSchema(prop, types, parser)) .filter(Boolean), }, }; @@ -233,7 +234,8 @@ function getTypeAnnotation<+T>( defaultValue: $FlowFixMe | null, withNullDefault: boolean, types: TypeDeclarationMap, - buildSchema: (property: PropAST, types: TypeDeclarationMap) => ?NamedShape, + parser: Parser, + buildSchema: BuildSchemaFN, ): $FlowFixMe { const typeAnnotation = getValueFromTypes(annotation, types); @@ -248,6 +250,7 @@ function getTypeAnnotation<+T>( typeAnnotation.typeParameters.params[0], defaultValue, types, + parser, buildSchema, ), }; @@ -263,7 +266,7 @@ function getTypeAnnotation<+T>( typeAnnotation.typeParameters.params[0].properties, types, ) - .map(prop => buildSchema(prop, types)) + .map(prop => buildSchema(prop, types, parser)) .filter(Boolean), }; } @@ -499,9 +502,6 @@ function getSchemaInfo( }; } -// $FlowFixMe[unclear-type] there's no flowtype for ASTs -type PropAST = Object; - module.exports = { getProperties, getSchemaInfo, diff --git a/packages/react-native-codegen/src/parsers/flow/components/events.js b/packages/react-native-codegen/src/parsers/flow/components/events.js index fefa09cefb9f60..9c7f0312c0e4ef 100644 --- a/packages/react-native-codegen/src/parsers/flow/components/events.js +++ b/packages/react-native-codegen/src/parsers/flow/components/events.js @@ -15,6 +15,12 @@ import type { NamedShape, EventTypeAnnotation, } from '../../../CodegenSchema.js'; +import type {Parser} from '../../parser'; +const { + throwIfEventHasNoName, + throwIfBubblingTypeIsNull, +} = require('../../error-utils'); +const {getEventArgument} = require('../../parsers-commons'); function getPropertyType( /* $FlowFixMe[missing-local-annot] The type annotation(s) required by Flow's @@ -22,11 +28,9 @@ function getPropertyType( name, optional: boolean, typeAnnotation: $FlowFixMe, + parser: Parser, ): NamedShape { - const type = - typeAnnotation.type === 'GenericTypeAnnotation' - ? typeAnnotation.id.name - : typeAnnotation.type; + const type = extractTypeFromTypeAnnotation(typeAnnotation); switch (type) { case 'BooleanTypeAnnotation': @@ -74,6 +78,7 @@ function getPropertyType( name, optional, typeAnnotation.typeParameters.params[0], + parser, ); case 'ObjectTypeAnnotation': return { @@ -81,7 +86,9 @@ function getPropertyType( optional, typeAnnotation: { type: 'ObjectTypeAnnotation', - properties: typeAnnotation.properties.map(buildPropertiesForEvent), + properties: typeAnnotation.properties.map(member => + buildPropertiesForEvent(member, parser), + ), }, }; case 'UnionTypeAnnotation': @@ -101,13 +108,96 @@ function getPropertyType( type: 'MixedTypeAnnotation', }, }; + case 'ArrayTypeAnnotation': + case '$ReadOnlyArray': + return { + name, + optional, + typeAnnotation: extractArrayElementType(typeAnnotation, name, parser), + }; default: - (type: empty); throw new Error(`Unable to determine event type for "${name}": ${type}`); } } +function extractArrayElementType( + typeAnnotation: $FlowFixMe, + name: string, + parser: Parser, +): EventTypeAnnotation { + const type = extractTypeFromTypeAnnotation(typeAnnotation); + + switch (type) { + case 'BooleanTypeAnnotation': + return {type: 'BooleanTypeAnnotation'}; + case 'StringTypeAnnotation': + return {type: 'StringTypeAnnotation'}; + case 'Int32': + return {type: 'Int32TypeAnnotation'}; + case 'Float': + return {type: 'FloatTypeAnnotation'}; + case 'NumberTypeAnnotation': + case 'Double': + return { + type: 'DoubleTypeAnnotation', + }; + case 'UnionTypeAnnotation': + return { + type: 'StringEnumTypeAnnotation', + options: typeAnnotation.types.map(option => option.value), + }; + case 'UnsafeMixed': + return {type: 'MixedTypeAnnotation'}; + case 'ObjectTypeAnnotation': + return { + type: 'ObjectTypeAnnotation', + properties: typeAnnotation.properties.map(member => + buildPropertiesForEvent(member, parser), + ), + }; + case 'ArrayTypeAnnotation': + return { + type: 'ArrayTypeAnnotation', + elementType: extractArrayElementType( + typeAnnotation.elementType, + name, + parser, + ), + }; + case '$ReadOnlyArray': + const genericParams = typeAnnotation.typeParameters.params; + if (genericParams.length !== 1) { + throw new Error( + `Events only supports arrays with 1 Generic type. Found ${ + genericParams.length + } types:\n${prettify(genericParams)}`, + ); + } + return { + type: 'ArrayTypeAnnotation', + elementType: extractArrayElementType(genericParams[0], name, parser), + }; + default: + throw new Error( + `Unrecognized ${type} for Array ${name} in events.\n${prettify( + typeAnnotation, + )}`, + ); + } +} + +function prettify(jsonObject: $FlowFixMe): string { + return JSON.stringify(jsonObject, null, 2); +} + +function extractTypeFromTypeAnnotation(typeAnnotation: $FlowFixMe): string { + return typeAnnotation.type === 'GenericTypeAnnotation' + ? typeAnnotation.id.name + : typeAnnotation.type; +} + function findEventArgumentsAndType( + parser: Parser, typeAnnotation: $FlowFixMe, types: TypeMap, bubblingType: void | 'direct' | 'bubble', @@ -117,9 +207,7 @@ function findEventArgumentsAndType( bubblingType: ?('direct' | 'bubble'), paperTopLevelNameDeprecated: ?$FlowFixMe, } { - if (!typeAnnotation.id) { - throw new Error("typeAnnotation of event doesn't have a name"); - } + throwIfEventHasNoName(typeAnnotation, parser); const name = typeAnnotation.id.name; if (name === '$ReadOnly') { return { @@ -144,6 +232,7 @@ function findEventArgumentsAndType( }; } return findEventArgumentsAndType( + parser, typeAnnotation.typeParameters.params[0], types, eventType, @@ -151,6 +240,7 @@ function findEventArgumentsAndType( ); } else if (types[name]) { return findEventArgumentsAndType( + parser, types[name].right, types, bubblingType, @@ -165,32 +255,26 @@ function findEventArgumentsAndType( } } -/* $FlowFixMe[missing-local-annot] The type annotation(s) required by Flow's - * LTI update could not be added via codemod */ -function buildPropertiesForEvent(property): NamedShape { +function buildPropertiesForEvent( + /* $FlowFixMe[missing-local-annot] The type annotation(s) required by Flow's + * LTI update could not be added via codemod */ + property, + parser: Parser, +): NamedShape { const name = property.key.name; - const optional = - property.value.type === 'NullableTypeAnnotation' || property.optional; + const optional = parser.isOptionalProperty(property); let typeAnnotation = property.value.type === 'NullableTypeAnnotation' ? property.value.typeAnnotation : property.value; - return getPropertyType(name, optional, typeAnnotation); -} - -/* $FlowFixMe[missing-local-annot] The type annotation(s) required by Flow's - * LTI update could not be added via codemod */ -function getEventArgument(argumentProps, name: $FlowFixMe) { - return { - type: 'ObjectTypeAnnotation', - properties: argumentProps.map(buildPropertiesForEvent), - }; + return getPropertyType(name, optional, typeAnnotation, parser); } function buildEventSchema( types: TypeMap, property: EventTypeAST, + parser: Parser, ): ?EventTypeShape { const name = property.key.name; const optional = @@ -210,29 +294,29 @@ function buildEventSchema( } const {argumentProps, bubblingType, paperTopLevelNameDeprecated} = - findEventArgumentsAndType(typeAnnotation, types); + findEventArgumentsAndType(parser, typeAnnotation, types); - if (bubblingType && argumentProps) { - if (paperTopLevelNameDeprecated != null) { - return { - name, - optional, - bubblingType, - paperTopLevelNameDeprecated, - typeAnnotation: { - type: 'EventTypeAnnotation', - argument: getEventArgument(argumentProps, name), - }, - }; - } + if (!argumentProps) { + throw new Error(`Unable to determine event arguments for "${name}"`); + } + if (!bubblingType) { + throw new Error(`Unable to determine event arguments for "${name}"`); + } + + if (paperTopLevelNameDeprecated != null) { return { name, optional, bubblingType, + paperTopLevelNameDeprecated, typeAnnotation: { type: 'EventTypeAnnotation', - argument: getEventArgument(argumentProps, name), + argument: getEventArgument( + argumentProps, + buildPropertiesForEvent, + parser, + ), }, }; } @@ -241,9 +325,21 @@ function buildEventSchema( throw new Error(`Unable to determine event arguments for "${name}"`); } - if (bubblingType === null) { - throw new Error(`Unable to determine event arguments for "${name}"`); - } + throwIfBubblingTypeIsNull(bubblingType, name); + + return { + name, + optional, + bubblingType, + typeAnnotation: { + type: 'EventTypeAnnotation', + argument: getEventArgument( + argumentProps, + buildPropertiesForEvent, + parser, + ), + }, + }; } // $FlowFixMe[unclear-type] there's no flowtype for ASTs @@ -258,10 +354,11 @@ type TypeMap = { function getEvents( eventTypeAST: $ReadOnlyArray, types: TypeMap, + parser: Parser, ): $ReadOnlyArray { return eventTypeAST .filter(property => property.type === 'ObjectTypeProperty') - .map(property => buildEventSchema(types, property)) + .map(property => buildEventSchema(types, property, parser)) .filter(Boolean); } diff --git a/packages/react-native-codegen/src/parsers/flow/components/extends.js b/packages/react-native-codegen/src/parsers/flow/components/extends.js deleted file mode 100644 index d53147d9d4f505..00000000000000 --- a/packages/react-native-codegen/src/parsers/flow/components/extends.js +++ /dev/null @@ -1,66 +0,0 @@ -/** - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @flow strict - * @format - */ - -'use strict'; - -import type {ExtendsPropsShape} from '../../../CodegenSchema.js'; -import type {TypeDeclarationMap} from '../../utils'; - -function extendsForProp(prop: PropsAST, types: TypeDeclarationMap) { - if (!prop.argument) { - console.log('null', prop); - } - const name = prop.argument.id.name; - - if (types[name] != null) { - // This type is locally defined in the file - return null; - } - - switch (name) { - case 'ViewProps': - return { - type: 'ReactNativeBuiltInType', - knownTypeName: 'ReactNativeCoreViewProps', - }; - default: { - throw new Error(`Unable to handle prop spread: ${name}`); - } - } -} - -function removeKnownExtends( - typeDefinition: $ReadOnlyArray, - types: TypeDeclarationMap, -): $ReadOnlyArray { - return typeDefinition.filter( - prop => - prop.type !== 'ObjectTypeSpreadProperty' || - extendsForProp(prop, types) === null, - ); -} - -// $FlowFixMe[unclear-type] there's no flowtype for ASTs -type PropsAST = Object; - -function getExtendsProps( - typeDefinition: $ReadOnlyArray, - types: TypeDeclarationMap, -): $ReadOnlyArray { - return typeDefinition - .filter(prop => prop.type === 'ObjectTypeSpreadProperty') - .map(prop => extendsForProp(prop, types)) - .filter(Boolean); -} - -module.exports = { - getExtendsProps, - removeKnownExtends, -}; diff --git a/packages/react-native-codegen/src/parsers/flow/components/index.js b/packages/react-native-codegen/src/parsers/flow/components/index.js index a216417f9cbc95..a86fc9f9016539 100644 --- a/packages/react-native-codegen/src/parsers/flow/components/index.js +++ b/packages/react-native-codegen/src/parsers/flow/components/index.js @@ -14,7 +14,6 @@ import type {ComponentSchemaBuilderConfig} from '../../schema.js'; const {getCommands} = require('./commands'); const {getEvents} = require('./events'); -const {getExtendsProps, removeKnownExtends} = require('./extends'); const {getProps} = require('./props'); const {getProperties} = require('./componentsUtils.js'); const {throwIfMoreThanOneCodegenNativecommands} = require('../../error-utils'); @@ -126,15 +125,11 @@ function buildComponentSchema( const types = parser.getTypes(ast); const propProperties = getProperties(propsTypeName, types); - const commandProperties = getCommandProperties(ast, parser); + const {extendsProps, props} = getProps(propProperties, types, parser); - const extendsProps = getExtendsProps(propProperties, types); const options = getOptions(optionsExpression); - - const nonExtendsProps = removeKnownExtends(propProperties, types); - const props = getProps(nonExtendsProps, types); - const events = getEvents(propProperties, types); + const events = getEvents(propProperties, types, parser); const commands = getCommands(commandProperties, types); return { diff --git a/packages/react-native-codegen/src/parsers/flow/components/props.js b/packages/react-native-codegen/src/parsers/flow/components/props.js index 70ff36e8526ea1..1542e8f4e8b554 100644 --- a/packages/react-native-codegen/src/parsers/flow/components/props.js +++ b/packages/react-native-codegen/src/parsers/flow/components/props.js @@ -10,49 +10,93 @@ 'use strict'; -const { - flattenProperties, - getSchemaInfo, - getTypeAnnotation, -} = require('./componentsUtils.js'); +import type { + ExtendsPropsShape, + NamedShape, + PropTypeAnnotation, +} from '../../../CodegenSchema.js'; +import type {TypeDeclarationMap, PropAST} from '../../utils'; +import type {Parser} from '../../parser'; -import type {NamedShape, PropTypeAnnotation} from '../../../CodegenSchema.js'; -import type {TypeDeclarationMap} from '../../utils'; +const {flattenProperties} = require('./componentsUtils.js'); +const {buildPropSchema} = require('../../parsers-commons'); -// $FlowFixMe[unclear-type] there's no flowtype for ASTs -type PropAST = Object; +type ExtendsForProp = null | { + type: 'ReactNativeBuiltInType', + knownTypeName: 'ReactNativeCoreViewProps', +}; -function buildPropSchema( - property: PropAST, +function extendsForProp( + prop: PropAST, types: TypeDeclarationMap, -): ?NamedShape { - const info = getSchemaInfo(property, types); - if (info == null) { + parser: Parser, +): ExtendsForProp { + const argument = parser.argumentForProp(prop); + if (!argument) { + console.log('null', prop); + } + const name = parser.nameForArgument(prop); + + if (types[name] != null) { + // This type is locally defined in the file return null; } - const {name, optional, typeAnnotation, defaultValue, withNullDefault} = info; - return { - name, - optional, - typeAnnotation: getTypeAnnotation( - name, - typeAnnotation, - defaultValue, - withNullDefault, - types, - buildPropSchema, - ), - }; + switch (name) { + case 'ViewProps': + return { + type: 'ReactNativeBuiltInType', + knownTypeName: 'ReactNativeCoreViewProps', + }; + default: { + throw new Error(`Unable to handle prop spread: ${name}`); + } + } +} + +function removeKnownExtends( + typeDefinition: $ReadOnlyArray, + types: TypeDeclarationMap, + parser: Parser, +): $ReadOnlyArray { + return typeDefinition.filter( + prop => + prop.type !== 'ObjectTypeSpreadProperty' || + extendsForProp(prop, types, parser) === null, + ); } +function getExtendsProps( + typeDefinition: $ReadOnlyArray, + types: TypeDeclarationMap, + parser: Parser, +): $ReadOnlyArray { + return typeDefinition + .filter(prop => prop.type === 'ObjectTypeSpreadProperty') + .map(prop => extendsForProp(prop, types, parser)) + .filter(Boolean); +} +/** + * Extracts the `props` and `extendsProps` (props with `extends` syntax) + * from a type definition AST. + */ function getProps( typeDefinition: $ReadOnlyArray, types: TypeDeclarationMap, -): $ReadOnlyArray> { - return flattenProperties(typeDefinition, types) - .map(property => buildPropSchema(property, types)) + parser: Parser, +): { + props: $ReadOnlyArray>, + extendsProps: $ReadOnlyArray, +} { + const nonExtendsProps = removeKnownExtends(typeDefinition, types, parser); + const props = flattenProperties(nonExtendsProps, types) + .map(property => buildPropSchema(property, types, parser)) .filter(Boolean); + + return { + props, + extendsProps: getExtendsProps(typeDefinition, types, parser), + }; } module.exports = { 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 6de97cbbc6b47a..00d66fd81de929 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 @@ -201,14 +201,26 @@ exports[`RN Codegen Flow Parser can generate fixture CXX_ONLY_NATIVE_MODULE 1`] 'typeAnnotation': { 'type': 'FunctionTypeAnnotation', 'returnTypeAnnotation': { - 'type': 'GenericObjectTypeAnnotation' + 'type': 'GenericObjectTypeAnnotation', + 'dictionaryValueType': { + 'type': 'NullableTypeAnnotation', + 'typeAnnotation': { + 'type': 'NumberTypeAnnotation' + } + } }, 'params': [ { 'name': 'arg', 'optional': false, 'typeAnnotation': { - 'type': 'GenericObjectTypeAnnotation' + 'type': 'GenericObjectTypeAnnotation', + 'dictionaryValueType': { + 'type': 'NullableTypeAnnotation', + 'typeAnnotation': { + 'type': 'NumberTypeAnnotation' + } + } } } ] @@ -220,14 +232,20 @@ exports[`RN Codegen Flow Parser can generate fixture CXX_ONLY_NATIVE_MODULE 1`] 'typeAnnotation': { 'type': 'FunctionTypeAnnotation', 'returnTypeAnnotation': { - 'type': 'GenericObjectTypeAnnotation' + 'type': 'GenericObjectTypeAnnotation', + 'dictionaryValueType': { + 'type': 'StringTypeAnnotation' + } }, 'params': [ { 'name': 'arg', 'optional': false, 'typeAnnotation': { - 'type': 'GenericObjectTypeAnnotation' + 'type': 'GenericObjectTypeAnnotation', + 'dictionaryValueType': { + 'type': 'StringTypeAnnotation' + } } } ] @@ -2165,7 +2183,11 @@ exports[`RN Codegen Flow Parser can generate fixture PROMISE_WITH_COMMONLY_USED_ 'returnTypeAnnotation': { 'type': 'PromiseTypeAnnotation', 'elementType': { - 'type': 'GenericObjectTypeAnnotation' + 'type': 'GenericObjectTypeAnnotation', + 'dictionaryValueType': { + 'type': 'TypeAliasTypeAnnotation', + 'name': 'CustomObject' + } } }, 'params': [] 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 1b7b2503f70d25..75352fea2bf67e 100644 --- a/packages/react-native-codegen/src/parsers/flow/modules/index.js +++ b/packages/react-native-codegen/src/parsers/flow/modules/index.js @@ -32,7 +32,7 @@ const { const { emitArrayType, emitFunction, - emitGenericObject, + emitDictionary, emitPromise, emitRootTag, emitUnion, @@ -152,7 +152,7 @@ function translateTypeAnnotation( // check the property type to prevent developers from using unsupported types // the return value from `translateTypeAnnotation` is unused const propertyType = indexers[0].value; - translateTypeAnnotation( + const valueType = translateTypeAnnotation( hasteModuleName, propertyType, types, @@ -163,7 +163,7 @@ function translateTypeAnnotation( parser, ); // no need to do further checking - return emitGenericObject(nullable); + return emitDictionary(nullable, valueType); } } diff --git a/packages/react-native-codegen/src/parsers/flow/parser.js b/packages/react-native-codegen/src/parsers/flow/parser.js index b15fc4b56ab32e..5758bfb404643a 100644 --- a/packages/react-native-codegen/src/parsers/flow/parser.js +++ b/packages/react-native-codegen/src/parsers/flow/parser.js @@ -22,8 +22,13 @@ import type { NativeModuleEnumMap, } from '../../CodegenSchema'; import type {ParserType} from '../errors'; -import type {Parser} from '../parser'; -import type {ParserErrorCapturer, TypeDeclarationMap} from '../utils'; +import type {GetSchemaInfoFN, GetTypeAnnotationFN, Parser} from '../parser'; +import type {ParserErrorCapturer, TypeDeclarationMap, PropAST} from '../utils'; + +const { + getSchemaInfo, + getTypeAnnotation, +} = require('./components/componentsUtils'); const {flowTranslateTypeAnnotation} = require('./modules'); @@ -329,6 +334,28 @@ class FlowParser implements Parser { convertKeywordToTypeAnnotation(keyword: string): string { return keyword; } + + argumentForProp(prop: PropAST): $FlowFixMe { + return prop.argument; + } + + nameForArgument(prop: PropAST): $FlowFixMe { + return prop.argument.id.name; + } + + isOptionalProperty(property: $FlowFixMe): boolean { + return ( + property.value.type === 'NullableTypeAnnotation' || property.optional + ); + } + + getGetSchemaInfoFN(): GetSchemaInfoFN { + return getSchemaInfo; + } + + getGetTypeAnnotationFN(): GetTypeAnnotationFN { + return getTypeAnnotation; + } } 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 3692cf16f89b7c..258c9258512fc0 100644 --- a/packages/react-native-codegen/src/parsers/flow/utils.js +++ b/packages/react-native-codegen/src/parsers/flow/utils.js @@ -10,10 +10,7 @@ 'use strict'; -import type {TypeResolutionStatus, TypeDeclarationMap} from '../utils'; - -// $FlowFixMe[unclear-type] there's no flowtype for ASTs -export type ASTNode = Object; +import type {TypeResolutionStatus, TypeDeclarationMap, ASTNode} from '../utils'; const invariant = require('invariant'); diff --git a/packages/react-native-codegen/src/parsers/parser.js b/packages/react-native-codegen/src/parsers/parser.js index a8c2feccffc4f9..b95cc3d5ad2d01 100644 --- a/packages/react-native-codegen/src/parsers/parser.js +++ b/packages/react-native-codegen/src/parsers/parser.js @@ -22,7 +22,45 @@ import type { NativeModuleEnumMap, } from '../CodegenSchema'; import type {ParserType} from './errors'; -import type {ParserErrorCapturer, TypeDeclarationMap} from './utils'; +import type { + ParserErrorCapturer, + TypeDeclarationMap, + PropAST, + ASTNode, +} from './utils'; + +export type GetTypeAnnotationFN = ( + name: string, + annotation: $FlowFixMe | ASTNode, + defaultValue: $FlowFixMe | void, + withNullDefault: boolean, + types: TypeDeclarationMap, + parser: Parser, + buildSchema: ( + property: PropAST, + types: TypeDeclarationMap, + parser: Parser, + ) => $FlowFixMe, +) => $FlowFixMe; + +export type SchemaInfo = { + name: string, + optional: boolean, + typeAnnotation: $FlowFixMe, + defaultValue: $FlowFixMe, + withNullDefault: boolean, +}; + +export type GetSchemaInfoFN = ( + property: PropAST, + types: TypeDeclarationMap, +) => ?SchemaInfo; + +export type BuildSchemaFN = ( + property: PropAST, + types: TypeDeclarationMap, + parser: Parser, +) => ?NamedShape; /** * This is the main interface for Parsers of various languages. @@ -255,4 +293,29 @@ export interface Parser { * @returns: converted TypeAnnotation to Keywords */ convertKeywordToTypeAnnotation(keyword: string): string; + + /** + * Given a prop return its arguments. + * @parameter prop + * @returns: Arguments of the prop + */ + argumentForProp(prop: PropAST): $FlowFixMe; + + /** + * Given a prop return its name. + * @parameter prop + * @returns: name property + */ + nameForArgument(prop: PropAST): $FlowFixMe; + + /** + * Given a property return if it is optional. + * @parameter property + * @returns: a boolean specifying if the Property is optional + */ + isOptionalProperty(property: $FlowFixMe): boolean; + + getGetTypeAnnotationFN(): GetTypeAnnotationFN; + + getGetSchemaInfoFN(): GetSchemaInfoFN; } diff --git a/packages/react-native-codegen/src/parsers/parserMock.js b/packages/react-native-codegen/src/parsers/parserMock.js index e31b9de7cc05f7..4dbb5246c24102 100644 --- a/packages/react-native-codegen/src/parsers/parserMock.js +++ b/packages/react-native-codegen/src/parsers/parserMock.js @@ -10,7 +10,7 @@ 'use strict'; -import type {Parser} from './parser'; +import type {GetSchemaInfoFN, GetTypeAnnotationFN, Parser} from './parser'; import type {ParserType} from './errors'; import type { UnionTypeAnnotationMemberType, @@ -23,7 +23,7 @@ import type { NativeModuleAliasMap, NativeModuleEnumMap, } from '../CodegenSchema'; -import type {ParserErrorCapturer, TypeDeclarationMap} from './utils'; +import type {ParserErrorCapturer, PropAST, TypeDeclarationMap} from './utils'; // $FlowFixMe[untyped-import] there's no flowtype flow-parser const flowParser = require('flow-parser'); @@ -243,4 +243,34 @@ export class MockedParser implements Parser { convertKeywordToTypeAnnotation(keyword: string): string { return keyword; } + + argumentForProp(prop: PropAST): $FlowFixMe { + return prop.expression; + } + + nameForArgument(prop: PropAST): $FlowFixMe { + return prop.expression.name; + } + + isOptionalProperty(property: $FlowFixMe): boolean { + return property.optional || false; + } + + getGetTypeAnnotationFN(): GetTypeAnnotationFN { + return () => { + return {}; + }; + } + + getGetSchemaInfoFN(): GetSchemaInfoFN { + return () => { + return { + name: 'MockedSchema', + optional: false, + typeAnnotation: 'BooleanTypeAnnotation', + defaultValue: false, + withNullDefault: false, + }; + }; + } } diff --git a/packages/react-native-codegen/src/parsers/parsers-commons.js b/packages/react-native-codegen/src/parsers/parsers-commons.js index 6fbb0baf8e87cc..0b9f06c36cb060 100644 --- a/packages/react-native-codegen/src/parsers/parsers-commons.js +++ b/packages/react-native-codegen/src/parsers/parsers-commons.js @@ -23,11 +23,14 @@ import type { SchemaType, NativeModuleEnumMap, OptionsShape, + PropTypeAnnotation, + EventTypeAnnotation, + ObjectTypeAnnotation, } from '../CodegenSchema.js'; import type {Parser} from './parser'; import type {ParserType} from './errors'; -import type {ParserErrorCapturer, TypeDeclarationMap} from './utils'; +import type {ParserErrorCapturer, TypeDeclarationMap, PropAST} from './utils'; import type {ComponentSchemaBuilderConfig} from './schema.js'; const { @@ -69,6 +72,11 @@ export type CommandOptions = $ReadOnly<{ // $FlowFixMe[unclear-type] TODO(T108222691): Use flow-types for @babel/parser type OptionsAST = Object; +type ExtendedPropResult = { + type: 'ReactNativeBuiltInType', + knownTypeName: 'ReactNativeCoreViewProps', +} | null; + function wrapModuleSchema( nativeModuleSchema: NativeModuleSchema, hasteModuleName: string, @@ -817,6 +825,83 @@ function propertyNames( .filter(Boolean); } +function extendsForProp( + prop: PropAST, + types: TypeDeclarationMap, + parser: Parser, +): ExtendedPropResult { + const argument = parser.argumentForProp(prop); + + if (!argument) { + console.log('null', prop); + } + + const name = parser.nameForArgument(prop); + + if (types[name] != null) { + // This type is locally defined in the file + return null; + } + + switch (name) { + case 'ViewProps': + return { + type: 'ReactNativeBuiltInType', + knownTypeName: 'ReactNativeCoreViewProps', + }; + default: { + throw new Error(`Unable to handle prop spread: ${name}`); + } + } +} + +function buildPropSchema( + property: PropAST, + types: TypeDeclarationMap, + parser: Parser, +): ?NamedShape { + const getSchemaInfoFN = parser.getGetSchemaInfoFN(); + const info = getSchemaInfoFN(property, types); + if (info == null) { + return null; + } + const {name, optional, typeAnnotation, defaultValue, withNullDefault} = info; + + const getTypeAnnotationFN = parser.getGetTypeAnnotationFN(); + + return { + name, + optional, + typeAnnotation: getTypeAnnotationFN( + name, + typeAnnotation, + defaultValue, + withNullDefault, + types, + parser, + buildPropSchema, + ), + }; +} + +/* $FlowFixMe[missing-local-annot] The type annotation(s) required by Flow's + * LTI update could not be added via codemod */ +function getEventArgument( + argumentProps: PropAST, + buildPropertiesForEvent: ( + property: PropAST, + parser: Parser, + ) => NamedShape, + parser: Parser, +): ObjectTypeAnnotation { + return { + type: 'ObjectTypeAnnotation', + properties: argumentProps.map(member => + buildPropertiesForEvent(member, parser), + ), + }; +} + module.exports = { wrapModuleSchema, unwrapNullable, @@ -836,4 +921,7 @@ module.exports = { getCommandOptions, getOptions, getCommandTypeNameAndOptionsExpression, + extendsForProp, + buildPropSchema, + getEventArgument, }; diff --git a/packages/react-native-codegen/src/parsers/parsers-primitives.js b/packages/react-native-codegen/src/parsers/parsers-primitives.js index 849c3e756fb0b5..84ba85949d5e1a 100644 --- a/packages/react-native-codegen/src/parsers/parsers-primitives.js +++ b/packages/react-native-codegen/src/parsers/parsers-primitives.js @@ -309,6 +309,16 @@ function emitGenericObject( }); } +function emitDictionary( + nullable: boolean, + valueType: Nullable, +): Nullable { + return wrapNullable(nullable, { + type: 'GenericObjectTypeAnnotation', + dictionaryValueType: valueType, + }); +} + function emitObject( nullable: boolean, properties: Array<$FlowFixMe>, @@ -576,6 +586,7 @@ module.exports = { emitInt32, emitNumber, emitGenericObject, + emitDictionary, emitObject, emitPromise, emitRootTag, diff --git a/packages/react-native-codegen/src/parsers/typescript/components/__test_fixtures__/fixtures.js b/packages/react-native-codegen/src/parsers/typescript/components/__test_fixtures__/fixtures.js index 57aafa7b5562d4..7f81b17e6cc3fe 100644 --- a/packages/react-native-codegen/src/parsers/typescript/components/__test_fixtures__/fixtures.js +++ b/packages/react-native-codegen/src/parsers/typescript/components/__test_fixtures__/fixtures.js @@ -84,6 +84,57 @@ const EVENT_DEFINITION = ` object_readonly_optional_both?: Readonly<{ int32_optional_both?: Int32 | null | undefined; }> | null | undefined; + + boolean_array_required: boolean[]; + boolean_array_optional_key?: boolean[]; + boolean_array_optional_value: boolean[] | null | undefined; + boolean_array_optional_both?: boolean[] | null | undefined; + + string_array_required: string[]; + string_array_optional_key?: (string[]); + string_array_optional_value: (string[]) | null | undefined; + string_array_optional_both?: (string[] | null | undefined); + + double_array_required: Double[]; + double_array_optional_key?: Double[]; + double_array_optional_value: Double[] | null | undefined; + double_array_optional_both?: Double[] | null | undefined; + + float_array_required: Float[]; + float_array_optional_key?: Float[]; + float_array_optional_value: Float[] | null | undefined; + float_array_optional_both?: Float[] | null | undefined; + + int32_array_required: Int32[]; + int32_array_optional_key?: Int32[]; + int32_array_optional_value: Int32[] | null | undefined; + int32_array_optional_both?: Int32[] | null | undefined; + + enum_array_required: ('small' | 'large')[]; + enum_array_optional_key?: ('small' | 'large')[]; + enum_array_optional_value: ('small' | 'large')[] | null | undefined; + enum_array_optional_both?: ('small' | 'large')[] | null | undefined; + + object_array_required: { + boolean_required: boolean; + }[]; + + object_array_optional_key?: { + string_optional_key?: string; + }[]; + + object_array_optional_value: { + float_optional_value: Float | null | undefined; + }[] | null | undefined; + + object_array_optional_both?: { + int32_optional_both?: Int32 | null | undefined; + }[] | null | undefined; + + int32_array_array_required: Int32[][]; + int32_array_array_optional_key?: Int32[][]; + int32_array_array_optional_value: Int32[][] | null | undefined; + int32_array_array_optional_both?: Int32[][] | null | undefined; `; const ONE_OF_EACH_PROP_EVENT_DEFAULT_AND_OPTIONS = ` diff --git a/packages/react-native-codegen/src/parsers/typescript/components/__tests__/__snapshots__/typescript-component-parser-test.js.snap b/packages/react-native-codegen/src/parsers/typescript/components/__tests__/__snapshots__/typescript-component-parser-test.js.snap index 4211709793e576..59699c28576fb4 100644 --- a/packages/react-native-codegen/src/parsers/typescript/components/__tests__/__snapshots__/typescript-component-parser-test.js.snap +++ b/packages/react-native-codegen/src/parsers/typescript/components/__tests__/__snapshots__/typescript-component-parser-test.js.snap @@ -2548,384 +2548,389 @@ exports[`RN Codegen TypeScript Parser can generate fixture COMMANDS_EVENTS_TYPES } ] } - } - ] - } - } - }, - { - 'name': 'onBubblingEventDefinedInlineWithPaperName', - 'optional': false, - 'bubblingType': 'bubble', - 'paperTopLevelNameDeprecated': 'paperBubblingEventDefinedInlineWithPaperName', - 'typeAnnotation': { - 'type': 'EventTypeAnnotation', - 'argument': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ + }, { - 'name': 'boolean_required', + 'name': 'boolean_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'boolean_optional_key', + 'name': 'boolean_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'boolean_optional_value', + 'name': 'boolean_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'boolean_optional_both', + 'name': 'boolean_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'string_required', + 'name': 'string_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'string_optional_key', + 'name': 'string_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'string_optional_value', + 'name': 'string_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'string_optional_both', + 'name': 'string_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'double_required', + 'name': 'double_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } } }, { - 'name': 'double_optional_key', + 'name': 'double_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } } }, { - 'name': 'double_optional_value', + 'name': 'double_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } } }, { - 'name': 'double_optional_both', + 'name': 'double_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } } }, { - 'name': 'float_required', + 'name': 'float_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'float_optional_key', + 'name': 'float_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'float_optional_value', + 'name': 'float_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'float_optional_both', + 'name': 'float_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'int32_required', + 'name': 'int32_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'int32_optional_key', + 'name': 'int32_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'int32_optional_value', + 'name': 'int32_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'int32_optional_both', + 'name': 'int32_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'enum_required', + 'name': 'enum_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } } }, { - 'name': 'enum_optional_key', + 'name': 'enum_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } } }, { - 'name': 'enum_optional_value', + 'name': 'enum_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } } }, { - 'name': 'enum_optional_both', + 'name': 'enum_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } } }, { - 'name': 'object_required', + 'name': 'object_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'boolean_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_optional_key', + 'name': 'object_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'string_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_optional_value', + 'name': 'object_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'float_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_optional_both', + 'name': 'object_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'int32_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_required_nested_2_layers', + 'name': 'int32_array_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'object_optional_nested_1_layer', - 'optional': true, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'boolean_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } - }, - { - 'name': 'string_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation' - } - }, - { - 'name': 'double_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' - } - }, - { - 'name': 'float_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' - } - }, - { - 'name': 'int32_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } - } - ] - } - } - ] - } - }, - { - 'name': 'object_readonly_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'boolean_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] + } } }, { - 'name': 'object_readonly_optional_key', + 'name': 'int32_array_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'string_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] + } } }, { - 'name': 'object_readonly_optional_value', + 'name': 'int32_array_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'float_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] + } } }, { - 'name': 'object_readonly_optional_both', + 'name': 'int32_array_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'int32_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] + } } } ] @@ -2933,9 +2938,10 @@ exports[`RN Codegen TypeScript Parser can generate fixture COMMANDS_EVENTS_TYPES } }, { - 'name': 'onDirectEventDefinedInline', + 'name': 'onBubblingEventDefinedInlineWithPaperName', 'optional': false, - 'bubblingType': 'direct', + 'bubblingType': 'bubble', + 'paperTopLevelNameDeprecated': 'paperBubblingEventDefinedInlineWithPaperName', 'typeAnnotation': { 'type': 'EventTypeAnnotation', 'argument': { @@ -3305,641 +3311,399 @@ exports[`RN Codegen TypeScript Parser can generate fixture COMMANDS_EVENTS_TYPES } ] } - } - ] - } - } - }, - { - 'name': 'onDirectEventDefinedInlineWithPaperName', - 'optional': false, - 'bubblingType': 'direct', - 'paperTopLevelNameDeprecated': 'paperDirectEventDefinedInlineWithPaperName', - 'typeAnnotation': { - 'type': 'EventTypeAnnotation', - 'argument': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ + }, { - 'name': 'boolean_required', + 'name': 'boolean_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'boolean_optional_key', + 'name': 'boolean_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'boolean_optional_value', + 'name': 'boolean_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'boolean_optional_both', + 'name': 'boolean_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'string_required', + 'name': 'string_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'string_optional_key', + 'name': 'string_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'string_optional_value', + 'name': 'string_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'string_optional_both', + 'name': 'string_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'double_required', + 'name': 'double_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } } }, { - 'name': 'double_optional_key', + 'name': 'double_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } } }, { - 'name': 'double_optional_value', + 'name': 'double_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } } }, { - 'name': 'double_optional_both', + 'name': 'double_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } } }, { - 'name': 'float_required', + 'name': 'float_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'float_optional_key', + 'name': 'float_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'float_optional_value', + 'name': 'float_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'float_optional_both', + 'name': 'float_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'int32_required', + 'name': 'int32_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'int32_optional_key', + 'name': 'int32_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'int32_optional_value', + 'name': 'int32_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'int32_optional_both', + 'name': 'int32_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'enum_required', + 'name': 'enum_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } } }, { - 'name': 'enum_optional_key', + 'name': 'enum_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } } }, { - 'name': 'enum_optional_value', + 'name': 'enum_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } } }, { - 'name': 'enum_optional_both', + 'name': 'enum_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } } }, { - 'name': 'object_required', + 'name': 'object_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'boolean_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' - } - } - ] - } - }, - { - 'name': 'object_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'string_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_optional_value', + 'name': 'object_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'float_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_optional_both', + 'name': 'object_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'int32_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_required_nested_2_layers', - 'optional': false, + 'name': 'object_array_optional_both', + 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'object_optional_nested_1_layer', - 'optional': true, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'boolean_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } - }, - { - 'name': 'string_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation' - } - }, - { - 'name': 'double_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' - } - }, - { - 'name': 'float_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' - } - }, - { - 'name': 'int32_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } - } - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_readonly_required', + 'name': 'int32_array_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'boolean_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] + } } }, { - 'name': 'object_readonly_optional_key', + 'name': 'int32_array_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'string_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] + } } }, { - 'name': 'object_readonly_optional_value', + 'name': 'int32_array_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'float_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] + } } }, { - 'name': 'object_readonly_optional_both', + 'name': 'int32_array_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'int32_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] + } } } ] } } - } - ], - 'props': [], - 'commands': [ - { - 'name': 'scrollTo', - 'optional': false, - 'typeAnnotation': { - 'type': 'FunctionTypeAnnotation', - 'params': [ - { - 'name': 'y', - 'optional': false, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } - }, - { - 'name': 'animated', - 'optional': false, - 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' - } - } - ], - 'returnTypeAnnotation': { - 'type': 'VoidTypeAnnotation' - } - } - } - ] - } - } - } - } -}" -`; - -exports[`RN Codegen TypeScript Parser can generate fixture COMMANDS_WITH_EXTERNAL_TYPES 1`] = ` -"{ - 'modules': { - 'Module': { - 'type': 'Component', - 'components': { - 'Module': { - 'extendsProps': [ - { - 'type': 'ReactNativeBuiltInType', - 'knownTypeName': 'ReactNativeCoreViewProps' - } - ], - 'events': [], - 'props': [], - 'commands': [ + }, { - 'name': 'scrollTo', + 'name': 'onDirectEventDefinedInline', 'optional': false, - 'typeAnnotation': { - 'type': 'FunctionTypeAnnotation', - 'params': [ - { - 'name': 'y', - 'optional': false, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } - }, - { - 'name': 'animated', - 'optional': false, - 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' - } - } - ], - 'returnTypeAnnotation': { - 'type': 'VoidTypeAnnotation' - } - } - } - ] - } - } - } - } -}" -`; - -exports[`RN Codegen TypeScript Parser can generate fixture EVENTS_DEFINED_AS_NULL_INLINE 1`] = ` -"{ - 'modules': { - 'Module': { - 'type': 'Component', - 'components': { - 'Module': { - 'extendsProps': [ - { - 'type': 'ReactNativeBuiltInType', - 'knownTypeName': 'ReactNativeCoreViewProps' - } - ], - 'events': [ - { - 'name': 'onDirectEventDefinedInlineNull', - 'optional': false, - 'bubblingType': 'direct', - 'typeAnnotation': { - 'type': 'EventTypeAnnotation', - 'argument': { - 'type': 'ObjectTypeAnnotation', - 'properties': [] - } - } - }, - { - 'name': 'onDirectEventDefinedInlineNullOptionalKey', - 'optional': true, - 'bubblingType': 'direct', - 'typeAnnotation': { - 'type': 'EventTypeAnnotation', - 'argument': { - 'type': 'ObjectTypeAnnotation', - 'properties': [] - } - } - }, - { - 'name': 'onDirectEventDefinedInlineNullOptionalValue', - 'optional': true, - 'bubblingType': 'direct', - 'typeAnnotation': { - 'type': 'EventTypeAnnotation', - 'argument': { - 'type': 'ObjectTypeAnnotation', - 'properties': [] - } - } - }, - { - 'name': 'onDirectEventDefinedInlineNullOptionalBoth', - 'optional': true, - 'bubblingType': 'direct', - 'typeAnnotation': { - 'type': 'EventTypeAnnotation', - 'argument': { - 'type': 'ObjectTypeAnnotation', - 'properties': [] - } - } - }, - { - 'name': 'onDirectEventDefinedInlineNullWithPaperName', - 'optional': true, - 'bubblingType': 'direct', - 'paperTopLevelNameDeprecated': 'paperDirectEventDefinedInlineNullWithPaperName', - 'typeAnnotation': { - 'type': 'EventTypeAnnotation', - 'argument': { - 'type': 'ObjectTypeAnnotation', - 'properties': [] - } - } - }, - { - 'name': 'onBubblingEventDefinedInlineNull', - 'optional': false, - 'bubblingType': 'bubble', - 'typeAnnotation': { - 'type': 'EventTypeAnnotation', - 'argument': { - 'type': 'ObjectTypeAnnotation', - 'properties': [] - } - } - }, - { - 'name': 'onBubblingEventDefinedInlineNullOptionalKey', - 'optional': true, - 'bubblingType': 'bubble', - 'typeAnnotation': { - 'type': 'EventTypeAnnotation', - 'argument': { - 'type': 'ObjectTypeAnnotation', - 'properties': [] - } - } - }, - { - 'name': 'onBubblingEventDefinedInlineNullOptionalValue', - 'optional': true, - 'bubblingType': 'bubble', - 'typeAnnotation': { - 'type': 'EventTypeAnnotation', - 'argument': { - 'type': 'ObjectTypeAnnotation', - 'properties': [] - } - } - }, - { - 'name': 'onBubblingEventDefinedInlineNullOptionalBoth', - 'optional': true, - 'bubblingType': 'bubble', - 'typeAnnotation': { - 'type': 'EventTypeAnnotation', - 'argument': { - 'type': 'ObjectTypeAnnotation', - 'properties': [] - } - } - }, - { - 'name': 'onBubblingEventDefinedInlineNullWithPaperName', - 'optional': true, - 'bubblingType': 'bubble', - 'paperTopLevelNameDeprecated': 'paperBubblingEventDefinedInlineNullWithPaperName', - 'typeAnnotation': { - 'type': 'EventTypeAnnotation', - 'argument': { - 'type': 'ObjectTypeAnnotation', - 'properties': [] - } - } - } - ], - 'props': [], - 'commands': [] - } - } - } - } -}" -`; - -exports[`RN Codegen TypeScript Parser can generate fixture EVENTS_DEFINED_INLINE_WITH_ALL_TYPES 1`] = ` -"{ - 'modules': { - 'Module': { - 'type': 'Component', - 'components': { - 'Module': { - 'extendsProps': [ - { - 'type': 'ReactNativeBuiltInType', - 'knownTypeName': 'ReactNativeCoreViewProps' - } - ], - 'events': [ - { - 'name': 'onDirectEventDefinedInline', - 'optional': false, - 'bubblingType': 'direct', + 'bubblingType': 'direct', 'typeAnnotation': { 'type': 'EventTypeAnnotation', 'argument': { @@ -4309,383 +4073,389 @@ exports[`RN Codegen TypeScript Parser can generate fixture EVENTS_DEFINED_INLINE } ] } - } - ] - } - } - }, - { - 'name': 'onDirectEventDefinedInlineOptionalKey', - 'optional': true, - 'bubblingType': 'direct', - 'typeAnnotation': { - 'type': 'EventTypeAnnotation', - 'argument': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ + }, { - 'name': 'boolean_required', + 'name': 'boolean_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'boolean_optional_key', + 'name': 'boolean_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'boolean_optional_value', + 'name': 'boolean_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'boolean_optional_both', + 'name': 'boolean_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'string_required', + 'name': 'string_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'string_optional_key', + 'name': 'string_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'string_optional_value', + 'name': 'string_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'string_optional_both', + 'name': 'string_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'double_required', + 'name': 'double_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } } }, { - 'name': 'double_optional_key', + 'name': 'double_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } } }, { - 'name': 'double_optional_value', + 'name': 'double_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } } }, { - 'name': 'double_optional_both', + 'name': 'double_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } } }, { - 'name': 'float_required', + 'name': 'float_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'float_optional_key', + 'name': 'float_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'float_optional_value', + 'name': 'float_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'float_optional_both', + 'name': 'float_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'int32_required', + 'name': 'int32_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'int32_optional_key', + 'name': 'int32_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'int32_optional_value', + 'name': 'int32_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'int32_optional_both', + 'name': 'int32_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'enum_required', + 'name': 'enum_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } } }, { - 'name': 'enum_optional_key', + 'name': 'enum_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } } }, { - 'name': 'enum_optional_value', + 'name': 'enum_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } } }, { - 'name': 'enum_optional_both', + 'name': 'enum_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } } }, { - 'name': 'object_required', + 'name': 'object_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'boolean_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_optional_key', + 'name': 'object_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'string_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_optional_value', + 'name': 'object_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'float_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_optional_both', + 'name': 'object_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'int32_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } - } - ] - } - }, - { - 'name': 'object_required_nested_2_layers', - 'optional': false, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'object_optional_nested_1_layer', - 'optional': true, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'boolean_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } - }, - { - 'name': 'string_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation' - } - }, - { - 'name': 'double_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' - } - }, - { - 'name': 'float_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' - } - }, - { - 'name': 'int32_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } - } - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_readonly_required', + 'name': 'int32_array_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'boolean_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] + } } }, { - 'name': 'object_readonly_optional_key', + 'name': 'int32_array_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'string_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] + } } }, { - 'name': 'object_readonly_optional_value', + 'name': 'int32_array_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'float_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] + } } }, { - 'name': 'object_readonly_optional_both', + 'name': 'int32_array_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'int32_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] + } } } ] @@ -4693,9 +4463,10 @@ exports[`RN Codegen TypeScript Parser can generate fixture EVENTS_DEFINED_INLINE } }, { - 'name': 'onDirectEventDefinedInlineOptionalValue', - 'optional': true, + 'name': 'onDirectEventDefinedInlineWithPaperName', + 'optional': false, 'bubblingType': 'direct', + 'paperTopLevelNameDeprecated': 'paperDirectEventDefinedInlineWithPaperName', 'typeAnnotation': { 'type': 'EventTypeAnnotation', 'argument': { @@ -5065,447 +4836,699 @@ exports[`RN Codegen TypeScript Parser can generate fixture EVENTS_DEFINED_INLINE } ] } - } - ] - } - } - }, - { - 'name': 'onDirectEventDefinedInlineOptionalBoth', - 'optional': true, - 'bubblingType': 'direct', - 'typeAnnotation': { - 'type': 'EventTypeAnnotation', - 'argument': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ + }, { - 'name': 'boolean_required', + 'name': 'boolean_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'boolean_optional_key', + 'name': 'boolean_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'boolean_optional_value', + 'name': 'boolean_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'boolean_optional_both', + 'name': 'boolean_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'string_required', + 'name': 'string_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'string_optional_key', + 'name': 'string_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'string_optional_value', + 'name': 'string_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'string_optional_both', + 'name': 'string_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'double_required', + 'name': 'double_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } } }, { - 'name': 'double_optional_key', + 'name': 'double_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } } }, { - 'name': 'double_optional_value', + 'name': 'double_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } } }, { - 'name': 'double_optional_both', + 'name': 'double_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } } }, { - 'name': 'float_required', + 'name': 'float_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'float_optional_key', + 'name': 'float_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'float_optional_value', + 'name': 'float_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'float_optional_both', + 'name': 'float_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'int32_required', + 'name': 'int32_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'int32_optional_key', + 'name': 'int32_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'int32_optional_value', + 'name': 'int32_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'int32_optional_both', + 'name': 'int32_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'enum_required', + 'name': 'enum_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } } }, { - 'name': 'enum_optional_key', + 'name': 'enum_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } } }, { - 'name': 'enum_optional_value', + 'name': 'enum_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } } }, { - 'name': 'enum_optional_both', + 'name': 'enum_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } } }, { - 'name': 'object_required', + 'name': 'object_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'boolean_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_optional_key', + 'name': 'object_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'string_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_optional_value', + 'name': 'object_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'float_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_optional_both', + 'name': 'object_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'int32_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_required_nested_2_layers', + 'name': 'int32_array_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'object_optional_nested_1_layer', - 'optional': true, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'boolean_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } - }, - { - 'name': 'string_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation' - } - }, - { - 'name': 'double_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' - } - }, - { - 'name': 'float_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' - } - }, - { - 'name': 'int32_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } - } - ] - } - } - ] - } - }, - { - 'name': 'object_readonly_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'boolean_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] + } } }, { - 'name': 'object_readonly_optional_key', + 'name': 'int32_array_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'string_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] + } } }, { - 'name': 'object_readonly_optional_value', + 'name': 'int32_array_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'float_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] + } } }, { - 'name': 'object_readonly_optional_both', + 'name': 'int32_array_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'int32_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] + } } } ] } } + } + ], + 'props': [], + 'commands': [ + { + 'name': 'scrollTo', + 'optional': false, + 'typeAnnotation': { + 'type': 'FunctionTypeAnnotation', + 'params': [ + { + 'name': 'y', + 'optional': false, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'animated', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ], + 'returnTypeAnnotation': { + 'type': 'VoidTypeAnnotation' + } + } + } + ] + } + } + } + } +}" +`; + +exports[`RN Codegen TypeScript Parser can generate fixture COMMANDS_WITH_EXTERNAL_TYPES 1`] = ` +"{ + 'modules': { + 'Module': { + 'type': 'Component', + 'components': { + 'Module': { + 'extendsProps': [ + { + 'type': 'ReactNativeBuiltInType', + 'knownTypeName': 'ReactNativeCoreViewProps' + } + ], + 'events': [], + 'props': [], + 'commands': [ + { + 'name': 'scrollTo', + 'optional': false, + 'typeAnnotation': { + 'type': 'FunctionTypeAnnotation', + 'params': [ + { + 'name': 'y', + 'optional': false, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'animated', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ], + 'returnTypeAnnotation': { + 'type': 'VoidTypeAnnotation' + } + } + } + ] + } + } + } + } +}" +`; + +exports[`RN Codegen TypeScript Parser can generate fixture EVENTS_DEFINED_AS_NULL_INLINE 1`] = ` +"{ + 'modules': { + 'Module': { + 'type': 'Component', + 'components': { + 'Module': { + 'extendsProps': [ + { + 'type': 'ReactNativeBuiltInType', + 'knownTypeName': 'ReactNativeCoreViewProps' + } + ], + 'events': [ + { + 'name': 'onDirectEventDefinedInlineNull', + 'optional': false, + 'bubblingType': 'direct', + 'typeAnnotation': { + 'type': 'EventTypeAnnotation', + 'argument': { + 'type': 'ObjectTypeAnnotation', + 'properties': [] + } + } }, { - 'name': 'onDirectEventDefinedInlineWithPaperName', + 'name': 'onDirectEventDefinedInlineNullOptionalKey', 'optional': true, 'bubblingType': 'direct', - 'paperTopLevelNameDeprecated': 'paperDirectEventDefinedInlineWithPaperName', 'typeAnnotation': { 'type': 'EventTypeAnnotation', 'argument': { 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'boolean_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' - } - }, - { - 'name': 'boolean_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' - } - }, - { - 'name': 'boolean_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' - } - }, - { - 'name': 'boolean_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' - } - }, - { - 'name': 'string_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation' - } - }, - { - 'name': 'string_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation' - } - }, - { - 'name': 'string_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation' - } + 'properties': [] + } + } + }, + { + 'name': 'onDirectEventDefinedInlineNullOptionalValue', + 'optional': true, + 'bubblingType': 'direct', + 'typeAnnotation': { + 'type': 'EventTypeAnnotation', + 'argument': { + 'type': 'ObjectTypeAnnotation', + 'properties': [] + } + } + }, + { + 'name': 'onDirectEventDefinedInlineNullOptionalBoth', + 'optional': true, + 'bubblingType': 'direct', + 'typeAnnotation': { + 'type': 'EventTypeAnnotation', + 'argument': { + 'type': 'ObjectTypeAnnotation', + 'properties': [] + } + } + }, + { + 'name': 'onDirectEventDefinedInlineNullWithPaperName', + 'optional': true, + 'bubblingType': 'direct', + 'paperTopLevelNameDeprecated': 'paperDirectEventDefinedInlineNullWithPaperName', + 'typeAnnotation': { + 'type': 'EventTypeAnnotation', + 'argument': { + 'type': 'ObjectTypeAnnotation', + 'properties': [] + } + } + }, + { + 'name': 'onBubblingEventDefinedInlineNull', + 'optional': false, + 'bubblingType': 'bubble', + 'typeAnnotation': { + 'type': 'EventTypeAnnotation', + 'argument': { + 'type': 'ObjectTypeAnnotation', + 'properties': [] + } + } + }, + { + 'name': 'onBubblingEventDefinedInlineNullOptionalKey', + 'optional': true, + 'bubblingType': 'bubble', + 'typeAnnotation': { + 'type': 'EventTypeAnnotation', + 'argument': { + 'type': 'ObjectTypeAnnotation', + 'properties': [] + } + } + }, + { + 'name': 'onBubblingEventDefinedInlineNullOptionalValue', + 'optional': true, + 'bubblingType': 'bubble', + 'typeAnnotation': { + 'type': 'EventTypeAnnotation', + 'argument': { + 'type': 'ObjectTypeAnnotation', + 'properties': [] + } + } + }, + { + 'name': 'onBubblingEventDefinedInlineNullOptionalBoth', + 'optional': true, + 'bubblingType': 'bubble', + 'typeAnnotation': { + 'type': 'EventTypeAnnotation', + 'argument': { + 'type': 'ObjectTypeAnnotation', + 'properties': [] + } + } + }, + { + 'name': 'onBubblingEventDefinedInlineNullWithPaperName', + 'optional': true, + 'bubblingType': 'bubble', + 'paperTopLevelNameDeprecated': 'paperBubblingEventDefinedInlineNullWithPaperName', + 'typeAnnotation': { + 'type': 'EventTypeAnnotation', + 'argument': { + 'type': 'ObjectTypeAnnotation', + 'properties': [] + } + } + } + ], + 'props': [], + 'commands': [] + } + } + } + } +}" +`; + +exports[`RN Codegen TypeScript Parser can generate fixture EVENTS_DEFINED_INLINE_WITH_ALL_TYPES 1`] = ` +"{ + 'modules': { + 'Module': { + 'type': 'Component', + 'components': { + 'Module': { + 'extendsProps': [ + { + 'type': 'ReactNativeBuiltInType', + 'knownTypeName': 'ReactNativeCoreViewProps' + } + ], + 'events': [ + { + 'name': 'onDirectEventDefinedInline', + 'optional': false, + 'bubblingType': 'direct', + 'typeAnnotation': { + 'type': 'EventTypeAnnotation', + 'argument': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'boolean_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'boolean_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'boolean_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'string_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'string_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } }, { 'name': 'string_optional_both', @@ -5822,383 +5845,389 @@ exports[`RN Codegen TypeScript Parser can generate fixture EVENTS_DEFINED_INLINE } ] } - } - ] - } - } - }, - { - 'name': 'onBubblingEventDefinedInline', - 'optional': false, - 'bubblingType': 'bubble', - 'typeAnnotation': { - 'type': 'EventTypeAnnotation', - 'argument': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ + }, { - 'name': 'boolean_required', + 'name': 'boolean_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'boolean_optional_key', + 'name': 'boolean_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'boolean_optional_value', + 'name': 'boolean_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'boolean_optional_both', + 'name': 'boolean_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'string_required', + 'name': 'string_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'string_optional_key', + 'name': 'string_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'string_optional_value', + 'name': 'string_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'string_optional_both', + 'name': 'string_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'double_required', + 'name': 'double_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } } }, { - 'name': 'double_optional_key', + 'name': 'double_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } } }, { - 'name': 'double_optional_value', + 'name': 'double_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } } }, { - 'name': 'double_optional_both', + 'name': 'double_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } }, { - 'name': 'float_required', + 'name': 'float_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'float_optional_key', + 'name': 'float_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'float_optional_value', + 'name': 'float_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'float_optional_both', + 'name': 'float_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'int32_required', + 'name': 'int32_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'int32_optional_key', + 'name': 'int32_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'int32_optional_value', + 'name': 'int32_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'int32_optional_both', + 'name': 'int32_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'enum_required', + 'name': 'enum_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } } }, { - 'name': 'enum_optional_key', + 'name': 'enum_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } } }, { - 'name': 'enum_optional_value', + 'name': 'enum_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } } }, { - 'name': 'enum_optional_both', + 'name': 'enum_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } } }, { - 'name': 'object_required', + 'name': 'object_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'boolean_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_optional_key', + 'name': 'object_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'string_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_optional_value', + 'name': 'object_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'float_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_optional_both', + 'name': 'object_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'int32_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_required_nested_2_layers', + 'name': 'int32_array_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'object_optional_nested_1_layer', - 'optional': true, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'boolean_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } - }, - { - 'name': 'string_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation' - } - }, - { - 'name': 'double_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' - } - }, - { - 'name': 'float_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' - } - }, - { - 'name': 'int32_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } - } - ] - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] + } } }, { - 'name': 'object_readonly_required', - 'optional': false, + 'name': 'int32_array_array_optional_key', + 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'boolean_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] + } } }, { - 'name': 'object_readonly_optional_key', + 'name': 'int32_array_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'string_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] + } } }, { - 'name': 'object_readonly_optional_value', + 'name': 'int32_array_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'float_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] - } - }, - { - 'name': 'object_readonly_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'int32_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } - } - ] + } } } ] @@ -6206,9 +6235,9 @@ exports[`RN Codegen TypeScript Parser can generate fixture EVENTS_DEFINED_INLINE } }, { - 'name': 'onBubblingEventDefinedInlineOptionalKey', + 'name': 'onDirectEventDefinedInlineOptionalKey', 'optional': true, - 'bubblingType': 'bubble', + 'bubblingType': 'direct', 'typeAnnotation': { 'type': 'EventTypeAnnotation', 'argument': { @@ -6578,383 +6607,389 @@ exports[`RN Codegen TypeScript Parser can generate fixture EVENTS_DEFINED_INLINE } ] } - } - ] - } - } - }, - { - 'name': 'onBubblingEventDefinedInlineOptionalValue', - 'optional': true, - 'bubblingType': 'bubble', - 'typeAnnotation': { - 'type': 'EventTypeAnnotation', - 'argument': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ + }, { - 'name': 'boolean_required', + 'name': 'boolean_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'boolean_optional_key', + 'name': 'boolean_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'boolean_optional_value', + 'name': 'boolean_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'boolean_optional_both', + 'name': 'boolean_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'string_required', + 'name': 'string_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'string_optional_key', + 'name': 'string_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'string_optional_value', + 'name': 'string_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'string_optional_both', + 'name': 'string_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'double_required', + 'name': 'double_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } } }, { - 'name': 'double_optional_key', + 'name': 'double_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } } }, { - 'name': 'double_optional_value', + 'name': 'double_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } } }, { - 'name': 'double_optional_both', + 'name': 'double_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } } }, { - 'name': 'float_required', + 'name': 'float_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'float_optional_key', + 'name': 'float_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'float_optional_value', + 'name': 'float_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'float_optional_both', + 'name': 'float_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'int32_required', + 'name': 'int32_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'int32_optional_key', + 'name': 'int32_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'int32_optional_value', + 'name': 'int32_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'int32_optional_both', + 'name': 'int32_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'enum_required', + 'name': 'enum_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } } }, { - 'name': 'enum_optional_key', + 'name': 'enum_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } } }, { - 'name': 'enum_optional_value', + 'name': 'enum_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } } }, { - 'name': 'enum_optional_both', + 'name': 'enum_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } } }, { - 'name': 'object_required', + 'name': 'object_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'boolean_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_optional_key', + 'name': 'object_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'string_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_optional_value', + 'name': 'object_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'float_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_optional_both', + 'name': 'object_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'int32_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_required_nested_2_layers', + 'name': 'int32_array_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'object_optional_nested_1_layer', - 'optional': true, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'boolean_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } - }, - { - 'name': 'string_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation' - } - }, - { - 'name': 'double_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' - } - }, - { - 'name': 'float_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' - } - }, - { - 'name': 'int32_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } - } - ] - } - } - ] - } - }, - { - 'name': 'object_readonly_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'boolean_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] + } } }, { - 'name': 'object_readonly_optional_key', + 'name': 'int32_array_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'string_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] + } } }, { - 'name': 'object_readonly_optional_value', + 'name': 'int32_array_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'float_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] + } } }, { - 'name': 'object_readonly_optional_both', + 'name': 'int32_array_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'int32_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] + } } } ] @@ -6962,9 +6997,9 @@ exports[`RN Codegen TypeScript Parser can generate fixture EVENTS_DEFINED_INLINE } }, { - 'name': 'onBubblingEventDefinedInlineOptionalBoth', + 'name': 'onDirectEventDefinedInlineOptionalValue', 'optional': true, - 'bubblingType': 'bubble', + 'bubblingType': 'direct', 'typeAnnotation': { 'type': 'EventTypeAnnotation', 'argument': { @@ -7334,720 +7369,6231 @@ exports[`RN Codegen TypeScript Parser can generate fixture EVENTS_DEFINED_INLINE } ] } - } - ] - } - } - }, - { - 'name': 'onBubblingEventDefinedInlineWithPaperName', - 'optional': true, - 'bubblingType': 'bubble', - 'paperTopLevelNameDeprecated': 'paperBubblingEventDefinedInlineWithPaperName', - 'typeAnnotation': { - 'type': 'EventTypeAnnotation', - 'argument': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ + }, { - 'name': 'boolean_required', + 'name': 'boolean_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'boolean_optional_key', + 'name': 'boolean_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'boolean_optional_value', + 'name': 'boolean_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'boolean_optional_both', + 'name': 'boolean_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'string_required', + 'name': 'string_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'string_optional_key', + 'name': 'string_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'string_optional_value', + 'name': 'string_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'string_optional_both', + 'name': 'string_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'double_required', + 'name': 'double_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } } }, { - 'name': 'double_optional_key', + 'name': 'double_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } } }, { - 'name': 'double_optional_value', + 'name': 'double_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } } }, { - 'name': 'double_optional_both', + 'name': 'double_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } } }, { - 'name': 'float_required', + 'name': 'float_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'float_optional_key', + 'name': 'float_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'float_optional_value', + 'name': 'float_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'float_optional_both', + 'name': 'float_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'int32_required', + 'name': 'int32_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'int32_optional_key', + 'name': 'int32_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'int32_optional_value', + 'name': 'int32_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'int32_optional_both', + 'name': 'int32_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'enum_required', + 'name': 'enum_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } } }, { - 'name': 'enum_optional_key', + 'name': 'enum_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } } }, { - 'name': 'enum_optional_value', + 'name': 'enum_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } } }, { - 'name': 'enum_optional_both', + 'name': 'enum_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } } }, { - 'name': 'object_required', + 'name': 'object_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'boolean_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_optional_key', + 'name': 'object_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'string_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_optional_value', + 'name': 'object_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'float_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_optional_both', + 'name': 'object_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'int32_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } - } - ] - } - }, - { - 'name': 'object_required_nested_2_layers', - 'optional': false, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'object_optional_nested_1_layer', - 'optional': true, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'boolean_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } - }, - { - 'name': 'string_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation' - } - }, - { - 'name': 'double_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' - } - }, - { - 'name': 'float_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' - } - }, - { - 'name': 'int32_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } - } - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_readonly_required', + 'name': 'int32_array_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'boolean_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] + } } }, { - 'name': 'object_readonly_optional_key', + 'name': 'int32_array_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'string_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] + } } }, { - 'name': 'object_readonly_optional_value', + 'name': 'int32_array_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'float_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] + } } }, { - 'name': 'object_readonly_optional_both', + 'name': 'int32_array_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'int32_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] + } } } ] } } - } - ], - 'props': [], - 'commands': [] - } - } - } - } -}" -`; - -exports[`RN Codegen TypeScript Parser can generate fixture NO_PROPS_EVENTS_ONLY_DEPRECATED_VIEW_CONFIG_NAME_OPTION 1`] = ` -"{ - 'modules': { - 'Module': { - 'type': 'Component', - 'components': { - 'Module': { - 'deprecatedViewConfigName': 'DeprecateModuleName', - 'extendsProps': [ - { - 'type': 'ReactNativeBuiltInType', - 'knownTypeName': 'ReactNativeCoreViewProps' - } - ], - 'events': [], - 'props': [], - 'commands': [] - } - } - } - } -}" -`; - -exports[`RN Codegen TypeScript Parser can generate fixture OBJECT_PROP_TYPES_NO_EVENTS 1`] = ` -"{ - 'modules': { - 'Module': { - 'type': 'Component', - 'components': { - 'Module': { - 'extendsProps': [ - { - 'type': 'ReactNativeBuiltInType', - 'knownTypeName': 'ReactNativeCoreViewProps' - } - ], - 'events': [], - 'props': [ + }, { - 'name': 'boolean_required', - 'optional': false, + 'name': 'onDirectEventDefinedInlineOptionalBoth', + 'optional': true, + 'bubblingType': 'direct', 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'prop', - 'optional': false, - 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation', - 'default': false - } - } - ] - } - }, - { - 'name': 'boolean_optional', - 'optional': false, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'prop', - 'optional': true, - 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation', - 'default': false - } - } - ] - } - }, - { - 'name': 'string_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'prop', - 'optional': false, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation', - 'default': null - } - } - ] - } - }, - { - 'name': 'string_optional', - 'optional': false, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'prop', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation', - 'default': '' - } - } - ] - } - }, - { - 'name': 'double_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'prop', - 'optional': false, - 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation', - 'default': 0 - } - } - ] - } - }, - { - 'name': 'double_optional', - 'optional': false, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'prop', - 'optional': true, - 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation', - 'default': 0 - } - } - ] - } - }, - { - 'name': 'float_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'prop', - 'optional': false, - 'typeAnnotation': { - 'type': 'FloatTypeAnnotation', - 'default': 0 - } - } - ] - } - }, - { - 'name': 'float_optional', - 'optional': false, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'prop', - 'optional': true, - 'typeAnnotation': { - 'type': 'FloatTypeAnnotation', - 'default': 0 - } - } - ] - } - }, - { - 'name': 'int_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'prop', - 'optional': false, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation', - 'default': 0 - } - } - ] - } - }, - { - 'name': 'int_optional', - 'optional': false, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'prop', - 'optional': true, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation', - 'default': 0 - } - } - ] - } - }, - { - 'name': 'enum_optional', - 'optional': false, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'prop', - 'optional': true, - 'typeAnnotation': { - 'type': 'ArrayTypeAnnotation', - 'elementType': { - 'type': 'StringEnumTypeAnnotation', - 'default': 'small', - 'options': [ - 'small', - 'large' - ] + 'type': 'EventTypeAnnotation', + 'argument': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' } - } - } - ] - } - }, - { - 'name': 'image_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'prop', - 'optional': false, - 'typeAnnotation': { - 'type': 'ReservedPropTypeAnnotation', - 'name': 'ImageSourcePrimitive' - } - } - ] - } - }, - { - 'name': 'image_optional_key', - 'optional': false, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'prop', - 'optional': true, - 'typeAnnotation': { - 'type': 'ReservedPropTypeAnnotation', - 'name': 'ImageSourcePrimitive' - } - } - ] - } - }, - { - 'name': 'image_optional_value', - 'optional': false, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'prop', - 'optional': true, - 'typeAnnotation': { - 'type': 'ReservedPropTypeAnnotation', - 'name': 'ImageSourcePrimitive' - } - } - ] - } - }, - { - 'name': 'image_optional_both', - 'optional': false, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'prop', - 'optional': true, - 'typeAnnotation': { - 'type': 'ReservedPropTypeAnnotation', - 'name': 'ImageSourcePrimitive' - } - } - ] + }, + { + 'name': 'boolean_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'boolean_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'boolean_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'string_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'string_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'string_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'double_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'double_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'double_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'double_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'float_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'float_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'float_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'int32_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'int32_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'int32_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'enum_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'enum_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'enum_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'enum_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'object_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_required_nested_2_layers', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'object_optional_nested_1_layer', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'double_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + } + ] + } + }, + { + 'name': 'object_readonly_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_readonly_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_readonly_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_readonly_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + }, + { + 'name': 'boolean_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'boolean_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'boolean_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'boolean_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'string_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'string_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'string_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'string_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'double_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'double_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'double_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'double_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'float_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'float_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'float_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'float_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'int32_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'int32_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'int32_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'int32_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'enum_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'enum_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'enum_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'enum_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'object_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ] + } + } + }, + { + 'name': 'object_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + } + ] + } + } + }, + { + 'name': 'object_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + } + ] + } + } + }, + { + 'name': 'object_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + } + }, + { + 'name': 'int32_array_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + } + }, + { + 'name': 'int32_array_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + } + }, + { + 'name': 'int32_array_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + } + }, + { + 'name': 'int32_array_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + } + } + ] + } + } + }, + { + 'name': 'onDirectEventDefinedInlineWithPaperName', + 'optional': true, + 'bubblingType': 'direct', + 'paperTopLevelNameDeprecated': 'paperDirectEventDefinedInlineWithPaperName', + 'typeAnnotation': { + 'type': 'EventTypeAnnotation', + 'argument': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'boolean_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'boolean_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'boolean_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'string_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'string_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'string_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'double_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'double_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'double_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'double_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'float_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'float_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'float_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'int32_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'int32_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'int32_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'enum_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'enum_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'enum_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'enum_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'object_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_required_nested_2_layers', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'object_optional_nested_1_layer', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'double_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + } + ] + } + }, + { + 'name': 'object_readonly_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_readonly_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_readonly_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_readonly_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + }, + { + 'name': 'boolean_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'boolean_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'boolean_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'boolean_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'string_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'string_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'string_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'string_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'double_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'double_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'double_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'double_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'float_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'float_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'float_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'float_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'int32_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'int32_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'int32_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'int32_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'enum_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'enum_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'enum_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'enum_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'object_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ] + } + } + }, + { + 'name': 'object_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + } + ] + } + } + }, + { + 'name': 'object_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + } + ] + } + } + }, + { + 'name': 'object_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + } + }, + { + 'name': 'int32_array_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + } + }, + { + 'name': 'int32_array_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + } + }, + { + 'name': 'int32_array_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + } + }, + { + 'name': 'int32_array_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + } + } + ] + } + } + }, + { + 'name': 'onBubblingEventDefinedInline', + 'optional': false, + 'bubblingType': 'bubble', + 'typeAnnotation': { + 'type': 'EventTypeAnnotation', + 'argument': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'boolean_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'boolean_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'boolean_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'string_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'string_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'string_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'double_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'double_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'double_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'double_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'float_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'float_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'float_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'int32_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'int32_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'int32_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'enum_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'enum_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'enum_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'enum_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'object_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_required_nested_2_layers', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'object_optional_nested_1_layer', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'double_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + } + ] + } + }, + { + 'name': 'object_readonly_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_readonly_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_readonly_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_readonly_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + }, + { + 'name': 'boolean_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'boolean_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'boolean_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'boolean_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'string_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'string_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'string_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'string_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'double_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'double_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'double_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'double_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'float_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'float_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'float_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'float_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'int32_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'int32_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'int32_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'int32_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'enum_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'enum_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'enum_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'enum_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'object_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ] + } + } + }, + { + 'name': 'object_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + } + ] + } + } + }, + { + 'name': 'object_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + } + ] + } + } + }, + { + 'name': 'object_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + } + }, + { + 'name': 'int32_array_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + } + }, + { + 'name': 'int32_array_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + } + }, + { + 'name': 'int32_array_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + } + }, + { + 'name': 'int32_array_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + } + } + ] + } + } + }, + { + 'name': 'onBubblingEventDefinedInlineOptionalKey', + 'optional': true, + 'bubblingType': 'bubble', + 'typeAnnotation': { + 'type': 'EventTypeAnnotation', + 'argument': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'boolean_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'boolean_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'boolean_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'string_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'string_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'string_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'double_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'double_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'double_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'double_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'float_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'float_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'float_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'int32_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'int32_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'int32_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'enum_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'enum_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'enum_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'enum_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'object_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_required_nested_2_layers', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'object_optional_nested_1_layer', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'double_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + } + ] + } + }, + { + 'name': 'object_readonly_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_readonly_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_readonly_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_readonly_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + }, + { + 'name': 'boolean_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'boolean_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'boolean_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'boolean_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'string_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'string_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'string_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'string_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'double_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'double_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'double_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'double_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'float_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'float_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'float_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'float_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'int32_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'int32_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'int32_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'int32_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'enum_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'enum_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'enum_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'enum_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'object_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ] + } + } + }, + { + 'name': 'object_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + } + ] + } + } + }, + { + 'name': 'object_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + } + ] + } + } + }, + { + 'name': 'object_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + } + }, + { + 'name': 'int32_array_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + } + }, + { + 'name': 'int32_array_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + } + }, + { + 'name': 'int32_array_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + } + }, + { + 'name': 'int32_array_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + } + } + ] + } + } + }, + { + 'name': 'onBubblingEventDefinedInlineOptionalValue', + 'optional': true, + 'bubblingType': 'bubble', + 'typeAnnotation': { + 'type': 'EventTypeAnnotation', + 'argument': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'boolean_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'boolean_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'boolean_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'string_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'string_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'string_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'double_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'double_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'double_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'double_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'float_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'float_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'float_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'int32_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'int32_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'int32_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'enum_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'enum_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'enum_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'enum_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'object_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_required_nested_2_layers', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'object_optional_nested_1_layer', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'double_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + } + ] + } + }, + { + 'name': 'object_readonly_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_readonly_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_readonly_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_readonly_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + }, + { + 'name': 'boolean_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'boolean_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'boolean_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'boolean_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'string_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'string_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'string_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'string_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'double_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'double_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'double_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'double_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'float_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'float_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'float_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'float_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'int32_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'int32_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'int32_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'int32_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'enum_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'enum_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'enum_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'enum_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'object_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ] + } + } + }, + { + 'name': 'object_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + } + ] + } + } + }, + { + 'name': 'object_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + } + ] + } + } + }, + { + 'name': 'object_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + } + }, + { + 'name': 'int32_array_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + } + }, + { + 'name': 'int32_array_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + } + }, + { + 'name': 'int32_array_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + } + }, + { + 'name': 'int32_array_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + } + } + ] + } + } + }, + { + 'name': 'onBubblingEventDefinedInlineOptionalBoth', + 'optional': true, + 'bubblingType': 'bubble', + 'typeAnnotation': { + 'type': 'EventTypeAnnotation', + 'argument': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'boolean_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'boolean_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'boolean_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'string_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'string_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'string_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'double_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'double_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'double_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'double_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'float_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'float_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'float_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'int32_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'int32_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'int32_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'enum_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'enum_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'enum_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'enum_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'object_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_required_nested_2_layers', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'object_optional_nested_1_layer', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'double_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + } + ] + } + }, + { + 'name': 'object_readonly_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_readonly_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_readonly_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_readonly_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + }, + { + 'name': 'boolean_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'boolean_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'boolean_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'boolean_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'string_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'string_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'string_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'string_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'double_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'double_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'double_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'double_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'float_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'float_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'float_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'float_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'int32_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'int32_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'int32_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'int32_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'enum_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'enum_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'enum_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'enum_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'object_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ] + } + } + }, + { + 'name': 'object_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + } + ] + } + } + }, + { + 'name': 'object_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + } + ] + } + } + }, + { + 'name': 'object_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + } + }, + { + 'name': 'int32_array_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + } + }, + { + 'name': 'int32_array_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + } + }, + { + 'name': 'int32_array_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + } + }, + { + 'name': 'int32_array_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + } + } + ] + } + } + }, + { + 'name': 'onBubblingEventDefinedInlineWithPaperName', + 'optional': true, + 'bubblingType': 'bubble', + 'paperTopLevelNameDeprecated': 'paperBubblingEventDefinedInlineWithPaperName', + 'typeAnnotation': { + 'type': 'EventTypeAnnotation', + 'argument': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'boolean_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'boolean_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'boolean_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'string_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'string_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'string_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'double_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'double_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'double_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'double_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'float_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'float_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'float_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'int32_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'int32_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'int32_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'enum_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'enum_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'enum_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'enum_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'object_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_required_nested_2_layers', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'object_optional_nested_1_layer', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'double_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + } + ] + } + }, + { + 'name': 'object_readonly_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_readonly_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_readonly_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_readonly_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + }, + { + 'name': 'boolean_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'boolean_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'boolean_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'boolean_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'string_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'string_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'string_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'string_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'double_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'double_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'double_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'double_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'float_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'float_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'float_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'float_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'int32_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'int32_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'int32_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'int32_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'enum_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'enum_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'enum_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'enum_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'object_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ] + } + } + }, + { + 'name': 'object_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + } + ] + } + } + }, + { + 'name': 'object_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + } + ] + } + } + }, + { + 'name': 'object_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + } + }, + { + 'name': 'int32_array_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + } + }, + { + 'name': 'int32_array_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + } + }, + { + 'name': 'int32_array_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + } + }, + { + 'name': 'int32_array_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + } + } + ] + } + } + } + ], + 'props': [], + 'commands': [] + } + } + } + } +}" +`; + +exports[`RN Codegen TypeScript Parser can generate fixture NO_PROPS_EVENTS_ONLY_DEPRECATED_VIEW_CONFIG_NAME_OPTION 1`] = ` +"{ + 'modules': { + 'Module': { + 'type': 'Component', + 'components': { + 'Module': { + 'deprecatedViewConfigName': 'DeprecateModuleName', + 'extendsProps': [ + { + 'type': 'ReactNativeBuiltInType', + 'knownTypeName': 'ReactNativeCoreViewProps' + } + ], + 'events': [], + 'props': [], + 'commands': [] + } + } + } + } +}" +`; + +exports[`RN Codegen TypeScript Parser can generate fixture OBJECT_PROP_TYPES_NO_EVENTS 1`] = ` +"{ + 'modules': { + 'Module': { + 'type': 'Component', + 'components': { + 'Module': { + 'extendsProps': [ + { + 'type': 'ReactNativeBuiltInType', + 'knownTypeName': 'ReactNativeCoreViewProps' + } + ], + 'events': [], + 'props': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation', + 'default': false + } + } + ] + } + }, + { + 'name': 'boolean_optional', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation', + 'default': false + } + } + ] + } + }, + { + 'name': 'string_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation', + 'default': null + } + } + ] + } + }, + { + 'name': 'string_optional', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation', + 'default': '' + } + } + ] + } + }, + { + 'name': 'double_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': false, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation', + 'default': 0 + } + } + ] + } + }, + { + 'name': 'double_optional', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation', + 'default': 0 + } + } + ] + } + }, + { + 'name': 'float_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': false, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation', + 'default': 0 + } + } + ] + } + }, + { + 'name': 'float_optional', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation', + 'default': 0 + } + } + ] + } + }, + { + 'name': 'int_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': false, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation', + 'default': 0 + } + } + ] + } + }, + { + 'name': 'int_optional', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation', + 'default': 0 + } + } + ] + } + }, + { + 'name': 'enum_optional', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'default': 'small', + 'options': [ + 'small', + 'large' + ] + } + } + } + ] + } + }, + { + 'name': 'image_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': false, + 'typeAnnotation': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ImageSourcePrimitive' + } + } + ] + } + }, + { + 'name': 'image_optional_key', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': true, + 'typeAnnotation': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ImageSourcePrimitive' + } + } + ] + } + }, + { + 'name': 'image_optional_value', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': true, + 'typeAnnotation': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ImageSourcePrimitive' + } + } + ] + } + }, + { + 'name': 'image_optional_both', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': true, + 'typeAnnotation': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ImageSourcePrimitive' + } + } + ] + } + }, + { + 'name': 'color_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': false, + 'typeAnnotation': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ColorPrimitive' + } + } + ] + } + }, + { + 'name': 'color_optional_key', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': true, + 'typeAnnotation': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ColorPrimitive' + } + } + ] + } + }, + { + 'name': 'color_optional_value', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': true, + 'typeAnnotation': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ColorPrimitive' + } + } + ] + } + }, + { + 'name': 'color_optional_both', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': true, + 'typeAnnotation': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ColorPrimitive' + } + } + ] + } + }, + { + 'name': 'processed_color_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': false, + 'typeAnnotation': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ColorPrimitive' + } + } + ] + } + }, + { + 'name': 'processed_color_optional_key', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': true, + 'typeAnnotation': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ColorPrimitive' + } + } + ] + } + }, + { + 'name': 'processed_color_optional_value', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': true, + 'typeAnnotation': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ColorPrimitive' + } + } + ] + } + }, + { + 'name': 'processed_color_optional_both', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': true, + 'typeAnnotation': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'ColorPrimitive' + } + } + ] + } + }, + { + 'name': 'point_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': false, + 'typeAnnotation': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'PointPrimitive' + } + } + ] + } + }, + { + 'name': 'point_optional_key', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': true, + 'typeAnnotation': { + 'type': 'ReservedPropTypeAnnotation', + 'name': 'PointPrimitive' + } + } + ] } }, { - 'name': 'color_required', + 'name': 'point_optional_value', 'optional': false, 'typeAnnotation': { 'type': 'ObjectTypeAnnotation', 'properties': [ { 'name': 'prop', - 'optional': false, + 'optional': true, 'typeAnnotation': { 'type': 'ReservedPropTypeAnnotation', - 'name': 'ColorPrimitive' + 'name': 'PointPrimitive' } } ] } }, { - 'name': 'color_optional_key', + 'name': 'point_optional_both', 'optional': false, 'typeAnnotation': { 'type': 'ObjectTypeAnnotation', @@ -8057,31 +13603,31 @@ exports[`RN Codegen TypeScript Parser can generate fixture OBJECT_PROP_TYPES_NO_ 'optional': true, 'typeAnnotation': { 'type': 'ReservedPropTypeAnnotation', - 'name': 'ColorPrimitive' + 'name': 'PointPrimitive' } } ] } }, { - 'name': 'color_optional_value', + 'name': 'insets_required', 'optional': false, 'typeAnnotation': { 'type': 'ObjectTypeAnnotation', 'properties': [ { 'name': 'prop', - 'optional': true, + 'optional': false, 'typeAnnotation': { 'type': 'ReservedPropTypeAnnotation', - 'name': 'ColorPrimitive' + 'name': 'EdgeInsetsPrimitive' } } ] } }, { - 'name': 'color_optional_both', + 'name': 'insets_optional_key', 'optional': false, 'typeAnnotation': { 'type': 'ObjectTypeAnnotation', @@ -8091,31 +13637,31 @@ exports[`RN Codegen TypeScript Parser can generate fixture OBJECT_PROP_TYPES_NO_ 'optional': true, 'typeAnnotation': { 'type': 'ReservedPropTypeAnnotation', - 'name': 'ColorPrimitive' + 'name': 'EdgeInsetsPrimitive' } } ] } }, { - 'name': 'processed_color_required', + 'name': 'insets_optional_value', 'optional': false, 'typeAnnotation': { 'type': 'ObjectTypeAnnotation', 'properties': [ { 'name': 'prop', - 'optional': false, + 'optional': true, 'typeAnnotation': { 'type': 'ReservedPropTypeAnnotation', - 'name': 'ColorPrimitive' + 'name': 'EdgeInsetsPrimitive' } } ] } }, { - 'name': 'processed_color_optional_key', + 'name': 'insets_optional_both', 'optional': false, 'typeAnnotation': { 'type': 'ObjectTypeAnnotation', @@ -8125,31 +13671,31 @@ exports[`RN Codegen TypeScript Parser can generate fixture OBJECT_PROP_TYPES_NO_ 'optional': true, 'typeAnnotation': { 'type': 'ReservedPropTypeAnnotation', - 'name': 'ColorPrimitive' + 'name': 'EdgeInsetsPrimitive' } } ] } }, { - 'name': 'processed_color_optional_value', + 'name': 'dimension_required', 'optional': false, 'typeAnnotation': { 'type': 'ObjectTypeAnnotation', 'properties': [ { 'name': 'prop', - 'optional': true, + 'optional': false, 'typeAnnotation': { 'type': 'ReservedPropTypeAnnotation', - 'name': 'ColorPrimitive' + 'name': 'DimensionPrimitive' } } ] } }, { - 'name': 'processed_color_optional_both', + 'name': 'dimension_optional_key', 'optional': false, 'typeAnnotation': { 'type': 'ObjectTypeAnnotation', @@ -8159,31 +13705,31 @@ exports[`RN Codegen TypeScript Parser can generate fixture OBJECT_PROP_TYPES_NO_ 'optional': true, 'typeAnnotation': { 'type': 'ReservedPropTypeAnnotation', - 'name': 'ColorPrimitive' + 'name': 'DimensionPrimitive' } } ] } }, { - 'name': 'point_required', + 'name': 'dimension_optional_value', 'optional': false, 'typeAnnotation': { 'type': 'ObjectTypeAnnotation', 'properties': [ { 'name': 'prop', - 'optional': false, + 'optional': true, 'typeAnnotation': { 'type': 'ReservedPropTypeAnnotation', - 'name': 'PointPrimitive' + 'name': 'DimensionPrimitive' } } ] } }, { - 'name': 'point_optional_key', + 'name': 'dimension_optional_both', 'optional': false, 'typeAnnotation': { 'type': 'ObjectTypeAnnotation', @@ -8193,551 +13739,1906 @@ exports[`RN Codegen TypeScript Parser can generate fixture OBJECT_PROP_TYPES_NO_ 'optional': true, 'typeAnnotation': { 'type': 'ReservedPropTypeAnnotation', - 'name': 'PointPrimitive' + 'name': 'DimensionPrimitive' } } ] } }, { - 'name': 'point_optional_value', + 'name': 'object_required', 'optional': false, 'typeAnnotation': { 'type': 'ObjectTypeAnnotation', 'properties': [ { 'name': 'prop', - 'optional': true, + 'optional': false, 'typeAnnotation': { - 'type': 'ReservedPropTypeAnnotation', - 'name': 'PointPrimitive' + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'nestedProp', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation', + 'default': null + } + } + ] } } ] } }, { - 'name': 'point_optional_both', - 'optional': false, + 'name': 'object_optional_key', + 'optional': true, 'typeAnnotation': { 'type': 'ObjectTypeAnnotation', 'properties': [ { 'name': 'prop', - 'optional': true, + 'optional': false, 'typeAnnotation': { - 'type': 'ReservedPropTypeAnnotation', - 'name': 'PointPrimitive' + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'nestedProp', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation', + 'default': null + } + } + ] + } + } + ] + } + }, + { + 'name': 'object_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'nestedProp', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation', + 'default': null + } + } + ] + } + } + ] + } + }, + { + 'name': 'object_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'prop', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'nestedProp', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation', + 'default': null + } + } + ] } } ] } - }, + } + ], + 'commands': [] + } + } + } + } +}" +`; + +exports[`RN Codegen TypeScript Parser can generate fixture ONE_OF_EACH_PROP_EVENT_DEFAULT_AND_OPTIONS 1`] = ` +"{ + 'modules': { + 'Module': { + 'type': 'Component', + 'components': { + 'Module': { + 'interfaceOnly': true, + 'paperComponentName': 'RCTModule', + 'extendsProps': [ + { + 'type': 'ReactNativeBuiltInType', + 'knownTypeName': 'ReactNativeCoreViewProps' + } + ], + 'events': [ + { + 'name': 'onDirectEventDefinedInlineNull', + 'optional': false, + 'bubblingType': 'direct', + 'typeAnnotation': { + 'type': 'EventTypeAnnotation', + 'argument': { + 'type': 'ObjectTypeAnnotation', + 'properties': [] + } + } + }, + { + 'name': 'onBubblingEventDefinedInlineNull', + 'optional': false, + 'bubblingType': 'bubble', + 'typeAnnotation': { + 'type': 'EventTypeAnnotation', + 'argument': { + 'type': 'ObjectTypeAnnotation', + 'properties': [] + } + } + } + ], + 'props': [ + { + 'name': 'boolean_default_true_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation', + 'default': true + } + } + ], + 'commands': [] + } + } + } + } +}" +`; + +exports[`RN Codegen TypeScript Parser can generate fixture ONE_OF_EACH_PROP_EVENT_DEFAULT_AND_OPTIONS_NO_CAST 1`] = ` +"{ + 'modules': { + 'Module': { + 'type': 'Component', + 'components': { + 'Module': { + 'interfaceOnly': true, + 'excludedPlatforms': [ + 'android' + ], + 'paperComponentName': 'RCTModule', + 'extendsProps': [ + { + 'type': 'ReactNativeBuiltInType', + 'knownTypeName': 'ReactNativeCoreViewProps' + } + ], + 'events': [ + { + 'name': 'onDirectEventDefinedInlineNull', + 'optional': false, + 'bubblingType': 'direct', + 'typeAnnotation': { + 'type': 'EventTypeAnnotation', + 'argument': { + 'type': 'ObjectTypeAnnotation', + 'properties': [] + } + } + }, + { + 'name': 'onBubblingEventDefinedInlineNull', + 'optional': false, + 'bubblingType': 'bubble', + 'typeAnnotation': { + 'type': 'EventTypeAnnotation', + 'argument': { + 'type': 'ObjectTypeAnnotation', + 'properties': [] + } + } + } + ], + 'props': [ + { + 'name': 'boolean_default_true_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation', + 'default': true + } + } + ], + 'commands': [] + } + } + } + } +}" +`; + +exports[`RN Codegen TypeScript Parser can generate fixture PROPS_ALIASED_LOCALLY 1`] = ` +"{ + 'modules': { + 'Module': { + 'type': 'Component', + 'components': { + 'Module': { + 'extendsProps': [ { - 'name': 'insets_required', + 'type': 'ReactNativeBuiltInType', + 'knownTypeName': 'ReactNativeCoreViewProps' + } + ], + 'events': [], + 'props': [ + { + 'name': 'otherStringProp', 'optional': false, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'prop', - 'optional': false, - 'typeAnnotation': { - 'type': 'ReservedPropTypeAnnotation', - 'name': 'EdgeInsetsPrimitive' - } - } - ] + 'type': 'StringTypeAnnotation', + 'default': null } }, { - 'name': 'insets_optional_key', + 'name': 'isEnabled', 'optional': false, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'prop', - 'optional': true, - 'typeAnnotation': { - 'type': 'ReservedPropTypeAnnotation', - 'name': 'EdgeInsetsPrimitive' - } - } - ] + 'type': 'BooleanTypeAnnotation', + 'default': false } }, { - 'name': 'insets_optional_value', + 'name': 'label', 'optional': false, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'prop', - 'optional': true, - 'typeAnnotation': { - 'type': 'ReservedPropTypeAnnotation', - 'name': 'EdgeInsetsPrimitive' - } - } - ] + 'type': 'StringTypeAnnotation', + 'default': null } }, { - 'name': 'insets_optional_both', + 'name': 'localType', 'optional': false, 'typeAnnotation': { 'type': 'ObjectTypeAnnotation', 'properties': [ { - 'name': 'prop', - 'optional': true, + 'name': 'otherStringProp', + 'optional': false, 'typeAnnotation': { - 'type': 'ReservedPropTypeAnnotation', - 'name': 'EdgeInsetsPrimitive' + 'type': 'StringTypeAnnotation', + 'default': null } - } - ] - } - }, - { - 'name': 'dimension_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ + }, { - 'name': 'prop', + 'name': 'isEnabled', 'optional': false, 'typeAnnotation': { - 'type': 'ReservedPropTypeAnnotation', - 'name': 'DimensionPrimitive' + 'type': 'BooleanTypeAnnotation', + 'default': false } - } - ] - } - }, - { - 'name': 'dimension_optional_key', - 'optional': false, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ + }, { - 'name': 'prop', - 'optional': true, + 'name': 'label', + 'optional': false, 'typeAnnotation': { - 'type': 'ReservedPropTypeAnnotation', - 'name': 'DimensionPrimitive' + 'type': 'StringTypeAnnotation', + 'default': null } } ] } }, { - 'name': 'dimension_optional_value', + 'name': 'localArr', 'optional': false, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'prop', - 'optional': true, - 'typeAnnotation': { - 'type': 'ReservedPropTypeAnnotation', - 'name': 'DimensionPrimitive' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'otherStringProp', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation', + 'default': null + } + }, + { + 'name': 'isEnabled', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation', + 'default': false + } + }, + { + 'name': 'label', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation', + 'default': null + } } - } - ] + ] + } } - }, + } + ], + 'commands': [] + } + } + } + } +}" +`; + +exports[`RN Codegen TypeScript Parser can generate fixture PROPS_AND_EVENTS_TYPES_EXPORTED 1`] = ` +"{ + 'modules': { + 'Module': { + 'type': 'Component', + 'components': { + 'Module': { + 'extendsProps': [ { - 'name': 'dimension_optional_both', + 'type': 'ReactNativeBuiltInType', + 'knownTypeName': 'ReactNativeCoreViewProps' + } + ], + 'events': [ + { + 'name': 'onBubblingEventDefinedInline', 'optional': false, + 'bubblingType': 'bubble', 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'prop', - 'optional': true, - 'typeAnnotation': { - 'type': 'ReservedPropTypeAnnotation', - 'name': 'DimensionPrimitive' + 'type': 'EventTypeAnnotation', + 'argument': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'boolean_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'boolean_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'boolean_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'string_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'string_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'string_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'double_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'double_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'double_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'double_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'float_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'float_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'float_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'int32_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'int32_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'int32_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'enum_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'enum_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'enum_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'enum_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'object_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_required_nested_2_layers', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'object_optional_nested_1_layer', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'double_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + } + ] + } + }, + { + 'name': 'object_readonly_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_readonly_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_readonly_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_readonly_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + }, + { + 'name': 'boolean_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'boolean_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'boolean_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'boolean_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'string_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'string_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'string_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'string_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'double_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'double_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'double_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'double_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'float_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'float_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'float_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'float_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'int32_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'int32_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'int32_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'int32_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'enum_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'enum_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'enum_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'enum_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'object_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ] + } + } + }, + { + 'name': 'object_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + } + ] + } + } + }, + { + 'name': 'object_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + } + ] + } + } + }, + { + 'name': 'object_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + } + }, + { + 'name': 'int32_array_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + } + }, + { + 'name': 'int32_array_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + } + }, + { + 'name': 'int32_array_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + } + }, + { + 'name': 'int32_array_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + } } - } - ] + ] + } } }, { - 'name': 'object_required', + 'name': 'onBubblingEventDefinedInlineWithPaperName', 'optional': false, + 'bubblingType': 'bubble', + 'paperTopLevelNameDeprecated': 'paperBubblingEventDefinedInlineWithPaperName', 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'prop', - 'optional': false, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'nestedProp', - 'optional': false, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation', - 'default': null + 'type': 'EventTypeAnnotation', + 'argument': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'boolean_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'boolean_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'boolean_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + }, + { + 'name': 'string_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'string_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'string_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'double_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'double_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'double_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'double_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'float_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'float_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'float_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'int32_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'int32_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'int32_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'enum_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'enum_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'enum_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'enum_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + }, + { + 'name': 'object_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_required_nested_2_layers', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'object_optional_nested_1_layer', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + }, + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'double_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'DoubleTypeAnnotation' + } + }, + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + }, + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + } + ] + } + }, + { + 'name': 'object_readonly_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_readonly_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_readonly_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'object_readonly_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } } + ] + } + }, + { + 'name': 'boolean_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'boolean_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'boolean_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } + } + }, + { + 'name': 'boolean_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' } - ] - } - } - ] - } - }, - { - 'name': 'object_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'prop', - 'optional': false, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'nestedProp', - 'optional': false, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation', - 'default': null - } + } + }, + { + 'name': 'string_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' } - ] - } - } - ] - } - }, - { - 'name': 'object_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'prop', - 'optional': false, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'nestedProp', - 'optional': false, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation', - 'default': null - } + } + }, + { + 'name': 'string_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' } - ] - } - } - ] - } - }, - { - 'name': 'object_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'prop', - 'optional': false, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'nestedProp', - 'optional': false, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation', - 'default': null - } + } + }, + { + 'name': 'string_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'string_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } + } + }, + { + 'name': 'double_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'double_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'double_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'double_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } + } + }, + { + 'name': 'float_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'float_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'float_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'float_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } + } + }, + { + 'name': 'int32_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'int32_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'int32_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'int32_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + }, + { + 'name': 'enum_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'enum_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'enum_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'enum_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'object_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ] + } + } + }, + { + 'name': 'object_array_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + } + ] } - ] - } - } - ] - } - } - ], - 'commands': [] - } - } - } - } -}" -`; - -exports[`RN Codegen TypeScript Parser can generate fixture ONE_OF_EACH_PROP_EVENT_DEFAULT_AND_OPTIONS 1`] = ` -"{ - 'modules': { - 'Module': { - 'type': 'Component', - 'components': { - 'Module': { - 'interfaceOnly': true, - 'paperComponentName': 'RCTModule', - 'extendsProps': [ - { - 'type': 'ReactNativeBuiltInType', - 'knownTypeName': 'ReactNativeCoreViewProps' - } - ], - 'events': [ - { - 'name': 'onDirectEventDefinedInlineNull', - 'optional': false, - 'bubblingType': 'direct', - 'typeAnnotation': { - 'type': 'EventTypeAnnotation', - 'argument': { - 'type': 'ObjectTypeAnnotation', - 'properties': [] - } - } - }, - { - 'name': 'onBubblingEventDefinedInlineNull', - 'optional': false, - 'bubblingType': 'bubble', - 'typeAnnotation': { - 'type': 'EventTypeAnnotation', - 'argument': { - 'type': 'ObjectTypeAnnotation', - 'properties': [] - } - } - } - ], - 'props': [ - { - 'name': 'boolean_default_true_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation', - 'default': true - } - } - ], - 'commands': [] - } - } - } - } -}" -`; - -exports[`RN Codegen TypeScript Parser can generate fixture ONE_OF_EACH_PROP_EVENT_DEFAULT_AND_OPTIONS_NO_CAST 1`] = ` -"{ - 'modules': { - 'Module': { - 'type': 'Component', - 'components': { - 'Module': { - 'interfaceOnly': true, - 'excludedPlatforms': [ - 'android' - ], - 'paperComponentName': 'RCTModule', - 'extendsProps': [ - { - 'type': 'ReactNativeBuiltInType', - 'knownTypeName': 'ReactNativeCoreViewProps' - } - ], - 'events': [ - { - 'name': 'onDirectEventDefinedInlineNull', - 'optional': false, - 'bubblingType': 'direct', - 'typeAnnotation': { - 'type': 'EventTypeAnnotation', - 'argument': { - 'type': 'ObjectTypeAnnotation', - 'properties': [] - } - } - }, - { - 'name': 'onBubblingEventDefinedInlineNull', - 'optional': false, - 'bubblingType': 'bubble', - 'typeAnnotation': { - 'type': 'EventTypeAnnotation', - 'argument': { - 'type': 'ObjectTypeAnnotation', - 'properties': [] - } - } - } - ], - 'props': [ - { - 'name': 'boolean_default_true_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation', - 'default': true - } - } - ], - 'commands': [] - } - } - } - } -}" -`; - -exports[`RN Codegen TypeScript Parser can generate fixture PROPS_ALIASED_LOCALLY 1`] = ` -"{ - 'modules': { - 'Module': { - 'type': 'Component', - 'components': { - 'Module': { - 'extendsProps': [ - { - 'type': 'ReactNativeBuiltInType', - 'knownTypeName': 'ReactNativeCoreViewProps' - } - ], - 'events': [], - 'props': [ - { - 'name': 'otherStringProp', - 'optional': false, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation', - 'default': null - } - }, - { - 'name': 'isEnabled', - 'optional': false, - 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation', - 'default': false - } - }, - { - 'name': 'label', - 'optional': false, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation', - 'default': null - } - }, - { - 'name': 'localType', - 'optional': false, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'otherStringProp', - 'optional': false, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation', - 'default': null - } - }, - { - 'name': 'isEnabled', - 'optional': false, - 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation', - 'default': false - } - }, - { - 'name': 'label', - 'optional': false, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation', - 'default': null - } - } - ] - } - }, - { - 'name': 'localArr', - 'optional': false, - 'typeAnnotation': { - 'type': 'ArrayTypeAnnotation', - 'elementType': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ + } + }, + { + 'name': 'object_array_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } + } + ] + } + } + }, + { + 'name': 'object_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } + } + ] + } + } + }, { - 'name': 'otherStringProp', + 'name': 'int32_array_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'StringTypeAnnotation', - 'default': null + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } } }, { - 'name': 'isEnabled', - 'optional': false, + 'name': 'int32_array_array_optional_key', + 'optional': true, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation', - 'default': false + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } } }, { - 'name': 'label', - 'optional': false, + 'name': 'int32_array_array_optional_value', + 'optional': true, 'typeAnnotation': { - 'type': 'StringTypeAnnotation', - 'default': null + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } + } + }, + { + 'name': 'int32_array_array_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } + } } } ] } } - } - ], - 'commands': [] - } - } - } - } -}" -`; - -exports[`RN Codegen TypeScript Parser can generate fixture PROPS_AND_EVENTS_TYPES_EXPORTED 1`] = ` -"{ - 'modules': { - 'Module': { - 'type': 'Component', - 'components': { - 'Module': { - 'extendsProps': [ - { - 'type': 'ReactNativeBuiltInType', - 'knownTypeName': 'ReactNativeCoreViewProps' - } - ], - 'events': [ + }, { - 'name': 'onBubblingEventDefinedInline', + 'name': 'onDirectEventDefinedInline', 'optional': false, - 'bubblingType': 'bubble', + 'bubblingType': 'direct', 'typeAnnotation': { 'type': 'EventTypeAnnotation', 'argument': { @@ -9107,384 +16008,389 @@ exports[`RN Codegen TypeScript Parser can generate fixture PROPS_AND_EVENTS_TYPE } ] } - } - ] - } - } - }, - { - 'name': 'onBubblingEventDefinedInlineWithPaperName', - 'optional': false, - 'bubblingType': 'bubble', - 'paperTopLevelNameDeprecated': 'paperBubblingEventDefinedInlineWithPaperName', - 'typeAnnotation': { - 'type': 'EventTypeAnnotation', - 'argument': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ + }, { - 'name': 'boolean_required', + 'name': 'boolean_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'boolean_optional_key', + 'name': 'boolean_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'boolean_optional_value', + 'name': 'boolean_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'boolean_optional_both', + 'name': 'boolean_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'string_required', + 'name': 'string_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'string_optional_key', + 'name': 'string_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'string_optional_value', + 'name': 'string_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'string_optional_both', + 'name': 'string_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'double_required', + 'name': 'double_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } } }, { - 'name': 'double_optional_key', + 'name': 'double_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } } }, { - 'name': 'double_optional_value', + 'name': 'double_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } } }, { - 'name': 'double_optional_both', + 'name': 'double_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } } }, { - 'name': 'float_required', + 'name': 'float_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'float_optional_key', + 'name': 'float_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'float_optional_value', + 'name': 'float_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'float_optional_both', + 'name': 'float_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'int32_required', + 'name': 'int32_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'int32_optional_key', + 'name': 'int32_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'int32_optional_value', + 'name': 'int32_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'int32_optional_both', + 'name': 'int32_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'enum_required', + 'name': 'enum_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] - } - }, - { - 'name': 'enum_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } } }, { - 'name': 'enum_optional_value', + 'name': 'enum_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } } }, { - 'name': 'enum_optional_both', + 'name': 'enum_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] - } - }, - { - 'name': 'object_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'boolean_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' - } - } - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } } }, { - 'name': 'object_optional_key', + 'name': 'enum_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'string_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } + } + }, + { + 'name': 'object_array_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_optional_value', + 'name': 'object_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'float_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_optional_both', + 'name': 'object_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'int32_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_required_nested_2_layers', - 'optional': false, + 'name': 'object_array_optional_both', + 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'object_optional_nested_1_layer', - 'optional': true, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'boolean_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } - }, - { - 'name': 'string_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation' - } - }, - { - 'name': 'double_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' - } - }, - { - 'name': 'float_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' - } - }, - { - 'name': 'int32_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } - } - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_readonly_required', + 'name': 'int32_array_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'boolean_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] + } } }, { - 'name': 'object_readonly_optional_key', + 'name': 'int32_array_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'string_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] + } } }, { - 'name': 'object_readonly_optional_value', + 'name': 'int32_array_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'float_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] + } } }, { - 'name': 'object_readonly_optional_both', + 'name': 'int32_array_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'int32_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] + } } } ] @@ -9492,9 +16398,10 @@ exports[`RN Codegen TypeScript Parser can generate fixture PROPS_AND_EVENTS_TYPE } }, { - 'name': 'onDirectEventDefinedInline', + 'name': 'onDirectEventDefinedInlineWithPaperName', 'optional': false, 'bubblingType': 'direct', + 'paperTopLevelNameDeprecated': 'paperDirectEventDefinedInlineWithPaperName', 'typeAnnotation': { 'type': 'EventTypeAnnotation', 'argument': { @@ -9864,384 +16771,389 @@ exports[`RN Codegen TypeScript Parser can generate fixture PROPS_AND_EVENTS_TYPE } ] } - } - ] - } - } - }, - { - 'name': 'onDirectEventDefinedInlineWithPaperName', - 'optional': false, - 'bubblingType': 'direct', - 'paperTopLevelNameDeprecated': 'paperDirectEventDefinedInlineWithPaperName', - 'typeAnnotation': { - 'type': 'EventTypeAnnotation', - 'argument': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ + }, { - 'name': 'boolean_required', + 'name': 'boolean_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'boolean_optional_key', + 'name': 'boolean_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'boolean_optional_value', + 'name': 'boolean_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'boolean_optional_both', + 'name': 'boolean_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'BooleanTypeAnnotation' + } } }, { - 'name': 'string_required', + 'name': 'string_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'string_optional_key', + 'name': 'string_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'string_optional_value', + 'name': 'string_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'string_optional_both', + 'name': 'string_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringTypeAnnotation' + } } }, { - 'name': 'double_required', + 'name': 'double_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } } }, { - 'name': 'double_optional_key', + 'name': 'double_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } } }, { - 'name': 'double_optional_value', + 'name': 'double_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } } }, { - 'name': 'double_optional_both', + 'name': 'double_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'DoubleTypeAnnotation' + } } }, { - 'name': 'float_required', + 'name': 'float_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'float_optional_key', + 'name': 'float_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'float_optional_value', + 'name': 'float_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'float_optional_both', + 'name': 'float_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'FloatTypeAnnotation' + } } }, { - 'name': 'int32_required', + 'name': 'int32_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'int32_optional_key', + 'name': 'int32_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'int32_optional_value', + 'name': 'int32_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'int32_optional_both', + 'name': 'int32_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' + } } }, { - 'name': 'enum_required', + 'name': 'enum_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } } }, { - 'name': 'enum_optional_key', + 'name': 'enum_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } } }, { - 'name': 'enum_optional_value', + 'name': 'enum_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } } }, { - 'name': 'enum_optional_both', + 'name': 'enum_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'StringEnumTypeAnnotation', - 'options': [ - 'small', - 'large' - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'StringEnumTypeAnnotation', + 'options': [ + 'small', + 'large' + ] + } } }, { - 'name': 'object_required', + 'name': 'object_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'boolean_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'boolean_required', + 'optional': false, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_optional_key', + 'name': 'object_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'string_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'string_optional_key', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_optional_value', + 'name': 'object_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'float_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'float_optional_value', + 'optional': true, + 'typeAnnotation': { + 'type': 'FloatTypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_optional_both', + 'name': 'object_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'int32_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } - } - ] - } - }, - { - 'name': 'object_required_nested_2_layers', - 'optional': false, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'object_optional_nested_1_layer', - 'optional': true, - 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'boolean_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } - }, - { - 'name': 'string_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation' - } - }, - { - 'name': 'double_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'DoubleTypeAnnotation' - } - }, - { - 'name': 'float_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' - } - }, - { - 'name': 'int32_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } - } - ] + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'int32_optional_both', + 'optional': true, + 'typeAnnotation': { + 'type': 'Int32TypeAnnotation' + } } - } - ] + ] + } } }, { - 'name': 'object_readonly_required', + 'name': 'int32_array_array_required', 'optional': false, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'boolean_required', - 'optional': false, - 'typeAnnotation': { - 'type': 'BooleanTypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] + } } }, { - 'name': 'object_readonly_optional_key', + 'name': 'int32_array_array_optional_key', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'string_optional_key', - 'optional': true, - 'typeAnnotation': { - 'type': 'StringTypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] + } } }, { - 'name': 'object_readonly_optional_value', + 'name': 'int32_array_array_optional_value', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'float_optional_value', - 'optional': true, - 'typeAnnotation': { - 'type': 'FloatTypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] + } } }, { - 'name': 'object_readonly_optional_both', + 'name': 'int32_array_array_optional_both', 'optional': true, 'typeAnnotation': { - 'type': 'ObjectTypeAnnotation', - 'properties': [ - { - 'name': 'int32_optional_both', - 'optional': true, - 'typeAnnotation': { - 'type': 'Int32TypeAnnotation' - } + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'ArrayTypeAnnotation', + 'elementType': { + 'type': 'Int32TypeAnnotation' } - ] + } } } ] diff --git a/packages/react-native-codegen/src/parsers/typescript/components/componentsUtils.js b/packages/react-native-codegen/src/parsers/typescript/components/componentsUtils.js index 8adc7e586dfcd1..26b9bddaceac19 100644 --- a/packages/react-native-codegen/src/parsers/typescript/components/componentsUtils.js +++ b/packages/react-native-codegen/src/parsers/typescript/components/componentsUtils.js @@ -9,13 +9,12 @@ */ 'use strict'; -import type {ASTNode} from '../utils'; -import type {NamedShape} from '../../../CodegenSchema.js'; const { parseTopLevelType, flattenIntersectionType, } = require('../parseTopLevelType'); -import type {TypeDeclarationMap} from '../../utils'; +import type {TypeDeclarationMap, PropAST, ASTNode} from '../../utils'; +import type {BuildSchemaFN, Parser} from '../../parser'; function getProperties( typeName: string, @@ -111,7 +110,8 @@ function detectArrayType( typeAnnotation: $FlowFixMe | ASTNode, defaultValue: $FlowFixMe | void, types: TypeDeclarationMap, - buildSchema: (property: PropAST, types: TypeDeclarationMap) => ?NamedShape, + parser: Parser, + buildSchema: BuildSchemaFN, ): $FlowFixMe { // Covers: readonly T[] if ( @@ -126,6 +126,7 @@ function detectArrayType( typeAnnotation.typeAnnotation.elementType, defaultValue, types, + parser, buildSchema, ), }; @@ -140,6 +141,7 @@ function detectArrayType( typeAnnotation.elementType, defaultValue, types, + parser, buildSchema, ), }; @@ -158,6 +160,7 @@ function detectArrayType( typeAnnotation.typeParameters.params[0], defaultValue, types, + parser, buildSchema, ), }; @@ -169,11 +172,12 @@ function detectArrayType( function buildObjectType( rawProperties: Array<$FlowFixMe>, types: TypeDeclarationMap, - buildSchema: (property: PropAST, types: TypeDeclarationMap) => ?NamedShape, + parser: Parser, + buildSchema: BuildSchemaFN, ): $FlowFixMe { const flattenedProperties = flattenProperties(rawProperties, types); const properties = flattenedProperties - .map(prop => buildSchema(prop, types)) + .map(prop => buildSchema(prop, types, parser)) .filter(Boolean); return { @@ -189,17 +193,24 @@ function getCommonTypeAnnotation( typeAnnotation: $FlowFixMe, defaultValue: $FlowFixMe | void, types: TypeDeclarationMap, - buildSchema: (property: PropAST, types: TypeDeclarationMap) => ?NamedShape, + parser: Parser, + buildSchema: BuildSchemaFN, ): $FlowFixMe { switch (type) { case 'TSTypeLiteral': - return buildObjectType(typeAnnotation.members, types, buildSchema); + return buildObjectType( + typeAnnotation.members, + types, + parser, + buildSchema, + ); case 'TSInterfaceDeclaration': - return buildObjectType([typeAnnotation], types, buildSchema); + return buildObjectType([typeAnnotation], types, parser, buildSchema); case 'TSIntersectionType': return buildObjectType( flattenIntersectionType(typeAnnotation, types), types, + parser, buildSchema, ); case 'ImageSource': @@ -276,7 +287,8 @@ function getTypeAnnotationForArray( typeAnnotation: $FlowFixMe, defaultValue: $FlowFixMe | void, types: TypeDeclarationMap, - buildSchema: (property: PropAST, types: TypeDeclarationMap) => ?NamedShape, + parser: Parser, + buildSchema: BuildSchemaFN, ): $FlowFixMe { // unpack WithDefault, (T) or T|U const topLevelType = parseTopLevelType(typeAnnotation, types); @@ -297,6 +309,7 @@ function getTypeAnnotationForArray( extractedTypeAnnotation, defaultValue, types, + parser, buildSchema, ); if (arrayType) { @@ -322,6 +335,7 @@ function getTypeAnnotationForArray( extractedTypeAnnotation, defaultValue, types, + parser, buildSchema, ); if (common) { @@ -370,8 +384,10 @@ function getTypeAnnotation( name: string, annotation: $FlowFixMe | ASTNode, defaultValue: $FlowFixMe | void, + withNullDefault: boolean, // Just to make `getTypeAnnotation` signature match with the one from Flow types: TypeDeclarationMap, - buildSchema: (property: PropAST, types: TypeDeclarationMap) => ?NamedShape, + parser: Parser, + buildSchema: BuildSchemaFN, ): $FlowFixMe { // unpack WithDefault, (T) or T|U const topLevelType = parseTopLevelType(annotation, types); @@ -381,6 +397,7 @@ function getTypeAnnotation( typeAnnotation, defaultValue, types, + parser, buildSchema, ); if (arrayType) { @@ -400,6 +417,7 @@ function getTypeAnnotation( typeAnnotation, defaultValue, types, + parser, buildSchema, ); if (common) { @@ -435,6 +453,7 @@ type SchemaInfo = { optional: boolean, typeAnnotation: $FlowFixMe, defaultValue: $FlowFixMe, + withNullDefault: boolean, // Just to make `getTypeAnnotation` signature match with the one from Flow }; function getSchemaInfo( @@ -460,12 +479,10 @@ function getSchemaInfo( optional: property.optional || topLevelType.optional, typeAnnotation: topLevelType.type, defaultValue: topLevelType.defaultValue, + withNullDefault: false, // Just to make `getTypeAnnotation` signature match with the one from Flow }; } -// $FlowFixMe[unclear-type] TODO(T108222691): Use flow-types for @babel/parser -type PropAST = Object; - function verifyPropNotAlreadyDefined( props: $ReadOnlyArray, needleProp: PropAST, diff --git a/packages/react-native-codegen/src/parsers/typescript/components/events.js b/packages/react-native-codegen/src/parsers/typescript/components/events.js index a92931afb136db..d1e9dadde2c399 100644 --- a/packages/react-native-codegen/src/parsers/typescript/components/events.js +++ b/packages/react-native-codegen/src/parsers/typescript/components/events.js @@ -16,9 +16,14 @@ import type { EventTypeAnnotation, } from '../../../CodegenSchema.js'; import type {TypeDeclarationMap} from '../../utils'; +import type {Parser} from '../../parser'; const {flattenProperties} = require('./componentsUtils'); const {parseTopLevelType} = require('../parseTopLevelType'); - +const { + throwIfEventHasNoName, + throwIfBubblingTypeIsNull, +} = require('../../error-utils'); +const {getEventArgument} = require('../../parsers-commons'); function getPropertyType( /* $FlowFixMe[missing-local-annot] The type annotation(s) required by Flow's * LTI update could not be added via codemod */ @@ -27,6 +32,7 @@ function getPropertyType( /* $FlowFixMe[missing-local-annot] The type annotation(s) required by Flow's * LTI update could not be added via codemod */ annotation, + parser: Parser, ): NamedShape { const topLevelType = parseTopLevelType(annotation); const typeAnnotation = topLevelType.type; @@ -83,7 +89,9 @@ function getPropertyType( optional, typeAnnotation: { type: 'ObjectTypeAnnotation', - properties: typeAnnotation.members.map(buildPropertiesForEvent), + properties: typeAnnotation.members.map(member => + buildPropertiesForEvent(member, parser), + ), }, }; case 'TSUnionType': @@ -103,13 +111,89 @@ function getPropertyType( type: 'MixedTypeAnnotation', }, }; + case 'TSArrayType': + return { + name, + optional, + typeAnnotation: extractArrayElementType(typeAnnotation, name, parser), + }; default: (type: empty); throw new Error(`Unable to determine event type for "${name}": ${type}`); } } +function extractArrayElementType( + typeAnnotation: $FlowFixMe, + name: string, + parser: Parser, +): EventTypeAnnotation { + const type = extractTypeFromTypeAnnotation(typeAnnotation); + + switch (type) { + case 'TSParenthesizedType': + return extractArrayElementType( + typeAnnotation.typeAnnotation, + name, + parser, + ); + case 'TSBooleanKeyword': + return {type: 'BooleanTypeAnnotation'}; + case 'TSStringKeyword': + return {type: 'StringTypeAnnotation'}; + case 'Float': + return { + type: 'FloatTypeAnnotation', + }; + case 'Int32': + return { + type: 'Int32TypeAnnotation', + }; + case 'TSNumberKeyword': + case 'Double': + return { + type: 'DoubleTypeAnnotation', + }; + case 'TSUnionType': + return { + type: 'StringEnumTypeAnnotation', + options: typeAnnotation.types.map(option => option.literal.value), + }; + case 'TSTypeLiteral': + return { + type: 'ObjectTypeAnnotation', + properties: typeAnnotation.members.map(member => + buildPropertiesForEvent(member, parser), + ), + }; + case 'TSArrayType': + return { + type: 'ArrayTypeAnnotation', + elementType: extractArrayElementType( + typeAnnotation.elementType, + name, + parser, + ), + }; + default: + throw new Error( + `Unrecognized ${type} for Array ${name} in events.\n${JSON.stringify( + typeAnnotation, + null, + 2, + )}`, + ); + } +} + +function extractTypeFromTypeAnnotation(typeAnnotation: $FlowFixMe): string { + return typeAnnotation.type === 'TSTypeReference' + ? typeAnnotation.typeName.name + : typeAnnotation.type; +} + function findEventArgumentsAndType( + parser: Parser, typeAnnotation: $FlowFixMe, types: TypeDeclarationMap, bubblingType: void | 'direct' | 'bubble', @@ -135,12 +219,11 @@ function findEventArgumentsAndType( }; } - if (!typeAnnotation.typeName) { - throw new Error("typeAnnotation of event doesn't have a name"); - } + throwIfEventHasNoName(typeAnnotation, parser); const name = typeAnnotation.typeName.name; if (name === 'Readonly') { return findEventArgumentsAndType( + parser, typeAnnotation.typeParameters.params[0], types, bubblingType, @@ -163,6 +246,7 @@ function findEventArgumentsAndType( }; default: return findEventArgumentsAndType( + parser, typeAnnotation.typeParameters.params[0], types, eventType, @@ -175,6 +259,7 @@ function findEventArgumentsAndType( elementType = elementType.typeAnnotation; } return findEventArgumentsAndType( + parser, elementType, types, bubblingType, @@ -189,23 +274,17 @@ function findEventArgumentsAndType( } } -/* $FlowFixMe[missing-local-annot] The type annotation(s) required by Flow's - * LTI update could not be added via codemod */ -function buildPropertiesForEvent(property): NamedShape { +function buildPropertiesForEvent( + /* $FlowFixMe[missing-local-annot] The type annotation(s) required by Flow's + * LTI update could not be added via codemod */ + property, + parser: Parser, +): NamedShape { const name = property.key.name; - const optional = property.optional || false; + const optional = parser.isOptionalProperty(property); let typeAnnotation = property.typeAnnotation.typeAnnotation; - return getPropertyType(name, optional, typeAnnotation); -} - -/* $FlowFixMe[missing-local-annot] The type annotation(s) required by Flow's - * LTI update could not be added via codemod */ -function getEventArgument(argumentProps, name: $FlowFixMe) { - return { - type: 'ObjectTypeAnnotation', - properties: argumentProps.map(buildPropertiesForEvent), - }; + return getPropertyType(name, optional, typeAnnotation, parser); } // $FlowFixMe[unclear-type] TODO(T108222691): Use flow-types for @babel/parser @@ -214,7 +293,8 @@ type EventTypeAST = Object; function buildEventSchema( types: TypeDeclarationMap, property: EventTypeAST, -): EventTypeShape { + parser: Parser, +): ?EventTypeShape { // unpack WithDefault, (T) or T|U const topLevelType = parseTopLevelType( property.typeAnnotation.typeAnnotation, @@ -225,12 +305,12 @@ function buildEventSchema( const typeAnnotation = topLevelType.type; const optional = property.optional || topLevelType.optional; const {argumentProps, bubblingType, paperTopLevelNameDeprecated} = - findEventArgumentsAndType(typeAnnotation, types); + findEventArgumentsAndType(parser, typeAnnotation, types); if (!argumentProps) { throw new Error(`Unable to determine event arguments for "${name}"`); } else if (!bubblingType) { - throw new Error(`Unable to determine event bubbling type for "${name}"`); + throwIfBubblingTypeIsNull(bubblingType, name); } else { if (paperTopLevelNameDeprecated != null) { return { @@ -240,7 +320,11 @@ function buildEventSchema( paperTopLevelNameDeprecated, typeAnnotation: { type: 'EventTypeAnnotation', - argument: getEventArgument(argumentProps, name), + argument: getEventArgument( + argumentProps, + buildPropertiesForEvent, + parser, + ), }, }; } @@ -251,7 +335,11 @@ function buildEventSchema( bubblingType, typeAnnotation: { type: 'EventTypeAnnotation', - argument: getEventArgument(argumentProps, name), + argument: getEventArgument( + argumentProps, + buildPropertiesForEvent, + parser, + ), }, }; } @@ -260,8 +348,11 @@ function buildEventSchema( function getEvents( eventTypeAST: $ReadOnlyArray, types: TypeDeclarationMap, + parser: Parser, ): $ReadOnlyArray { - return eventTypeAST.map(property => buildEventSchema(types, property)); + return eventTypeAST + .map(property => buildEventSchema(types, property, parser)) + .filter(Boolean); } module.exports = { diff --git a/packages/react-native-codegen/src/parsers/typescript/components/index.js b/packages/react-native-codegen/src/parsers/typescript/components/index.js index a42fd058cf9a33..eb54a9e930c9b9 100644 --- a/packages/react-native-codegen/src/parsers/typescript/components/index.js +++ b/packages/react-native-codegen/src/parsers/typescript/components/index.js @@ -135,8 +135,8 @@ function buildComponentSchema( const componentEventAsts: Array = []; categorizeProps(propProperties, types, componentEventAsts); - const {props, extendsProps} = getProps(propProperties, types); - const events = getEvents(componentEventAsts, types); + const {props, extendsProps} = getProps(propProperties, types, parser); + const events = getEvents(componentEventAsts, types, parser); const commands = getCommands(commandProperties, types); return { diff --git a/packages/react-native-codegen/src/parsers/typescript/components/props.js b/packages/react-native-codegen/src/parsers/typescript/components/props.js index 36bb16c6eeef93..25d24698f5c24b 100644 --- a/packages/react-native-codegen/src/parsers/typescript/components/props.js +++ b/packages/react-native-codegen/src/parsers/typescript/components/props.js @@ -9,36 +9,15 @@ */ 'use strict'; -const {getSchemaInfo, getTypeAnnotation} = require('./componentsUtils.js'); import type {NamedShape, PropTypeAnnotation} from '../../../CodegenSchema.js'; -import type {TypeDeclarationMap} from '../../utils'; +import type {TypeDeclarationMap, PropAST} from '../../utils'; import type {ExtendsPropsShape} from '../../../CodegenSchema.js'; +import type {Parser} from '../../parser'; const {flattenProperties} = require('./componentsUtils.js'); const {parseTopLevelType} = require('../parseTopLevelType'); - -// $FlowFixMe[unclear-type] there's no flowtype for ASTs -type PropAST = Object; - -function buildPropSchema( - property: PropAST, - types: TypeDeclarationMap, -): NamedShape { - const info = getSchemaInfo(property, types); - const {name, optional, typeAnnotation, defaultValue} = info; - return { - name, - optional, - typeAnnotation: getTypeAnnotation( - name, - typeAnnotation, - defaultValue, - types, - buildPropSchema, - ), - }; -} +const {buildPropSchema, extendsForProp} = require('../../parsers-commons'); function isEvent(typeAnnotation: $FlowFixMe): boolean { if (typeAnnotation.type !== 'TSTypeReference') { @@ -59,32 +38,10 @@ function isProp(name: string, typeAnnotation: $FlowFixMe): boolean { return !isStyle; } -function extendsForProp(prop: PropAST, types: TypeDeclarationMap) { - if (!prop.expression) { - console.log('null', prop); - } - const name = prop.expression.name; - - if (types[name] != null) { - // This type is locally defined in the file - return null; - } - - switch (name) { - case 'ViewProps': - return { - type: 'ReactNativeBuiltInType', - knownTypeName: 'ReactNativeCoreViewProps', - }; - default: { - throw new Error(`Unable to handle prop spread: ${name}`); - } - } -} - function getProps( typeDefinition: $ReadOnlyArray, types: TypeDeclarationMap, + parser: Parser, ): { props: $ReadOnlyArray>, extendsProps: $ReadOnlyArray, @@ -96,7 +53,7 @@ function getProps( for (const prop of typeDefinition) { // find extends if (prop.type === 'TSExpressionWithTypeArguments') { - const extend = extendsForProp(prop, types); + const extend = extendsForProp(prop, types, parser); if (extend) { extendsProps.push(extend); continue; @@ -123,7 +80,9 @@ function getProps( } return { - props: componentPropAsts.map(property => buildPropSchema(property, types)), + props: componentPropAsts + .map(property => buildPropSchema(property, types, parser)) + .filter(Boolean), extendsProps, }; } 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 6f7033c94407af..870a93494166d8 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 @@ -199,14 +199,26 @@ exports[`RN Codegen TypeScript Parser can generate fixture CXX_ONLY_NATIVE_MODUL 'typeAnnotation': { 'type': 'FunctionTypeAnnotation', 'returnTypeAnnotation': { - 'type': 'GenericObjectTypeAnnotation' + 'type': 'GenericObjectTypeAnnotation', + 'dictionaryValueType': { + 'type': 'NullableTypeAnnotation', + 'typeAnnotation': { + 'type': 'NumberTypeAnnotation' + } + } }, 'params': [ { 'name': 'arg', 'optional': false, 'typeAnnotation': { - 'type': 'GenericObjectTypeAnnotation' + 'type': 'GenericObjectTypeAnnotation', + 'dictionaryValueType': { + 'type': 'NullableTypeAnnotation', + 'typeAnnotation': { + 'type': 'NumberTypeAnnotation' + } + } } } ] @@ -218,14 +230,20 @@ exports[`RN Codegen TypeScript Parser can generate fixture CXX_ONLY_NATIVE_MODUL 'typeAnnotation': { 'type': 'FunctionTypeAnnotation', 'returnTypeAnnotation': { - 'type': 'GenericObjectTypeAnnotation' + 'type': 'GenericObjectTypeAnnotation', + 'dictionaryValueType': { + 'type': 'StringTypeAnnotation' + } }, 'params': [ { 'name': 'arg', 'optional': false, 'typeAnnotation': { - 'type': 'GenericObjectTypeAnnotation' + 'type': 'GenericObjectTypeAnnotation', + 'dictionaryValueType': { + 'type': 'StringTypeAnnotation' + } } } ] 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 d9e20011a181a3..6123cf4321a736 100644 --- a/packages/react-native-codegen/src/parsers/typescript/modules/index.js +++ b/packages/react-native-codegen/src/parsers/typescript/modules/index.js @@ -35,7 +35,7 @@ const {parseObjectProperty} = require('../../parsers-commons'); const { emitArrayType, emitFunction, - emitGenericObject, + emitDictionary, emitPromise, emitRootTag, emitUnion, @@ -309,7 +309,7 @@ function translateTypeAnnotation( // check the property type to prevent developers from using unsupported types // the return value from `translateTypeAnnotation` is unused const propertyType = indexSignatures[0].typeAnnotation; - translateTypeAnnotation( + const valueType = translateTypeAnnotation( hasteModuleName, propertyType, types, @@ -320,7 +320,7 @@ function translateTypeAnnotation( parser, ); // no need to do further checking - return emitGenericObject(nullable); + return emitDictionary(nullable, valueType); } } diff --git a/packages/react-native-codegen/src/parsers/typescript/parser.js b/packages/react-native-codegen/src/parsers/typescript/parser.js index 7e496af2d13f81..a467dc919005df 100644 --- a/packages/react-native-codegen/src/parsers/typescript/parser.js +++ b/packages/react-native-codegen/src/parsers/typescript/parser.js @@ -22,8 +22,8 @@ import type { NativeModuleEnumMap, } from '../../CodegenSchema'; import type {ParserType} from '../errors'; -import type {Parser} from '../parser'; -import type {ParserErrorCapturer, TypeDeclarationMap} from '../utils'; +import type {GetSchemaInfoFN, GetTypeAnnotationFN, Parser} from '../parser'; +import type {ParserErrorCapturer, TypeDeclarationMap, PropAST} from '../utils'; const {typeScriptTranslateTypeAnnotation} = require('./modules'); @@ -36,6 +36,10 @@ const {buildComponentSchema} = require('./components'); const {wrapComponentSchema} = require('../schema.js'); const {buildModuleSchema} = require('../parsers-commons.js'); const {resolveTypeAnnotation} = require('./utils'); +const { + getSchemaInfo, + getTypeAnnotation, +} = require('./components/componentsUtils'); const fs = require('fs'); @@ -328,6 +332,26 @@ class TypeScriptParser implements Parser { return keyword; } + + argumentForProp(prop: PropAST): $FlowFixMe { + return prop.expression; + } + + nameForArgument(prop: PropAST): $FlowFixMe { + return prop.expression.name; + } + + isOptionalProperty(property: $FlowFixMe): boolean { + return property.optional || false; + } + + getGetSchemaInfoFN(): GetSchemaInfoFN { + return getSchemaInfo; + } + + getGetTypeAnnotationFN(): GetTypeAnnotationFN { + return getTypeAnnotation; + } } module.exports = { diff --git a/packages/react-native-codegen/src/parsers/typescript/utils.js b/packages/react-native-codegen/src/parsers/typescript/utils.js index ffb7145d620852..e555ff5fe4e2c4 100644 --- a/packages/react-native-codegen/src/parsers/typescript/utils.js +++ b/packages/react-native-codegen/src/parsers/typescript/utils.js @@ -14,9 +14,6 @@ import type {TypeResolutionStatus, TypeDeclarationMap} from '../utils'; const {parseTopLevelType} = require('./parseTopLevelType'); -// $FlowFixMe[unclear-type] Use flow-types for @babel/parser -export type ASTNode = Object; - const invariant = require('invariant'); function resolveTypeAnnotation( diff --git a/packages/react-native-codegen/src/parsers/utils.js b/packages/react-native-codegen/src/parsers/utils.js index ca939b04af2774..5c904c6c80fecf 100644 --- a/packages/react-native-codegen/src/parsers/utils.js +++ b/packages/react-native-codegen/src/parsers/utils.js @@ -34,6 +34,12 @@ function extractNativeModuleName(filename: string): string { export type ParserErrorCapturer = (fn: () => T) => ?T; +// $FlowFixMe[unclear-type] there's no flowtype for ASTs +export type PropAST = Object; + +// $FlowFixMe[unclear-type] there's no flowtype for ASTs +export type ASTNode = Object; + function createParserErrorCapturer(): [ Array, ParserErrorCapturer, diff --git a/packages/react-native-gradle-plugin/README.md b/packages/react-native-gradle-plugin/README.md index 6d6889a8067989..7233d33cbd3f6a 100644 --- a/packages/react-native-gradle-plugin/README.md +++ b/packages/react-native-gradle-plugin/README.md @@ -14,3 +14,10 @@ yarn add @react-native/gradle-plugin [version-badge]: https://img.shields.io/npm/v/@react-native/gradle-plugin?style=flat-square [package]: https://www.npmjs.com/package/@react-native/gradle-plugin + +## Testing + +To run the tests in this package, run the following commands from the React Native root folder: + +1. `yarn` to install the dependencies. You just need to run this once +2. `yarn jest packages/react-native-gradle-plugin`. diff --git a/packages/react-native-gradle-plugin/build.gradle.kts b/packages/react-native-gradle-plugin/build.gradle.kts index aba364903b2857..33f4dc589d42f9 100644 --- a/packages/react-native-gradle-plugin/build.gradle.kts +++ b/packages/react-native-gradle-plugin/build.gradle.kts @@ -11,7 +11,7 @@ import org.gradle.configurationcache.extensions.serviceOf import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { - kotlin("jvm") version "1.7.22" + kotlin("jvm") version "1.8.0" id("java-gradle-plugin") } @@ -33,7 +33,12 @@ group = "com.facebook.react" dependencies { implementation(gradleApi()) + + // The KGP/AGP version is defined by React Native Gradle plugin. + // Therefore we specify an implementation dep rather than a compileOnly. + implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.0") implementation("com.android.tools.build:gradle:7.4.2") + 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") @@ -54,6 +59,8 @@ java { targetCompatibility = JavaVersion.VERSION_11 } +kotlin { jvmToolchain(11) } + tasks.withType { kotlinOptions { jvmTarget = JavaVersion.VERSION_11.majorVersion diff --git a/packages/react-native-gradle-plugin/gradle/wrapper/gradle-wrapper.jar b/packages/react-native-gradle-plugin/gradle/wrapper/gradle-wrapper.jar index 249e5832f090a2..c1962a79e29d3e 100644 Binary files a/packages/react-native-gradle-plugin/gradle/wrapper/gradle-wrapper.jar and b/packages/react-native-gradle-plugin/gradle/wrapper/gradle-wrapper.jar differ diff --git a/packages/react-native-gradle-plugin/gradle/wrapper/gradle-wrapper.properties b/packages/react-native-gradle-plugin/gradle/wrapper/gradle-wrapper.properties index 608bd94305f244..a21c6ebe28b660 100644 --- a/packages/react-native-gradle-plugin/gradle/wrapper/gradle-wrapper.properties +++ b/packages/react-native-gradle-plugin/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.1-all.zip +networkTimeout=10000 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/packages/react-native-gradle-plugin/gradlew b/packages/react-native-gradle-plugin/gradlew index a69d9cb6c20655..aeb74cbb43e393 100755 --- a/packages/react-native-gradle-plugin/gradlew +++ b/packages/react-native-gradle-plugin/gradlew @@ -55,7 +55,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -80,13 +80,10 @@ do esac done -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -APP_NAME="Gradle" +# This is normally unused +# shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -143,12 +140,16 @@ fi if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -193,6 +194,10 @@ if "$cygwin" || "$msys" ; then done fi + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + # Collect all arguments for the java command; # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of # shell script including quotes and variable substitutions, so put them in diff --git a/packages/react-native-gradle-plugin/gradlew.bat b/packages/react-native-gradle-plugin/gradlew.bat index 53a6b238d414d9..6689b85beecde6 100644 --- a/packages/react-native-gradle-plugin/gradlew.bat +++ b/packages/react-native-gradle-plugin/gradlew.bat @@ -26,6 +26,7 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% diff --git a/packages/react-native-gradle-plugin/package.json b/packages/react-native-gradle-plugin/package.json index 9bf18596fc6a43..f5eb0fd73a30eb 100644 --- a/packages/react-native-gradle-plugin/package.json +++ b/packages/react-native-gradle-plugin/package.json @@ -1,19 +1,24 @@ { "name": "@react-native/gradle-plugin", "version": "0.73.0", - "description": "⚛️ Gradle Plugin for React Native", - "homepage": "https://github.com/facebook/react-native/tree/HEAD/packages/react-native-gradle-plugin", + "description": "Gradle Plugin for React Native", + "license": "MIT", "repository": { "type": "git", - "url": "git@github.com:facebook/react-native.git", + "url": "https://github.com/facebook/react-native.git", "directory": "packages/react-native-gradle-plugin" }, + "homepage": "https://github.com/facebook/react-native/tree/HEAD/packages/react-native-gradle-plugin#readme", + "keywords": ["gradle", "plugin", "react-native"], + "bugs": "https://github.com/facebook/react-native/issues", + "engines": { + "node": ">=16" + }, "scripts": { "build": "./gradlew build", "clean": "./gradlew clean", "test": "./gradlew check" }, - "license": "MIT", "files": [ "settings.gradle.kts", "build.gradle.kts", 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 4c8a6ff9996020..8663111ce17768 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 @@ -18,7 +18,8 @@ import com.facebook.react.utils.AgpConfiguratorUtils.configureDevPorts import com.facebook.react.utils.BackwardCompatUtils.configureBackwardCompatibilityReactMap import com.facebook.react.utils.DependencyUtils.configureDependencies import com.facebook.react.utils.DependencyUtils.configureRepositories -import com.facebook.react.utils.DependencyUtils.readVersionString +import com.facebook.react.utils.DependencyUtils.readVersionAndGroupStrings +import com.facebook.react.utils.JdkConfiguratorUtils.configureJavaToolChains import com.facebook.react.utils.JsonUtils import com.facebook.react.utils.NdkConfiguratorUtils.configureReactNativeNdk import com.facebook.react.utils.ProjectUtils.needsCodegenFromPackageJson @@ -54,8 +55,10 @@ class ReactPlugin : Plugin { project.afterEvaluate { val reactNativeDir = extension.reactNativeDir.get().asFile val propertiesFile = File(reactNativeDir, "ReactAndroid/gradle.properties") - val versionString = readVersionString(propertiesFile) - configureDependencies(project, versionString) + val versionAndGroupStrings = readVersionAndGroupStrings(propertiesFile) + val versionString = versionAndGroupStrings.first + val groupString = versionAndGroupStrings.second + configureDependencies(project, versionString, groupString) configureRepositories(project, reactNativeDir) } @@ -63,6 +66,7 @@ class ReactPlugin : Plugin { configureBuildConfigFields(project) configureDevPorts(project) configureBackwardCompatibilityReactMap(project) + configureJavaToolChains(project) project.extensions.getByType(AndroidComponentsExtension::class.java).apply { onVariants(selector().all()) { variant -> diff --git a/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/DependencyUtils.kt b/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/DependencyUtils.kt index 6679aba9c216eb..fbdf6fe131b545 100644 --- a/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/DependencyUtils.kt +++ b/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/DependencyUtils.kt @@ -13,6 +13,8 @@ import java.util.* import org.gradle.api.Project import org.gradle.api.artifacts.repositories.MavenArtifactRepository +internal const val DEFAULT_GROUP_STRING = "com.facebook.react" + internal object DependencyUtils { /** @@ -46,7 +48,11 @@ internal object DependencyUtils { * - Forcing the react-android/hermes-android version to the one specified in the package.json * - Substituting `react-native` with `react-android` and `hermes-engine` with `hermes-android`. */ - fun configureDependencies(project: Project, versionString: String) { + fun configureDependencies( + project: Project, + versionString: String, + groupString: String = DEFAULT_GROUP_STRING + ) { if (versionString.isBlank()) return project.rootProject.allprojects { eachProject -> eachProject.configurations.all { configuration -> @@ -56,32 +62,36 @@ internal object DependencyUtils { // implementation("com.facebook.react:react-native:+") and resolve the right dependency. configuration.resolutionStrategy.dependencySubstitution { it.substitute(it.module("com.facebook.react:react-native")) - .using(it.module("com.facebook.react:react-android:${versionString}")) + .using(it.module("${groupString}:react-android:${versionString}")) .because( "The react-native artifact was deprecated in favor of react-android due to https://github.com/facebook/react-native/issues/35210.") it.substitute(it.module("com.facebook.react:hermes-engine")) - .using(it.module("com.facebook.react:hermes-android:${versionString}")) + .using(it.module("${groupString}:hermes-android:${versionString}")) .because( "The hermes-engine artifact was deprecated in favor of hermes-android due to https://github.com/facebook/react-native/issues/35210.") } configuration.resolutionStrategy.force( - "com.facebook.react:react-android:${versionString}", - "com.facebook.react:hermes-android:${versionString}", + "${groupString}:react-android:${versionString}", + "${groupString}:hermes-android:${versionString}", ) } } } - fun readVersionString(propertiesFile: File): String { + fun readVersionAndGroupStrings(propertiesFile: File): Pair { val reactAndroidProperties = Properties() propertiesFile.inputStream().use { reactAndroidProperties.load(it) } - val versionString = reactAndroidProperties["VERSION_NAME"] as? String ?: "" + val versionStringFromFile = reactAndroidProperties["VERSION_NAME"] as? String ?: "" // If on a nightly, we need to fetch the -SNAPSHOT artifact from Sonatype. - return if (versionString.startsWith("0.0.0")) { - "$versionString-SNAPSHOT" - } else { - versionString - } + val versionString = + if (versionStringFromFile.startsWith("0.0.0") || "-nightly-" in versionStringFromFile) { + "$versionStringFromFile-SNAPSHOT" + } else { + versionStringFromFile + } + // Returns Maven group for repos using different group for Maven artifacts + val groupString = reactAndroidProperties["GROUP"] as? String ?: DEFAULT_GROUP_STRING + return Pair(versionString, groupString) } fun Project.mavenRepoFromUrl(url: String): MavenArtifactRepository = diff --git a/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/JdkConfiguratorUtils.kt b/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/JdkConfiguratorUtils.kt new file mode 100644 index 00000000000000..c86484ab5249c5 --- /dev/null +++ b/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/JdkConfiguratorUtils.kt @@ -0,0 +1,33 @@ +/* + * 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. + */ + +package com.facebook.react.utils + +import com.android.build.api.variant.AndroidComponentsExtension +import org.gradle.api.JavaVersion +import org.gradle.api.Project +import org.jetbrains.kotlin.gradle.dsl.KotlinTopLevelExtension + +internal object JdkConfiguratorUtils { + /** + * Function that takes care of configuring the JDK toolchain for Application projects. As we do + * decide the JDK version based on the AGP version that RNGP brings over, here we can safely + * configure the toolchain to 11. + */ + fun configureJavaToolChains(project: Project) { + project.extensions.getByType(AndroidComponentsExtension::class.java).finalizeDsl { ext -> + ext.compileOptions.sourceCompatibility = JavaVersion.VERSION_11 + ext.compileOptions.targetCompatibility = JavaVersion.VERSION_11 + } + project.pluginManager.withPlugin("org.jetbrains.kotlin.android") { + project.extensions.getByType(KotlinTopLevelExtension::class.java).jvmToolchain(11) + } + project.pluginManager.withPlugin("org.jetbrains.kotlin.jvm") { + project.extensions.getByType(KotlinTopLevelExtension::class.java).jvmToolchain(11) + } + } +} diff --git a/packages/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/utils/DependencyUtilsTest.kt b/packages/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/utils/DependencyUtilsTest.kt index 1b7c728cc4b4f6..f77c0bb3026b46 100644 --- a/packages/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/utils/DependencyUtilsTest.kt +++ b/packages/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/utils/DependencyUtilsTest.kt @@ -12,7 +12,7 @@ import com.facebook.react.utils.DependencyUtils.configureDependencies import com.facebook.react.utils.DependencyUtils.configureRepositories import com.facebook.react.utils.DependencyUtils.mavenRepoFromURI import com.facebook.react.utils.DependencyUtils.mavenRepoFromUrl -import com.facebook.react.utils.DependencyUtils.readVersionString +import com.facebook.react.utils.DependencyUtils.readVersionAndGroupStrings import java.net.URI import org.gradle.api.artifacts.repositories.MavenArtifactRepository import org.gradle.testfixtures.ProjectBuilder @@ -226,6 +226,24 @@ class DependencyUtilsTest { assertTrue(libForcedModules.any { it.toString() == "com.facebook.react:hermes-android:1.2.3" }) } + @Test + fun configureDependencies_withVersionStringAndGroupString_appliesOnAllProjects() { + val rootProject = ProjectBuilder.builder().build() + val appProject = ProjectBuilder.builder().withName("app").withParent(rootProject).build() + val libProject = ProjectBuilder.builder().withName("lib").withParent(rootProject).build() + appProject.plugins.apply("com.android.application") + libProject.plugins.apply("com.android.library") + + configureDependencies(appProject, "1.2.3", "io.github.test") + + val appForcedModules = appProject.configurations.first().resolutionStrategy.forcedModules + val libForcedModules = libProject.configurations.first().resolutionStrategy.forcedModules + assertTrue(appForcedModules.any { it.toString() == "io.github.test:react-android:1.2.3" }) + assertTrue(appForcedModules.any { it.toString() == "io.github.test:hermes-android:1.2.3" }) + assertTrue(libForcedModules.any { it.toString() == "io.github.test:react-android:1.2.3" }) + assertTrue(libForcedModules.any { it.toString() == "io.github.test:hermes-android:1.2.3" }) + } + @Test fun readVersionString_withCorrectVersionString_returnsIt() { val propertiesFile = @@ -238,7 +256,7 @@ class DependencyUtilsTest { .trimIndent()) } - val versionString = readVersionString(propertiesFile) + val versionString = readVersionAndGroupStrings(propertiesFile).first assertEquals("1000.0.0", versionString) } @@ -255,7 +273,7 @@ class DependencyUtilsTest { .trimIndent()) } - val versionString = readVersionString(propertiesFile) + val versionString = readVersionAndGroupStrings(propertiesFile).first assertEquals("0.0.0-20221101-2019-cfe811ab1-SNAPSHOT", versionString) } @@ -271,7 +289,7 @@ class DependencyUtilsTest { .trimIndent()) } - val versionString = readVersionString(propertiesFile) + val versionString = readVersionAndGroupStrings(propertiesFile).first assertEquals("", versionString) } @@ -287,10 +305,43 @@ class DependencyUtilsTest { .trimIndent()) } - val versionString = readVersionString(propertiesFile) + val versionString = readVersionAndGroupStrings(propertiesFile).first assertEquals("", versionString) } + @Test + fun readGroupString_withCorrectGroupString_returnsIt() { + val propertiesFile = + tempFolder.newFile("gradle.properties").apply { + writeText( + """ + GROUP=io.github.test + ANOTHER_PROPERTY=true + """ + .trimIndent()) + } + + val groupString = readVersionAndGroupStrings(propertiesFile).second + + assertEquals("io.github.test", groupString) + } + + @Test + fun readGroupString_withEmptyGroupString_returnsDefault() { + val propertiesFile = + tempFolder.newFile("gradle.properties").apply { + writeText( + """ + ANOTHER_PROPERTY=true + """ + .trimIndent()) + } + + val groupString = readVersionAndGroupStrings(propertiesFile).second + + assertEquals("com.facebook.react", groupString) + } + @Test fun mavenRepoFromUrl_worksCorrectly() { val process = createProject() diff --git a/packages/react-native/Libraries/Alert/Alert.js.flow b/packages/react-native/Libraries/Alert/Alert.js.flow deleted file mode 100644 index be6f948f557add..00000000000000 --- a/packages/react-native/Libraries/Alert/Alert.js.flow +++ /dev/null @@ -1,49 +0,0 @@ -/** - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - * @flow - */ - -export type AlertType = - | 'default' - | 'plain-text' - | 'secure-text' - | 'login-password'; -export type AlertButtonStyle = 'default' | 'cancel' | 'destructive'; -export type Buttons = Array<{ - text?: string, - onPress?: ?Function, - isPreferred?: boolean, - style?: AlertButtonStyle, - ... -}>; -type Options = { - cancelable?: ?boolean, - userInterfaceStyle?: 'unspecified' | 'light' | 'dark', - onDismiss?: ?() => void, - ... -}; - -declare class Alert { - static alert( - title: ?string, - message?: ?string, - buttons?: Buttons, - options?: Options, - ): void; - static prompt( - title: ?string, - message?: ?string, - callbackOrButtons?: ?(((text: string) => void) | Buttons), - type?: ?AlertType, - defaultValue?: string, - keyboardType?: string, - options?: Options, - ): void; -} - -module.exports = Alert; diff --git a/packages/react-native/Libraries/Animated/NativeAnimatedHelper.js b/packages/react-native/Libraries/Animated/NativeAnimatedHelper.js index 5a6c508fd0411e..a96287de26ddd8 100644 --- a/packages/react-native/Libraries/Animated/NativeAnimatedHelper.js +++ b/packages/react-native/Libraries/Animated/NativeAnimatedHelper.js @@ -28,9 +28,7 @@ import invariant from 'invariant'; // TODO T69437152 @petetheheat - Delete this fork when Fabric ships to 100%. const NativeAnimatedModule = - Platform.OS === 'ios' && global.RN$Bridgeless === true - ? NativeAnimatedTurboModule - : NativeAnimatedNonTurboModule; + NativeAnimatedNonTurboModule ?? NativeAnimatedTurboModule; let __nativeAnimatedNodeTagCount = 1; /* used for animated nodes */ let __nativeAnimationIdCount = 1; /* used for started animations */ diff --git a/packages/react-native/Libraries/Animated/NativeAnimatedModule.js b/packages/react-native/Libraries/Animated/NativeAnimatedModule.js index 9fc932e6b509cc..a080eb4d66eb0f 100644 --- a/packages/react-native/Libraries/Animated/NativeAnimatedModule.js +++ b/packages/react-native/Libraries/Animated/NativeAnimatedModule.js @@ -11,6 +11,7 @@ import type {TurboModule} from '../TurboModule/RCTExport'; import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; +import shouldUseTurboAnimatedModule from './shouldUseTurboAnimatedModule'; type EndResult = {finished: boolean, ...}; type EndCallback = (result: EndResult) => void; @@ -70,4 +71,7 @@ export interface Spec extends TurboModule { +queueAndExecuteBatchedOperations?: (operationsAndArgs: Array) => void; } -export default (TurboModuleRegistry.get('NativeAnimatedModule'): ?Spec); +const NativeModule: ?Spec = !shouldUseTurboAnimatedModule() + ? TurboModuleRegistry.get('NativeAnimatedModule') + : null; +export default NativeModule; diff --git a/packages/react-native/Libraries/Animated/NativeAnimatedTurboModule.js b/packages/react-native/Libraries/Animated/NativeAnimatedTurboModule.js index 58664ca8742173..f9ea5881232273 100644 --- a/packages/react-native/Libraries/Animated/NativeAnimatedTurboModule.js +++ b/packages/react-native/Libraries/Animated/NativeAnimatedTurboModule.js @@ -11,6 +11,7 @@ import type {TurboModule} from '../TurboModule/RCTExport'; import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; +import shouldUseTurboAnimatedModule from './shouldUseTurboAnimatedModule'; type EndResult = {finished: boolean, ...}; type EndCallback = (result: EndResult) => void; @@ -70,6 +71,8 @@ export interface Spec extends TurboModule { +queueAndExecuteBatchedOperations?: (operationsAndArgs: Array) => void; } -export default (TurboModuleRegistry.get( - 'NativeAnimatedTurboModule', -): ?Spec); +const NativeModule: ?Spec = shouldUseTurboAnimatedModule() + ? TurboModuleRegistry.get('NativeAnimatedTurboModule') + : null; + +export default NativeModule; diff --git a/packages/react-native/Libraries/Image/ImageBackground.js.flow b/packages/react-native/Libraries/Animated/shouldUseTurboAnimatedModule.js similarity index 50% rename from packages/react-native/Libraries/Image/ImageBackground.js.flow rename to packages/react-native/Libraries/Animated/shouldUseTurboAnimatedModule.js index ad91f1a4e78dea..c112ba99aca60c 100644 --- a/packages/react-native/Libraries/Image/ImageBackground.js.flow +++ b/packages/react-native/Libraries/Animated/shouldUseTurboAnimatedModule.js @@ -8,10 +8,10 @@ * @format */ -'use strict'; +import Platform from '../Utilities/Platform'; -import * as React from 'react'; -import type {ImageBackgroundProps} from './ImageProps'; +function shouldUseTurboAnimatedModule(): boolean { + return Platform.OS === 'ios' && global.RN$Bridgeless === true; +} -declare class ImageBackground extends React.Component {} -module.exports = ImageBackground; +export default shouldUseTurboAnimatedModule; diff --git a/packages/react-native/Libraries/AppDelegate/RCTAppDelegate.h b/packages/react-native/Libraries/AppDelegate/RCTAppDelegate.h index 18c318408d8c90..93b1543c7bacc4 100644 --- a/packages/react-native/Libraries/AppDelegate/RCTAppDelegate.h +++ b/packages/react-native/Libraries/AppDelegate/RCTAppDelegate.h @@ -10,7 +10,6 @@ #import @class RCTSurfacePresenterBridgeAdapter; -@class RCTTurboModuleManager; /** * The RCTAppDelegate is an utility class that implements some base configurations for all the React Native apps. @@ -95,9 +94,6 @@ - (UIViewController *)createRootViewController; #if RCT_NEW_ARCH_ENABLED - -/// The TurboModule manager -@property (nonatomic, strong) RCTTurboModuleManager *turboModuleManager; @property (nonatomic, strong) RCTSurfacePresenterBridgeAdapter *bridgeAdapter; /// This method controls whether the `turboModules` feature of the New Architecture is turned on or off. diff --git a/packages/react-native/Libraries/AppDelegate/RCTAppDelegate.mm b/packages/react-native/Libraries/AppDelegate/RCTAppDelegate.mm index 8cf3869690557d..fffea76a6c3459 100644 --- a/packages/react-native/Libraries/AppDelegate/RCTAppDelegate.mm +++ b/packages/react-native/Libraries/AppDelegate/RCTAppDelegate.mm @@ -130,13 +130,15 @@ - (UIViewController *)createRootViewController _runtimeScheduler = std::make_shared(RCTRuntimeExecutorFromBridge(bridge)); std::shared_ptr callInvoker = std::make_shared(_runtimeScheduler); - self.turboModuleManager = [[RCTTurboModuleManager alloc] initWithBridge:bridge delegate:self jsInvoker:callInvoker]; + RCTTurboModuleManager *turboModuleManager = [[RCTTurboModuleManager alloc] initWithBridge:bridge + delegate:self + jsInvoker:callInvoker]; _contextContainer->erase("RuntimeScheduler"); _contextContainer->insert("RuntimeScheduler", _runtimeScheduler); - return RCTAppSetupDefaultJsExecutorFactory(bridge, _turboModuleManager, _runtimeScheduler); + return RCTAppSetupDefaultJsExecutorFactory(bridge, turboModuleManager, _runtimeScheduler); } -#pragma mark RCTTurboModuleManagerDelegate +#pragma mark - RCTTurboModuleManagerDelegate - (Class)getModuleClassFromName:(const char *)name { diff --git a/packages/react-native/Libraries/AppDelegate/React-RCTAppDelegate.podspec b/packages/react-native/Libraries/AppDelegate/React-RCTAppDelegate.podspec index c37f0a9fa22d26..a98f3aea404347 100644 --- a/packages/react-native/Libraries/AppDelegate/React-RCTAppDelegate.podspec +++ b/packages/react-native/Libraries/AppDelegate/React-RCTAppDelegate.podspec @@ -36,7 +36,8 @@ header_search_paths = [ "$(PODS_ROOT)/RCT-Folly", "${PODS_ROOT}/Headers/Public/FlipperKit", "$(PODS_ROOT)/Headers/Public/ReactCommon", - "$(PODS_ROOT)/Headers/Public/React-RCTFabric" + "$(PODS_ROOT)/Headers/Public/React-RCTFabric", + "$(PODS_ROOT)/Headers/Private/Yoga", ].concat(use_hermes ? [ "$(PODS_ROOT)/Headers/Public/React-hermes", "$(PODS_ROOT)/Headers/Public/hermes-engine" @@ -54,7 +55,7 @@ Pod::Spec.new do |s| s.version = version s.summary = "An utility library to simplify common operations for the New Architecture" s.homepage = "https://reactnative.dev/" - s.documentation_url = "https://reactnative.dev/docs/actionsheetios" + s.documentation_url = "https://reactnative.dev/" s.license = package["license"] s.author = "Meta Platforms, Inc. and its affiliates" s.platforms = { :ios => min_ios_version_supported } @@ -75,8 +76,19 @@ Pod::Spec.new do |s| s.dependency "RCTRequired" s.dependency "RCTTypeSafety" s.dependency "ReactCommon/turbomodule/core" + s.dependency "React-RCTNetwork" + s.dependency "React-RCTImage" + s.dependency "React-NativeModulesApple" + s.dependency "React-CoreModules" + + if ENV['USE_HERMES'] == nil || ENV['USE_HERMES'] == "1" + s.dependency "React-hermes" + else + s.dependency "React-jsc" + end if is_new_arch_enabled + s.dependency "React-Fabric" s.dependency "React-RCTFabric" s.dependency "React-graphics" diff --git a/packages/react-native/Libraries/Blob/RCTBlobCollector.h b/packages/react-native/Libraries/Blob/RCTBlobCollector.h index 4d0166aab7db94..6fbf41c33ffc04 100644 --- a/packages/react-native/Libraries/Blob/RCTBlobCollector.h +++ b/packages/react-native/Libraries/Blob/RCTBlobCollector.h @@ -9,8 +9,7 @@ @class RCTBlobManager; -namespace facebook { -namespace react { +namespace facebook::react { class JSI_EXPORT RCTBlobCollector : public jsi::HostObject { public: @@ -24,5 +23,4 @@ class JSI_EXPORT RCTBlobCollector : public jsi::HostObject { RCTBlobManager *blobManager_; }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/Libraries/Blob/RCTBlobCollector.mm b/packages/react-native/Libraries/Blob/RCTBlobCollector.mm index 60053c3a140351..c9afc78057c955 100644 --- a/packages/react-native/Libraries/Blob/RCTBlobCollector.mm +++ b/packages/react-native/Libraries/Blob/RCTBlobCollector.mm @@ -10,8 +10,7 @@ #import #import -namespace facebook { -namespace react { +namespace facebook::react { RCTBlobCollector::RCTBlobCollector(RCTBlobManager *blobManager, const std::string &blobId) : blobId_(blobId), blobManager_(blobManager) @@ -52,5 +51,4 @@ queue:RCTJSThread]; } -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/Libraries/Components/Keyboard/KeyboardAvoidingView.js b/packages/react-native/Libraries/Components/Keyboard/KeyboardAvoidingView.js index 9fb5637c6c59b7..db89a91ab9ee70 100644 --- a/packages/react-native/Libraries/Components/Keyboard/KeyboardAvoidingView.js +++ b/packages/react-native/Libraries/Components/Keyboard/KeyboardAvoidingView.js @@ -112,14 +112,15 @@ class KeyboardAvoidingView extends React.Component { }; _onLayout = async (event: ViewLayoutEvent) => { - const wasFrameNull = this._frame == null; + const oldFrame = this._frame; this._frame = event.nativeEvent.layout; if (!this._initialFrameHeight) { // save the initial frame height, before the keyboard is visible this._initialFrameHeight = this._frame.height; } - if (wasFrameNull) { + // update bottom height for the first time or when the height is changed + if (!oldFrame || oldFrame.height !== this._frame.height) { await this._updateBottomIfNecessary(); } diff --git a/packages/react-native/Libraries/Components/TextInput/InputAccessoryView.js.flow b/packages/react-native/Libraries/Components/TextInput/InputAccessoryView.js.flow deleted file mode 100644 index e2245cb84d76ba..00000000000000 --- a/packages/react-native/Libraries/Components/TextInput/InputAccessoryView.js.flow +++ /dev/null @@ -1,25 +0,0 @@ -/** - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @flow - * @format - */ - -import * as React from 'react'; -import Platform from '../../Utilities/Platform'; -import StyleSheet, { - type ViewStyleProp, - type ColorValue, -} from '../../StyleSheet/StyleSheet'; - -type Props = $ReadOnly<{| - +children: React.Node, - nativeID?: ?string, - style?: ?ViewStyleProp, - backgroundColor?: ?ColorValue, -|}>; - -module.exports = class InputAccessoryView extends React.Component {}; diff --git a/packages/react-native/Libraries/Components/TextInput/__tests__/TextInput-test.js b/packages/react-native/Libraries/Components/TextInput/__tests__/TextInput-test.js index 6e9fbc1fd64299..3f0e8ed59278b6 100644 --- a/packages/react-native/Libraries/Components/TextInput/__tests__/TextInput-test.js +++ b/packages/react-native/Libraries/Components/TextInput/__tests__/TextInput-test.js @@ -322,7 +322,7 @@ describe('TextInput compat with web', () => { 'aria-label': 'label', 'aria-labelledby': 'labelledby', 'aria-level': 3, - // aria-live': 'polite', [TODO: https://github.com/facebook/react-native-deprecated-modules/pull/20] + 'aria-live': 'polite', 'aria-modal': true, 'aria-multiline': true, 'aria-multiselectable': true, @@ -381,6 +381,7 @@ describe('TextInput compat with web', () => { aria-label="label" aria-labelledby="labelledby" aria-level={3} + aria-live="polite" aria-modal={true} aria-multiline={true} aria-multiselectable={true} diff --git a/packages/react-native/Libraries/Core/__mocks__/NativeExceptionsManager.js b/packages/react-native/Libraries/Core/__mocks__/NativeExceptionsManager.js new file mode 100644 index 00000000000000..a43017ce012eee --- /dev/null +++ b/packages/react-native/Libraries/Core/__mocks__/NativeExceptionsManager.js @@ -0,0 +1,20 @@ +/** + * 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 + * @format + * @oncall react_native + */ + +import typeof NativeExceptionsManager from '../NativeExceptionsManager'; + +export default ({ + reportFatalException: jest.fn(), + reportSoftException: jest.fn(), + updateExceptionMessage: jest.fn(), + dismissRedbox: jest.fn(), + reportException: jest.fn(), +}: NativeExceptionsManager); diff --git a/packages/react-native/Libraries/DOM/Nodes/ReadOnlyCharacterData.js b/packages/react-native/Libraries/DOM/Nodes/ReadOnlyCharacterData.js index 6f3fb0f4ad7b96..6c9f87b43200b1 100644 --- a/packages/react-native/Libraries/DOM/Nodes/ReadOnlyCharacterData.js +++ b/packages/react-native/Libraries/DOM/Nodes/ReadOnlyCharacterData.js @@ -67,6 +67,6 @@ export default class ReadOnlyCharacterData extends ReadOnlyNode { ); } let adjustedCount = count < 0 || count > data.length ? data.length : count; - return data.substr(offset, adjustedCount); + return data.slice(offset, offset + adjustedCount); } } diff --git a/packages/react-native/Libraries/Image/ImageViewNativeComponent.js.flow b/packages/react-native/Libraries/Image/ImageViewNativeComponent.js.flow deleted file mode 100644 index 4bb29f02141311..00000000000000 --- a/packages/react-native/Libraries/Image/ImageViewNativeComponent.js.flow +++ /dev/null @@ -1,42 +0,0 @@ -/** - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @flow strict-local - * @format - */ - -import type {ResolvedAssetSource} from './AssetSourceResolver'; -import type {ImageProps} from './ImageProps'; -import type {ViewProps} from '../Components/View/ViewPropTypes'; -import {ConditionallyIgnoredEventHandlers} from '../NativeComponent/ViewConfigIgnore'; -import type {HostComponent} from '../Renderer/shims/ReactNativeTypes'; -import type { - ColorValue, - DangerouslyImpreciseStyle, - ImageStyleProp, -} from '../StyleSheet/StyleSheet'; -import Platform from '../Utilities/Platform'; - -type Props = $ReadOnly<{ - ...ImageProps, - ...ViewProps, - - style?: ImageStyleProp | DangerouslyImpreciseStyle, - - // iOS native props - tintColor?: ColorValue, - - // Android native props - shouldNotifyLoadEvents?: boolean, - src?: - | ?ResolvedAssetSource - | ?$ReadOnlyArray>, - headers?: ?{[string]: string}, - defaultSrc?: ?string, - loadingIndicatorSrc?: ?string, -}>; - -declare export default HostComponent; diff --git a/packages/react-native/Libraries/Image/RCTImageURLLoaderWithAttribution.h b/packages/react-native/Libraries/Image/RCTImageURLLoaderWithAttribution.h index c512736e106501..87b59f0843c6cf 100644 --- a/packages/react-native/Libraries/Image/RCTImageURLLoaderWithAttribution.h +++ b/packages/react-native/Libraries/Image/RCTImageURLLoaderWithAttribution.h @@ -11,8 +11,7 @@ // TODO (T61325135): Remove C++ checks #ifdef __cplusplus -namespace facebook { -namespace react { +namespace facebook::react { struct ImageURLLoaderAttribution { int32_t nativeViewTag = 0; @@ -21,8 +20,7 @@ struct ImageURLLoaderAttribution { NSString *analyticTag; }; -} // namespace react -} // namespace facebook +} // namespace facebook::react #endif @interface RCTImageURLLoaderRequest : NSObject diff --git a/packages/react-native/Libraries/Image/TextInlineImageNativeComponent.js.flow b/packages/react-native/Libraries/Image/TextInlineImageNativeComponent.js.flow deleted file mode 100644 index 6726b15d47a29b..00000000000000 --- a/packages/react-native/Libraries/Image/TextInlineImageNativeComponent.js.flow +++ /dev/null @@ -1,27 +0,0 @@ -/** - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - * @flow strict-local - */ - -'use strict'; - -import type {HostComponent} from '../Renderer/shims/ReactNativeTypes'; -import type {ViewProps} from '../Components/View/ViewPropTypes'; -import type {ImageResizeMode} from './ImageResizeMode'; -import * as NativeComponentRegistry from '../NativeComponent/NativeComponentRegistry'; -import type {ColorValue} from '../StyleSheet/StyleSheet'; - -type NativeProps = $ReadOnly<{ - ...ViewProps, - resizeMode?: ?ImageResizeMode, - src?: ?$ReadOnlyArray>, - tintColor?: ?ColorValue, - headers?: ?{[string]: string}, -}>; - -declare export default HostComponent; diff --git a/packages/react-native/Libraries/Inspector/NetworkOverlay.js b/packages/react-native/Libraries/Inspector/NetworkOverlay.js index c6d1ec33907e36..1e4d63f27fd9d2 100644 --- a/packages/react-native/Libraries/Inspector/NetworkOverlay.js +++ b/packages/react-native/Libraries/Inspector/NetworkOverlay.js @@ -64,7 +64,7 @@ function getStringByValue(value: any): string { } if (typeof value === 'string' && value.length > 500) { return String(value) - .substr(0, 500) + .slice(0, 500) .concat('\n***TRUNCATED TO 500 CHARACTERS***'); } return value; @@ -88,7 +88,7 @@ function keyExtractor(request: NetworkRequestInfo): string { * Show all the intercepted network requests over the InspectorPanel. */ class NetworkOverlay extends React.Component { - _requestsListView: ?React.ElementRef; + _requestsListView: ?React.ElementRef>>; _detailScrollView: ?React.ElementRef; // Metrics are used to decide when if the request list should be sticky, and diff --git a/packages/react-native/Libraries/Interaction/__tests__/InteractionManager-test.js b/packages/react-native/Libraries/Interaction/__tests__/InteractionManager-test.js index de32ebbf523ad5..c21f4c18b61d97 100644 --- a/packages/react-native/Libraries/Interaction/__tests__/InteractionManager-test.js +++ b/packages/react-native/Libraries/Interaction/__tests__/InteractionManager-test.js @@ -171,6 +171,10 @@ describe('promise tasks', () => { sequenceId = 0; }); + afterEach(() => { + jest.useRealTimers(); + }); + it('should run a basic promise task', () => { const task1 = jest.fn(() => { expect(++sequenceId).toBe(1); diff --git a/packages/react-native/Libraries/Lists/FlatList.d.ts b/packages/react-native/Libraries/Lists/FlatList.d.ts index b6b28675a7c6e1..5bbe2fa3b80c7a 100644 --- a/packages/react-native/Libraries/Lists/FlatList.d.ts +++ b/packages/react-native/Libraries/Lists/FlatList.d.ts @@ -12,6 +12,7 @@ import type { ListRenderItem, ViewToken, VirtualizedListProps, + ViewabilityConfig, } from '@react-native/virtualized-lists'; import type {ScrollViewComponent} from '../Components/ScrollView/ScrollView'; import type {StyleProp} from '../StyleSheet/StyleSheet'; @@ -144,7 +145,7 @@ export interface FlatListProps extends VirtualizedListProps { /** * See `ViewabilityHelper` for flow type and further documentation. */ - viewabilityConfig?: any | undefined; + viewabilityConfig?: ViewabilityConfig | undefined; /** * Note: may have bugs (missing content) in some circumstances - use at your own risk. diff --git a/packages/react-native/Libraries/Lists/FlatList.js b/packages/react-native/Libraries/Lists/FlatList.js index ddb929e6a80f4a..63e2de283821b1 100644 --- a/packages/react-native/Libraries/Lists/FlatList.js +++ b/packages/react-native/Libraries/Lists/FlatList.js @@ -36,7 +36,7 @@ type RequiredProps = {| * An array (or array-like list) of items to render. Other data types can be * used by targeting VirtualizedList directly. */ - data: ?$ArrayLike, + data: ?$ReadOnly<$ArrayLike>, |}; type OptionalProps = {| /** @@ -91,7 +91,7 @@ type OptionalProps = {| * specify `ItemSeparatorComponent`. */ getItemLayout?: ( - data: ?$ArrayLike, + data: ?$ReadOnly<$ArrayLike>, index: number, ) => { length: number, diff --git a/packages/react-native/Libraries/Lists/FlatList.js.flow b/packages/react-native/Libraries/Lists/FlatList.js.flow deleted file mode 100644 index 304a1006182186..00000000000000 --- a/packages/react-native/Libraries/Lists/FlatList.js.flow +++ /dev/null @@ -1,116 +0,0 @@ -/** - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @flow - * @format - */ - -const React = require('react'); -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, - RenderItemProps, - ViewToken, - ViewabilityConfigCallbackPair, -} from '@react-native/virtualized-lists'; -import {typeof VirtualizedList} from '@react-native/virtualized-lists'; - -type RequiredProps = {| - /** - * For simplicity, data is just a plain array. If you want to use something else, like an - * immutable list, use the underlying `VirtualizedList` directly. - */ - data: ?$ReadOnlyArray, -|}; -type OptionalProps = {| - renderItem?: ?RenderItemType, - columnWrapperStyle?: ViewStyleProp, - extraData?: any, - getItemLayout?: ( - data: ?Array, - index: number, - ) => { - length: number, - offset: number, - index: number, - ... - }, - horizontal?: ?boolean, - initialNumToRender?: ?number, - initialScrollIndex?: ?number, - inverted?: ?boolean, - keyExtractor?: ?(item: ItemT, index: number) => string, - numColumns?: number, - removeClippedSubviews?: boolean, - fadingEdgeLength?: ?number, - strictMode?: boolean, -|}; - -/** - * Default Props Helper Functions - * Use the following helper functions for default values - */ -type FlatListProps = {| - ...RequiredProps, - ...OptionalProps, -|}; - -type VirtualizedListProps = React.ElementConfig; - -export type Props = { - ...$Diff< - VirtualizedListProps, - { - getItem: $PropertyType, - getItemCount: $PropertyType, - getItemLayout: $PropertyType, - renderItem: $PropertyType, - keyExtractor: $PropertyType, - ... - }, - >, - ...FlatListProps, - ... -}; - -declare class FlatList extends React.PureComponent, void> { - scrollToEnd(params?: ?{animated?: ?boolean, ...}): void; - - scrollToIndex(params: { - animated?: ?boolean, - index: number, - viewOffset?: number, - viewPosition?: number, - ... - }): void; - scrollToItem(params: { - animated?: ?boolean, - item: ItemT, - viewPosition?: number, - ... - }): void; - scrollToOffset(params: {animated?: ?boolean, offset: number, ...}): void; - recordInteraction(): void; - - /** - * Displays the scroll indicators momentarily. - * - * @platform ios - */ - flashScrollIndicators(): void; - getScrollResponder(): ?ScrollResponderType; - getNativeScrollRef(): - | ?React.ElementRef - | ?React.ElementRef; - getScrollableNode(): any; - setNativeProps(props: {[string]: mixed, ...}): void; -} - -module.exports = FlatList; diff --git a/packages/react-native/Libraries/Lists/__tests__/__snapshots__/FlatList-test.js.snap b/packages/react-native/Libraries/Lists/__tests__/__snapshots__/FlatList-test.js.snap index 2fec3a235fb118..86901053a00d9f 100644 --- a/packages/react-native/Libraries/Lists/__tests__/__snapshots__/FlatList-test.js.snap +++ b/packages/react-native/Libraries/Lists/__tests__/__snapshots__/FlatList-test.js.snap @@ -111,6 +111,7 @@ exports[`FlatList renders all the bells and whistles 1`] = `
diff --git a/packages/react-native/Libraries/Lists/__tests__/__snapshots__/SectionList-test.js.snap b/packages/react-native/Libraries/Lists/__tests__/__snapshots__/SectionList-test.js.snap index ea1021883c1d92..a700cdb7be2a73 100644 --- a/packages/react-native/Libraries/Lists/__tests__/__snapshots__/SectionList-test.js.snap +++ b/packages/react-native/Libraries/Lists/__tests__/__snapshots__/SectionList-test.js.snap @@ -243,6 +243,7 @@ exports[`SectionList renders all the bells and whistles 1`] = `
prevOffset) { - const prevPart = content.substr( - prevOffset, - substitution.offset - prevOffset, - ); + const prevPart = content.slice(prevOffset, substitution.offset); createUnderLength(key, prevPart); } - const substitutionPart = content.substr( + const substitutionPart = content.slice( substitution.offset, - substitution.length, + substitution.offset + substitution.length, ); createUnderLength(key + '.5', substitutionPart, substitutionStyle); @@ -156,7 +153,7 @@ function LogBoxMessage(props: Props): React.Node { }, 0); if (lastOffset < content.length) { - const lastPart = content.substr(lastOffset); + const lastPart = content.slice(lastOffset); createUnderLength('-1', lastPart); } diff --git a/packages/react-native/Libraries/ReactNative/AppRegistry.d.ts b/packages/react-native/Libraries/ReactNative/AppRegistry.d.ts index fabfa126654537..b75715c6abc8ea 100644 --- a/packages/react-native/Libraries/ReactNative/AppRegistry.d.ts +++ b/packages/react-native/Libraries/ReactNative/AppRegistry.d.ts @@ -85,11 +85,6 @@ export namespace AppRegistry { displayMode?: number, ): void; - export function registerHeadlessTask( - appKey: string, - task: TaskProvider, - ): void; - export function getRunnable(appKey: string): Runnable | undefined; export function getRegistry(): {sections: string[]; runnables: Runnable[]}; diff --git a/packages/react-native/Libraries/ReactNative/ReactFabricPublicInstance/__tests__/ReactFabricPublicInstance-test.js b/packages/react-native/Libraries/ReactNative/ReactFabricPublicInstance/__tests__/ReactFabricPublicInstance-test.js index a9684999cc8101..ea645dd3c87e10 100644 --- a/packages/react-native/Libraries/ReactNative/ReactFabricPublicInstance/__tests__/ReactFabricPublicInstance-test.js +++ b/packages/react-native/Libraries/ReactNative/ReactFabricPublicInstance/__tests__/ReactFabricPublicInstance-test.js @@ -157,7 +157,7 @@ async function mockRenderKeys( }); describe('measure', () => { - test('component.measure(...) invokes callback', async () => { + itif(!isWindows)('component.measure(...) invokes callback', async () => { const result = await mockRenderKeys([['foo']]); const fooRef = nullthrows(result?.[0]?.[0]); @@ -170,7 +170,7 @@ async function mockRenderKeys( expect(callback.mock.calls).toEqual([[10, 10, 100, 100, 0, 0]]); }); - test('unmounted.measure(...) does nothing', async () => { + itif(!isWindows)('unmounted.measure(...) does nothing', async () => { const result = await mockRenderKeys([['foo'], null]); const fooRef = nullthrows(result?.[0]?.[0]); const callback = jest.fn(); @@ -184,18 +184,21 @@ async function mockRenderKeys( }); describe('measureInWindow', () => { - it('component.measureInWindow(...) invokes callback', async () => { - const result = await mockRenderKeys([['foo']]); - const fooRef = nullthrows(result?.[0]?.[0]); + itif(!isWindows)( + 'component.measureInWindow(...) invokes callback', + async () => { + const result = await mockRenderKeys([['foo']]); + const fooRef = nullthrows(result?.[0]?.[0]); - const callback = jest.fn(); - fooRef.measureInWindow(callback); + const callback = jest.fn(); + fooRef.measureInWindow(callback); - expect( - nullthrows(FabricUIManager.getFabricUIManager()).measureInWindow, - ).toHaveBeenCalledTimes(1); - expect(callback.mock.calls).toEqual([[10, 10, 100, 100]]); - }); + expect( + nullthrows(FabricUIManager.getFabricUIManager()).measureInWindow, + ).toHaveBeenCalledTimes(1); + expect(callback.mock.calls).toEqual([[10, 10, 100, 100]]); + }, + ); itif(!isWindows)( 'unmounted.measureInWindow(...) does nothing', @@ -215,71 +218,83 @@ async function mockRenderKeys( }); describe('measureLayout', () => { - test('component.measureLayout(component, ...) invokes callback', async () => { - const result = await mockRenderKeys([['foo', 'bar']]); - const fooRef = nullthrows(result?.[0]?.[0]); - const barRef = nullthrows(result?.[0]?.[1]); + itif(!isWindows)( + 'component.measureLayout(component, ...) invokes callback', + async () => { + const result = await mockRenderKeys([['foo', 'bar']]); + const fooRef = nullthrows(result?.[0]?.[0]); + const barRef = nullthrows(result?.[0]?.[1]); - const successCallback = jest.fn(); - const failureCallback = jest.fn(); - fooRef.measureLayout(barRef, successCallback, failureCallback); + const successCallback = jest.fn(); + const failureCallback = jest.fn(); + fooRef.measureLayout(barRef, successCallback, failureCallback); - expect( - nullthrows(FabricUIManager.getFabricUIManager()).measureLayout, - ).toHaveBeenCalledTimes(1); - expect(successCallback.mock.calls).toEqual([[1, 1, 100, 100]]); - }); + expect( + nullthrows(FabricUIManager.getFabricUIManager()).measureLayout, + ).toHaveBeenCalledTimes(1); + expect(successCallback.mock.calls).toEqual([[1, 1, 100, 100]]); + }, + ); - test('unmounted.measureLayout(component, ...) does nothing', async () => { - const result = await mockRenderKeys([ - ['foo', 'bar'], - ['foo', null], - ]); - const fooRef = nullthrows(result?.[0]?.[0]); - const barRef = nullthrows(result?.[0]?.[1]); + itif(!isWindows)( + 'unmounted.measureLayout(component, ...) does nothing', + async () => { + const result = await mockRenderKeys([ + ['foo', 'bar'], + ['foo', null], + ]); + const fooRef = nullthrows(result?.[0]?.[0]); + const barRef = nullthrows(result?.[0]?.[1]); - const successCallback = jest.fn(); - const failureCallback = jest.fn(); - fooRef.measureLayout(barRef, successCallback, failureCallback); + const successCallback = jest.fn(); + const failureCallback = jest.fn(); + fooRef.measureLayout(barRef, successCallback, failureCallback); - expect( - nullthrows(FabricUIManager.getFabricUIManager()).measureLayout, - ).not.toHaveBeenCalled(); - expect(successCallback).not.toHaveBeenCalled(); - }); + expect( + nullthrows(FabricUIManager.getFabricUIManager()).measureLayout, + ).not.toHaveBeenCalled(); + expect(successCallback).not.toHaveBeenCalled(); + }, + ); - test('component.measureLayout(unmounted, ...) does nothing', async () => { - const result = await mockRenderKeys([ - ['foo', 'bar'], - [null, 'bar'], - ]); - const fooRef = nullthrows(result?.[0]?.[0]); - const barRef = nullthrows(result?.[0]?.[1]); + itif(!isWindows)( + 'component.measureLayout(unmounted, ...) does nothing', + async () => { + const result = await mockRenderKeys([ + ['foo', 'bar'], + [null, 'bar'], + ]); + const fooRef = nullthrows(result?.[0]?.[0]); + const barRef = nullthrows(result?.[0]?.[1]); - const successCallback = jest.fn(); - const failureCallback = jest.fn(); - fooRef.measureLayout(barRef, successCallback, failureCallback); + const successCallback = jest.fn(); + const failureCallback = jest.fn(); + fooRef.measureLayout(barRef, successCallback, failureCallback); - expect( - nullthrows(FabricUIManager.getFabricUIManager()).measureLayout, - ).not.toHaveBeenCalled(); - expect(successCallback).not.toHaveBeenCalled(); - }); + expect( + nullthrows(FabricUIManager.getFabricUIManager()).measureLayout, + ).not.toHaveBeenCalled(); + expect(successCallback).not.toHaveBeenCalled(); + }, + ); - test('unmounted.measureLayout(unmounted, ...) does nothing', async () => { - const result = await mockRenderKeys([['foo', 'bar'], null]); - const fooRef = nullthrows(result?.[0]?.[0]); - const barRef = nullthrows(result?.[0]?.[1]); + itif(!isWindows)( + 'unmounted.measureLayout(unmounted, ...) does nothing', + async () => { + const result = await mockRenderKeys([['foo', 'bar'], null]); + const fooRef = nullthrows(result?.[0]?.[0]); + const barRef = nullthrows(result?.[0]?.[1]); - const successCallback = jest.fn(); - const failureCallback = jest.fn(); - fooRef.measureLayout(barRef, successCallback, failureCallback); + const successCallback = jest.fn(); + const failureCallback = jest.fn(); + fooRef.measureLayout(barRef, successCallback, failureCallback); - expect( - nullthrows(FabricUIManager.getFabricUIManager()).measureLayout, - ).not.toHaveBeenCalled(); - expect(successCallback).not.toHaveBeenCalled(); - }); + expect( + nullthrows(FabricUIManager.getFabricUIManager()).measureLayout, + ).not.toHaveBeenCalled(); + expect(successCallback).not.toHaveBeenCalled(); + }, + ); }); }); }); diff --git a/packages/react-native/Libraries/Renderer/REVISION b/packages/react-native/Libraries/Renderer/REVISION index 716da3a43fb9ee..c7aea0489414de 100644 --- a/packages/react-native/Libraries/Renderer/REVISION +++ b/packages/react-native/Libraries/Renderer/REVISION @@ -1 +1 @@ -58742c21b8c3237e8b66c7df4e200504846a01ae \ No newline at end of file +fda1f0b902b527089fe5ae7b3aa573c633166ec9 diff --git a/packages/react-native/Libraries/Renderer/shims/ReactFabric.js b/packages/react-native/Libraries/Renderer/shims/ReactFabric.js index 6ce97d99526678..8385a61ac40f4b 100644 --- a/packages/react-native/Libraries/Renderer/shims/ReactFabric.js +++ b/packages/react-native/Libraries/Renderer/shims/ReactFabric.js @@ -6,9 +6,8 @@ * * @noformat * @flow - * @generated SignedSource<> - * - * This file was sync'd from the facebook/react repository. + * @nolint + * @generated SignedSource<> */ 'use strict'; diff --git a/packages/react-native/Libraries/Renderer/shims/ReactFeatureFlags.js b/packages/react-native/Libraries/Renderer/shims/ReactFeatureFlags.js index 19914b304c53ac..d9d5a8b75ffbba 100644 --- a/packages/react-native/Libraries/Renderer/shims/ReactFeatureFlags.js +++ b/packages/react-native/Libraries/Renderer/shims/ReactFeatureFlags.js @@ -6,9 +6,8 @@ * * @noformat * @flow strict-local - * @generated SignedSource<<47062f1b1abd7428381f0362986d9c0e>> - * - * This file was sync'd from the facebook/react repository. + * @nolint + * @generated SignedSource<<2881c8e89ef0f73f4cf6612cb518b197>> */ 'use strict'; diff --git a/packages/react-native/Libraries/Renderer/shims/ReactNative.js b/packages/react-native/Libraries/Renderer/shims/ReactNative.js index e2cff0253cc08d..debaf0ae01cc34 100644 --- a/packages/react-native/Libraries/Renderer/shims/ReactNative.js +++ b/packages/react-native/Libraries/Renderer/shims/ReactNative.js @@ -6,9 +6,8 @@ * * @noformat * @flow - * @generated SignedSource<<744176db456e2656dac661d36e55f42a>> - * - * This file was sync'd from the facebook/react repository. + * @nolint + * @generated SignedSource<<0debd6e5a17dc037cb4661315a886de6>> */ 'use strict'; diff --git a/packages/react-native/Libraries/Renderer/shims/ReactNativeTypes.js b/packages/react-native/Libraries/Renderer/shims/ReactNativeTypes.js index 617344d3bf755d..c36c6bc9a8d196 100644 --- a/packages/react-native/Libraries/Renderer/shims/ReactNativeTypes.js +++ b/packages/react-native/Libraries/Renderer/shims/ReactNativeTypes.js @@ -6,9 +6,8 @@ * * @noformat * @flow strict - * @generated SignedSource<<31d4a4b65ed3b597c84dc2361d498e04>> - * - * This file was sync'd from the facebook/react repository. + * @nolint + * @generated SignedSource<<652b117c94307244bcf5e4af18928903>> */ import type {ElementRef, ElementType, Element, AbstractComponent} from 'react'; diff --git a/packages/react-native/Libraries/Renderer/shims/ReactNativeViewConfigRegistry.js b/packages/react-native/Libraries/Renderer/shims/ReactNativeViewConfigRegistry.js index 6fd96f25659a2d..74512b72977a3b 100644 --- a/packages/react-native/Libraries/Renderer/shims/ReactNativeViewConfigRegistry.js +++ b/packages/react-native/Libraries/Renderer/shims/ReactNativeViewConfigRegistry.js @@ -6,9 +6,8 @@ * * @noformat * @flow strict-local - * @generated SignedSource<<47ba85d7f43c9b591d6804827322d00e>> - * - * This file was sync'd from the facebook/react repository. + * @nolint + * @generated SignedSource<> */ 'use strict'; diff --git a/packages/react-native/Libraries/Renderer/shims/createReactNativeComponentClass.js b/packages/react-native/Libraries/Renderer/shims/createReactNativeComponentClass.js index 0b97635aa67869..a4b177e0ea6839 100644 --- a/packages/react-native/Libraries/Renderer/shims/createReactNativeComponentClass.js +++ b/packages/react-native/Libraries/Renderer/shims/createReactNativeComponentClass.js @@ -6,9 +6,8 @@ * * @noformat * @flow strict-local - * @generated SignedSource<> - * - * This file was sync'd from the facebook/react repository. + * @nolint + * @generated SignedSource<> */ 'use strict'; diff --git a/packages/react-native/Libraries/StyleSheet/StyleSheetTypes.d.ts b/packages/react-native/Libraries/StyleSheet/StyleSheetTypes.d.ts index df6b5c4afdaf86..8eb5e3c1e76ec7 100644 --- a/packages/react-native/Libraries/StyleSheet/StyleSheetTypes.d.ts +++ b/packages/react-native/Libraries/StyleSheet/StyleSheetTypes.d.ts @@ -18,7 +18,7 @@ type FlexAlignType = | 'stretch' | 'baseline'; -type DimensionValue = +export type DimensionValue = | number | 'auto' | `${number}%` @@ -69,13 +69,6 @@ export interface FlexStyle { flexShrink?: number | undefined; flexWrap?: 'wrap' | 'nowrap' | 'wrap-reverse' | undefined; height?: DimensionValue | undefined; - inset?: DimensionValue | undefined; - insetBlock?: DimensionValue | undefined; - insetBlockEnd?: DimensionValue | undefined; - insetBlockStart?: DimensionValue | undefined; - insetInline?: DimensionValue | undefined; - insetInlineEnd?: DimensionValue | undefined; - insetInlineStart?: DimensionValue | undefined; justifyContent?: | 'flex-start' | 'flex-end' @@ -86,15 +79,9 @@ export interface FlexStyle { | undefined; left?: DimensionValue | undefined; margin?: DimensionValue | undefined; - marginBlock?: DimensionValue | undefined; - marginBlockEnd?: DimensionValue | undefined; - marginBlockStart?: DimensionValue | undefined; marginBottom?: DimensionValue | undefined; marginEnd?: DimensionValue | undefined; marginHorizontal?: DimensionValue | undefined; - marginInline?: DimensionValue | undefined; - marginInlineEnd?: DimensionValue | undefined; - marginInlineStart?: DimensionValue | undefined; marginLeft?: DimensionValue | undefined; marginRight?: DimensionValue | undefined; marginStart?: DimensionValue | undefined; @@ -107,14 +94,8 @@ export interface FlexStyle { overflow?: 'visible' | 'hidden' | 'scroll' | undefined; padding?: DimensionValue | undefined; paddingBottom?: DimensionValue | undefined; - paddingBlock?: DimensionValue | undefined; - paddingBlockEnd?: DimensionValue | undefined; - paddingBlockStart?: DimensionValue | undefined; paddingEnd?: DimensionValue | undefined; paddingHorizontal?: DimensionValue | undefined; - paddingInline?: DimensionValue | undefined; - paddingInlineEnd?: DimensionValue | undefined; - paddingInlineStart?: DimensionValue | undefined; paddingLeft?: DimensionValue | undefined; paddingRight?: DimensionValue | undefined; paddingStart?: DimensionValue | undefined; diff --git a/packages/react-native/Libraries/TurboModule/TurboModuleRegistry.js b/packages/react-native/Libraries/TurboModule/TurboModuleRegistry.js index 27167a1347468a..a069106ff29084 100644 --- a/packages/react-native/Libraries/TurboModule/TurboModuleRegistry.js +++ b/packages/react-native/Libraries/TurboModule/TurboModuleRegistry.js @@ -16,22 +16,50 @@ const NativeModules = require('../BatchedBridge/NativeModules'); const turboModuleProxy = global.__turboModuleProxy; +const moduleLoadHistory = { + NativeModules: ([]: Array), + TurboModules: ([]: Array), + NotFound: ([]: Array), +}; + +function isBridgeless() { + return global.RN$Bridgeless === true; +} + +function isTurboModuleInteropEnabled() { + return global.RN$TurboInterop === true; +} + +function shouldReportLoadedModules() { + return isTurboModuleInteropEnabled(); +} + // TODO(148943970): Consider reversing the lookup here: // Lookup on __turboModuleProxy, then lookup on nativeModuleProxy function requireModule(name: string): ?T { - const isBridgeless = global.RN$Bridgeless === true; - const isTurboModuleInteropEnabled = global.RN$TurboInterop === true; - if (!isBridgeless || isTurboModuleInteropEnabled) { + if (!isBridgeless() || isTurboModuleInteropEnabled()) { // Backward compatibility layer during migration. const legacyModule = NativeModules[name]; if (legacyModule != null) { + if (shouldReportLoadedModules()) { + moduleLoadHistory.NativeModules.push(name); + } return ((legacyModule: $FlowFixMe): T); } } if (turboModuleProxy != null) { const module: ?T = turboModuleProxy(name); - return module; + if (module != null) { + if (shouldReportLoadedModules()) { + moduleLoadHistory.TurboModules.push(name); + } + return module; + } + } + + if (shouldReportLoadedModules()) { + moduleLoadHistory.NotFound.push(name); } return null; @@ -43,10 +71,14 @@ export function get(name: string): ?T { export function getEnforcing(name: string): T { const module = requireModule(name); - invariant( - module != null, + let message = `TurboModuleRegistry.getEnforcing(...): '${name}' could not be found. ` + - 'Verify that a module by this name is registered in the native binary.', - ); + 'Verify that a module by this name is registered in the native binary.'; + + if (shouldReportLoadedModules()) { + message += 'Modules loaded: ' + JSON.stringify(moduleLoadHistory); + } + + invariant(module != null, message); return module; } diff --git a/packages/react-native/Libraries/TypeSafety/RCTConvertHelpers.h b/packages/react-native/Libraries/TypeSafety/RCTConvertHelpers.h index d33f42c8ff18d8..f47ddeae42994c 100644 --- a/packages/react-native/Libraries/TypeSafety/RCTConvertHelpers.h +++ b/packages/react-native/Libraries/TypeSafety/RCTConvertHelpers.h @@ -13,12 +13,10 @@ #import -namespace facebook { -namespace react { +namespace facebook::react { template using LazyVector = FB::LazyVector; -} -} +} // namespace facebook::react template NSArray *RCTConvertVecToArray(const ContainerT &vec, id (^convertor)(typename ContainerT::value_type element)) diff --git a/packages/react-native/Libraries/TypeSafety/RCTTypedModuleConstants.h b/packages/react-native/Libraries/TypeSafety/RCTTypedModuleConstants.h index a787b6788ebc5d..d6a71e57ac9510 100644 --- a/packages/react-native/Libraries/TypeSafety/RCTTypedModuleConstants.h +++ b/packages/react-native/Libraries/TypeSafety/RCTTypedModuleConstants.h @@ -30,8 +30,7 @@ @end -namespace facebook { -namespace react { +namespace facebook::react { // Objective-C doesn't allow arbitrary types in its lightweight generics, only object and block types. We can work // around that by having the struct type we care about be a block-argument. The block never exists at runtime. @@ -45,5 +44,4 @@ ModuleConstants typedConstants(typename T::Builder::Input &&value) return [_RCTTypedModuleConstants newWithUnsafeDictionary:builder.buildUnsafeRawValue()]; } -} -} +} // namespace facebook::react diff --git a/packages/react-native/Libraries/Utilities/PolyfillFunctions.js b/packages/react-native/Libraries/Utilities/PolyfillFunctions.js index 61c6d8b8d491ac..09ae9658f7b561 100644 --- a/packages/react-native/Libraries/Utilities/PolyfillFunctions.js +++ b/packages/react-native/Libraries/Utilities/PolyfillFunctions.js @@ -32,7 +32,7 @@ function polyfillObjectProperty( ): void { const descriptor = Object.getOwnPropertyDescriptor<$FlowFixMe>(object, name); if (__DEV__ && descriptor) { - const backupName = `original${name[0].toUpperCase()}${name.substr(1)}`; + const backupName = `original${name[0].toUpperCase()}${name.slice(1)}`; Object.defineProperty(object, backupName, descriptor); } diff --git a/packages/react-native/Libraries/Utilities/createPerformanceLogger.js b/packages/react-native/Libraries/Utilities/createPerformanceLogger.js index 8891b4d1ac874c..0c09c750c7f094 100644 --- a/packages/react-native/Libraries/Utilities/createPerformanceLogger.js +++ b/packages/react-native/Libraries/Utilities/createPerformanceLogger.js @@ -16,7 +16,6 @@ import type { } from './IPerformanceLogger'; import * as Systrace from '../Performance/Systrace'; -import Performance from '../WebPerformance/Performance'; import infoLog from './infoLog'; const _cookies: {[key: string]: number, ...} = {}; @@ -27,9 +26,6 @@ const PRINT_TO_CONSOLE: false = false; // Type as false to prevent accidentally // used to separate these internally from other marks/measures const WEB_PERFORMANCE_PREFIX = 'global_perf_'; -// TODO: Remove once T143070419 is done -const performance = new Performance(); - export const getCurrentTimestamp: () => number = global.nativeQPLTimestamp ?? global.performance.now.bind(global.performance); diff --git a/packages/react-native/Libraries/WebPerformance/NativePerformance.cpp b/packages/react-native/Libraries/WebPerformance/NativePerformance.cpp index d08810da47c04e..e9ccdf332b6557 100644 --- a/packages/react-native/Libraries/WebPerformance/NativePerformance.cpp +++ b/packages/react-native/Libraries/WebPerformance/NativePerformance.cpp @@ -28,9 +28,8 @@ NativePerformance::NativePerformance(std::shared_ptr jsInvoker) void NativePerformance::mark( jsi::Runtime &rt, std::string name, - double startTime, - double duration) { - PerformanceEntryReporter::getInstance().mark(name, startTime, duration); + double startTime) { + PerformanceEntryReporter::getInstance().mark(name, startTime); } void NativePerformance::measure( diff --git a/packages/react-native/Libraries/WebPerformance/NativePerformance.h b/packages/react-native/Libraries/WebPerformance/NativePerformance.h index 4b334d7339b925..1726bb663f3f59 100644 --- a/packages/react-native/Libraries/WebPerformance/NativePerformance.h +++ b/packages/react-native/Libraries/WebPerformance/NativePerformance.h @@ -41,8 +41,7 @@ class NativePerformance : public NativePerformanceCxxSpec, public: NativePerformance(std::shared_ptr jsInvoker); - void - mark(jsi::Runtime &rt, std::string name, double startTime, double duration); + void mark(jsi::Runtime &rt, std::string name, double startTime); void measure( jsi::Runtime &rt, diff --git a/packages/react-native/Libraries/WebPerformance/NativePerformance.js b/packages/react-native/Libraries/WebPerformance/NativePerformance.js index 9a34b231299e4a..092b4ff6875c4b 100644 --- a/packages/react-native/Libraries/WebPerformance/NativePerformance.js +++ b/packages/react-native/Libraries/WebPerformance/NativePerformance.js @@ -22,7 +22,7 @@ export type ReactNativeStartupTiming = {| |}; export interface Spec extends TurboModule { - +mark: (name: string, startTime: number, duration: number) => void; + +mark: (name: string, startTime: number) => void; +measure: ( name: string, startTime: number, diff --git a/packages/react-native/Libraries/WebPerformance/Performance.js b/packages/react-native/Libraries/WebPerformance/Performance.js index 8e2ce32bd82f11..5b6fc03a1839a7 100644 --- a/packages/react-native/Libraries/WebPerformance/Performance.js +++ b/packages/react-native/Libraries/WebPerformance/Performance.js @@ -157,7 +157,7 @@ export default class Performance { const mark = new PerformanceMark(markName, markOptions); if (NativePerformance?.mark) { - NativePerformance.mark(markName, mark.startTime, mark.duration); + NativePerformance.mark(markName, mark.startTime); } else { warnNoNativePerformance(); } diff --git a/packages/react-native/Libraries/WebPerformance/PerformanceEntryReporter.cpp b/packages/react-native/Libraries/WebPerformance/PerformanceEntryReporter.cpp index 024178f344a39e..e223156ac94aa8 100644 --- a/packages/react-native/Libraries/WebPerformance/PerformanceEntryReporter.cpp +++ b/packages/react-native/Libraries/WebPerformance/PerformanceEntryReporter.cpp @@ -15,6 +15,10 @@ namespace facebook::react { EventTag PerformanceEntryReporter::sCurrentEventTag_{0}; +static inline double getCurrentTimeStamp() { + return JSExecutor::performanceNow(); +} + PerformanceEntryReporter &PerformanceEntryReporter::getInstance() { static PerformanceEntryReporter instance; return instance; @@ -68,7 +72,7 @@ GetPendingEntriesResult PerformanceEntryReporter::popPendingEntries() { } // Sort by starting time (or ending time, if starting times are equal) - std::sort( + std::stable_sort( res.entries.begin(), res.entries.end(), [](const RawPerformanceEntry &lhs, const RawPerformanceEntry &rhs) { @@ -134,13 +138,12 @@ void PerformanceEntryReporter::logEntry(const RawPerformanceEntry &entry) { void PerformanceEntryReporter::mark( const std::string &name, - double startTime, - double duration) { + const std::optional &startTime) { logEntry(RawPerformanceEntry{ name, static_cast(PerformanceEntryType::MARK), - startTime, - duration, + startTime ? *startTime : getCurrentTimeStamp(), + 0.0, std::nullopt, std::nullopt, std::nullopt}); @@ -352,7 +355,7 @@ EventTag PerformanceEntryReporter::onEventStart(const char *name) { sCurrentEventTag_ = 1; } - auto timeStamp = JSExecutor::performanceNow(); + auto timeStamp = getCurrentTimeStamp(); { std::lock_guard lock(eventsInFlightMutex_); eventsInFlight_.emplace(std::make_pair( @@ -365,7 +368,7 @@ void PerformanceEntryReporter::onEventDispatch(EventTag tag) { if (!isReporting(PerformanceEntryType::EVENT) || tag == 0) { return; } - auto timeStamp = JSExecutor::performanceNow(); + auto timeStamp = getCurrentTimeStamp(); { std::lock_guard lock(eventsInFlightMutex_); auto it = eventsInFlight_.find(tag); @@ -379,7 +382,7 @@ void PerformanceEntryReporter::onEventEnd(EventTag tag) { if (!isReporting(PerformanceEntryType::EVENT) || tag == 0) { return; } - auto timeStamp = JSExecutor::performanceNow(); + auto timeStamp = getCurrentTimeStamp(); { std::lock_guard lock(eventsInFlightMutex_); auto it = eventsInFlight_.find(tag); diff --git a/packages/react-native/Libraries/WebPerformance/PerformanceEntryReporter.h b/packages/react-native/Libraries/WebPerformance/PerformanceEntryReporter.h index 4ce7794078f8d8..8ea7c820e01893 100644 --- a/packages/react-native/Libraries/WebPerformance/PerformanceEntryReporter.h +++ b/packages/react-native/Libraries/WebPerformance/PerformanceEntryReporter.h @@ -111,7 +111,9 @@ class PerformanceEntryReporter : public EventLogger { return droppedEntryCount_; } - void mark(const std::string &name, double startTime, double duration); + void mark( + const std::string &name, + const std::optional &startTime = std::nullopt); void measure( const std::string &name, diff --git a/packages/react-native/Libraries/WebPerformance/__mocks__/NativePerformance.js b/packages/react-native/Libraries/WebPerformance/__mocks__/NativePerformance.js index 6b11a27a20a75c..b3335e0c774378 100644 --- a/packages/react-native/Libraries/WebPerformance/__mocks__/NativePerformance.js +++ b/packages/react-native/Libraries/WebPerformance/__mocks__/NativePerformance.js @@ -20,12 +20,12 @@ import {RawPerformanceEntryTypeValues} from '../RawPerformanceEntry'; const marks: Map = new Map(); const NativePerformanceMock: NativePerformance = { - mark: (name: string, startTime: number, duration: number): void => { + mark: (name: string, startTime: number): void => { NativePerformanceObserver?.logRawEntry({ name, entryType: RawPerformanceEntryTypeValues.MARK, startTime, - duration, + duration: 0, }); marks.set(name, startTime); }, diff --git a/packages/react-native/Libraries/WebPerformance/__tests__/PerformanceEntryReporterTest.cpp b/packages/react-native/Libraries/WebPerformance/__tests__/PerformanceEntryReporterTest.cpp index 9a6842eec2c623..c5895021ee6c88 100644 --- a/packages/react-native/Libraries/WebPerformance/__tests__/PerformanceEntryReporterTest.cpp +++ b/packages/react-native/Libraries/WebPerformance/__tests__/PerformanceEntryReporterTest.cpp @@ -54,9 +54,9 @@ TEST(PerformanceEntryReporter, PerformanceEntryReporterTestStopReporting) { reporter.startReporting(PerformanceEntryType::MARK); - reporter.mark("mark0", 0.0, 0.0); - reporter.mark("mark1", 0.0, 0.0); - reporter.mark("mark2", 0.0, 0.0); + reporter.mark("mark0", 0.0); + reporter.mark("mark1", 0.0); + reporter.mark("mark2", 0.0); reporter.measure("measure0", 0.0, 0.0); auto res = reporter.popPendingEntries(); @@ -73,7 +73,7 @@ TEST(PerformanceEntryReporter, PerformanceEntryReporterTestStopReporting) { reporter.stopReporting(PerformanceEntryType::MARK); reporter.startReporting(PerformanceEntryType::MEASURE); - reporter.mark("mark3", 0.0, 0.0); + reporter.mark("mark3"); reporter.measure("measure1", 0.0, 0.0); res = reporter.popPendingEntries(); @@ -91,9 +91,9 @@ TEST(PerformanceEntryReporter, PerformanceEntryReporterTestReportMarks) { reporter.startReporting(PerformanceEntryType::MARK); - reporter.mark("mark0", 0.0, 1.0); - reporter.mark("mark1", 1.0, 3.0); - reporter.mark("mark2", 2.0, 4.0); + reporter.mark("mark0", 0.0); + reporter.mark("mark1", 1.0); + reporter.mark("mark2", 2.0); auto res = reporter.popPendingEntries(); const auto &entries = res.entries; @@ -105,21 +105,21 @@ TEST(PerformanceEntryReporter, PerformanceEntryReporterTestReportMarks) { {"mark0", static_cast(PerformanceEntryType::MARK), 0.0, - 1.0, + 0.0, std::nullopt, std::nullopt, std::nullopt}, {"mark1", static_cast(PerformanceEntryType::MARK), 1.0, - 3.0, + 0.0, std::nullopt, std::nullopt, std::nullopt}, {"mark2", static_cast(PerformanceEntryType::MARK), 2.0, - 4.0, + 0.0, std::nullopt, std::nullopt, std::nullopt}}; @@ -136,9 +136,9 @@ TEST(PerformanceEntryReporter, PerformanceEntryReporterTestReportMeasures) { reporter.startReporting(PerformanceEntryType::MARK); reporter.startReporting(PerformanceEntryType::MEASURE); - reporter.mark("mark0", 0.0, 1.0); - reporter.mark("mark1", 1.0, 3.0); - reporter.mark("mark2", 2.0, 4.0); + reporter.mark("mark0", 0.0); + reporter.mark("mark1", 1.0); + reporter.mark("mark2", 2.0); reporter.measure("measure0", 0.0, 2.0); reporter.measure("measure1", 0.0, 2.0, 4.0); @@ -146,6 +146,10 @@ TEST(PerformanceEntryReporter, PerformanceEntryReporterTestReportMeasures) { reporter.measure("measure3", 0.0, 0.0, 5.0, "mark1"); reporter.measure("measure4", 1.5, 0.0, std::nullopt, std::nullopt, "mark2"); + reporter.mark("mark3", 2.0); + reporter.measure("measure5", 2.0, 2.0); + reporter.mark("mark4", 2.0); + auto res = reporter.popPendingEntries(); const auto &entries = res.entries; @@ -155,7 +159,7 @@ TEST(PerformanceEntryReporter, PerformanceEntryReporterTestReportMeasures) { {"mark0", static_cast(PerformanceEntryType::MARK), 0.0, - 1.0, + 0.0, std::nullopt, std::nullopt, std::nullopt}, @@ -173,17 +177,17 @@ TEST(PerformanceEntryReporter, PerformanceEntryReporterTestReportMeasures) { std::nullopt, std::nullopt, std::nullopt}, - {"measure2", - static_cast(PerformanceEntryType::MEASURE), - 1.0, + {"mark1", + static_cast(PerformanceEntryType::MARK), 1.0, + 0.0, std::nullopt, std::nullopt, std::nullopt}, - {"mark1", - static_cast(PerformanceEntryType::MARK), + {"measure2", + static_cast(PerformanceEntryType::MEASURE), + 1.0, 1.0, - 3.0, std::nullopt, std::nullopt, std::nullopt}, @@ -204,10 +208,32 @@ TEST(PerformanceEntryReporter, PerformanceEntryReporterTestReportMeasures) { {"mark2", static_cast(PerformanceEntryType::MARK), 2.0, - 4.0, + 0.0, std::nullopt, std::nullopt, - std::nullopt}}; + std::nullopt}, + {"mark3", + static_cast(PerformanceEntryType::MARK), + 2.0, + 0.0, + std::nullopt, + std::nullopt, + std::nullopt}, + {"mark4", + static_cast(PerformanceEntryType::MARK), + 2.0, + 0.0, + std::nullopt, + std::nullopt, + std::nullopt}, + {"measure5", + static_cast(PerformanceEntryType::MEASURE), + 2.0, + 0.0, + std::nullopt, + std::nullopt, + std::nullopt}, + }; ASSERT_EQ(expected, entries); } @@ -249,9 +275,9 @@ TEST(PerformanceEntryReporter, PerformanceEntryReporterTestGetEntries) { reporter.startReporting(PerformanceEntryType::MARK); reporter.startReporting(PerformanceEntryType::MEASURE); - reporter.mark("common_name", 0.0, 1.0); - reporter.mark("mark1", 1.0, 3.0); - reporter.mark("mark2", 2.0, 4.0); + reporter.mark("common_name", 0.0); + reporter.mark("mark1", 1.0); + reporter.mark("mark2", 2.0); reporter.measure("common_name", 0.0, 2.0); reporter.measure("measure1", 0.0, 2.0, 4.0); @@ -296,9 +322,9 @@ TEST(PerformanceEntryReporter, PerformanceEntryReporterTestClearEntries) { reporter.startReporting(PerformanceEntryType::MARK); reporter.startReporting(PerformanceEntryType::MEASURE); - reporter.mark("common_name", 0.0, 1.0); - reporter.mark("mark1", 1.0, 3.0); - reporter.mark("mark2", 2.0, 4.0); + reporter.mark("common_name", 0.0); + reporter.mark("mark1", 1.0); + reporter.mark("mark2", 2.0); reporter.measure("common_name", 0.0, 2.0); reporter.measure("measure1", 0.0, 2.0, 4.0); diff --git a/packages/react-native/React/Base/RCTBridge.h b/packages/react-native/React/Base/RCTBridge.h index 9df17ebc5528ea..2a55a8a730d33f 100644 --- a/packages/react-native/React/Base/RCTBridge.h +++ b/packages/react-native/React/Base/RCTBridge.h @@ -56,6 +56,14 @@ RCT_EXTERN void RCTEnableTurboModuleEagerInit(BOOL enabled); RCT_EXTERN BOOL RCTTurboModuleManagerDelegateLockingDisabled(void); RCT_EXTERN void RCTDisableTurboModuleManagerDelegateLocking(BOOL enabled); +// Turn on TurboModule interop +RCT_EXTERN BOOL RCTTurboModuleInteropEnabled(void); +RCT_EXTERN void RCTEnableTurboModuleInterop(BOOL enabled); + +// Route all TurboModules through TurboModule interop +RCT_EXTERN BOOL RCTTurboModuleInteropForAllTurboModulesEnabled(void); +RCT_EXTERN void RCTEnableTurboModuleInteropForAllTurboModules(BOOL enabled); + typedef enum { kRCTGlobalScope, kRCTGlobalScopeUsingRetainJSCallback, @@ -133,11 +141,11 @@ RCT_EXTERN void RCTSetTurboModuleCleanupMode(RCTTurboModuleCleanupMode mode); - (void)setRCTTurboModuleRegistry:(id)turboModuleRegistry; /** - * This hook is called by the TurboModule infra with every TurboModule that's created. - * It allows the bridge to attach properties to TurboModules that give TurboModules + * This hook is called by the TurboModule infra with every ObjC module that's created. + * It allows the bridge to attach properties to ObjC modules that give those modules * access to Bridge APIs. */ -- (void)attachBridgeAPIsToTurboModule:(id)module; +- (void)attachBridgeAPIsToObjCModule:(id)module; /** * Convenience method for retrieving all modules conforming to a given protocol. diff --git a/packages/react-native/React/Base/RCTBridge.m b/packages/react-native/React/Base/RCTBridge.m index 702e338aa5ac08..7308a6819b2e62 100644 --- a/packages/react-native/React/Base/RCTBridge.m +++ b/packages/react-native/React/Base/RCTBridge.m @@ -120,6 +120,26 @@ void RCTDisableTurboModuleManagerDelegateLocking(BOOL disabled) turboModuleManagerDelegateLockingDisabled = disabled; } +static BOOL turboModuleInteropEnabled = YES; +BOOL RCTTurboModuleInteropEnabled(void) +{ + return turboModuleInteropEnabled; +} +void RCTEnableTurboModuleInterop(BOOL enabled) +{ + turboModuleInteropEnabled = enabled; +} + +static BOOL useTurboModuleInteropForAllTurboModules = NO; +BOOL RCTTurboModuleInteropForAllTurboModulesEnabled(void) +{ + return useTurboModuleInteropForAllTurboModules; +} +void RCTEnableTurboModuleInteropForAllTurboModules(BOOL enabled) +{ + useTurboModuleInteropForAllTurboModules = enabled; +} + @interface RCTBridge () @end @@ -195,9 +215,9 @@ - (void)setRCTTurboModuleRegistry:(id)turboModuleRegistr [self.batchedBridge setRCTTurboModuleRegistry:turboModuleRegistry]; } -- (void)attachBridgeAPIsToTurboModule:(id)module +- (void)attachBridgeAPIsToObjCModule:(id)module { - [self.batchedBridge attachBridgeAPIsToTurboModule:module]; + [self.batchedBridge attachBridgeAPIsToObjCModule:module]; } - (void)didReceiveReloadCommand diff --git a/packages/react-native/React/Base/RCTBundleURLProvider.mm b/packages/react-native/React/Base/RCTBundleURLProvider.mm index d8ec3bcfa1e92f..f1dc797815c87d 100644 --- a/packages/react-native/React/Base/RCTBundleURLProvider.mm +++ b/packages/react-native/React/Base/RCTBundleURLProvider.mm @@ -265,10 +265,11 @@ + (NSURL *)jsBundleURLForBundleRoot:(NSString *)bundleRoot runModule:(BOOL)runModule { NSString *path = [NSString stringWithFormat:@"/%@.bundle", bundleRoot]; - + BOOL lazy = enableDev; // When we support only iOS 8 and above, use queryItems for a better API. - NSString *query = [NSString stringWithFormat:@"platform=ios&dev=%@&minify=%@&modulesOnly=%@&runModule=%@", + NSString *query = [NSString stringWithFormat:@"platform=ios&dev=%@&lazy=%@&minify=%@&modulesOnly=%@&runModule=%@", enableDev ? @"true" : @"false", + lazy ? @"true" : @"false", enableMinification ? @"true" : @"false", modulesOnly ? @"true" : @"false", runModule ? @"true" : @"false"]; diff --git a/packages/react-native/React/Base/RCTJSScriptLoaderModule.h b/packages/react-native/React/Base/RCTJSScriptLoaderModule.h deleted file mode 100644 index f05d361a579411..00000000000000 --- a/packages/react-native/React/Base/RCTJSScriptLoaderModule.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -@class RCTSource; - -NS_ASSUME_NONNULL_BEGIN - -/** - * This protocol should be adopted when a turbo module needs to tell React Native to load a script. - * In bridge-less React Native, it is a replacement for [_bridge loadAndExecuteSplitBundleURL:]. - */ -@protocol RCTJSScriptLoaderModule - -@property (nonatomic, copy) void (^loadScript)(RCTSource *source); - -@end - -NS_ASSUME_NONNULL_END diff --git a/packages/react-native/React/Base/RCTManagedPointer.h b/packages/react-native/React/Base/RCTManagedPointer.h index ff444d27e711ee..0579ae578801e3 100644 --- a/packages/react-native/React/Base/RCTManagedPointer.h +++ b/packages/react-native/React/Base/RCTManagedPointer.h @@ -24,8 +24,7 @@ @end -namespace facebook { -namespace react { +namespace facebook::react { template RCTManagedPointer *managedPointer(P initializer) @@ -34,7 +33,6 @@ RCTManagedPointer *managedPointer(P initializer) return [[RCTManagedPointer alloc] initWithPointer:std::move(ptr)]; } -} -} +} // namespace facebook::react #endif diff --git a/packages/react-native/React/Base/RCTRootView.h b/packages/react-native/React/Base/RCTRootView.h index 32eeb7ab007dcb..6ed9c5b8fc48f2 100644 --- a/packages/react-native/React/Base/RCTRootView.h +++ b/packages/react-native/React/Base/RCTRootView.h @@ -133,6 +133,11 @@ extern */ @property (nonatomic, weak, nullable) UIViewController *reactViewController; +/** + * The root view casted as UIView. Used by splash screen libraries. + */ +@property (nonatomic, strong, readonly) UIView *view; + /** * The React-managed contents view of the root view. */ diff --git a/packages/react-native/React/Base/RCTRootView.m b/packages/react-native/React/Base/RCTRootView.m index 5cb98b5ce9794d..a7b9b22881543f 100644 --- a/packages/react-native/React/Base/RCTRootView.m +++ b/packages/react-native/React/Base/RCTRootView.m @@ -116,6 +116,11 @@ - (instancetype)initWithBundleURL:(NSURL *)bundleURL RCT_NOT_IMPLEMENTED(-(instancetype)initWithFrame : (CGRect)frame) RCT_NOT_IMPLEMENTED(-(instancetype)initWithCoder : (NSCoder *)aDecoder) +- (UIView *)view +{ + return self; +} + - (BOOL)hasBridge { return _bridge != nil; diff --git a/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingProxyRootView.h b/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingProxyRootView.h index 3b2f7911464015..bb5a574e2ee1f5 100644 --- a/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingProxyRootView.h +++ b/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingProxyRootView.h @@ -34,6 +34,7 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, assign) RCTRootViewSizeFlexibility sizeFlexibility; @property (nonatomic, weak) id delegate; @property (nonatomic, weak) UIViewController *reactViewController; +@property (nonatomic, strong, readonly) UIView *view; @property (nonatomic, strong, readonly) UIView *contentView; @property (nonatomic, strong) UIView *loadingView; @property (nonatomic, assign) BOOL passThroughTouches; diff --git a/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingProxyRootView.mm b/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingProxyRootView.mm index 8f48551167f398..91ead4e7492774 100644 --- a/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingProxyRootView.mm +++ b/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingProxyRootView.mm @@ -134,6 +134,11 @@ - (NSString *)moduleName return super.surface.moduleName; } +- (UIView *)view +{ + return (UIView *)super.surface.view; +} + - (UIView *)contentView { return self; diff --git a/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.mm b/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.mm index 8fd40462a2377a..1056ff08dbbae7 100644 --- a/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.mm +++ b/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.mm @@ -74,9 +74,9 @@ - (void)dealloc [_surface stop]; } -- (void)setFrame:(CGRect)frame +- (void)layoutSubviews { - [super setFrame:frame]; + [super layoutSubviews]; CGSize minimumSize; CGSize maximumSize; diff --git a/packages/react-native/React/CoreModules/RCTDevLoadingView.mm b/packages/react-native/React/CoreModules/RCTDevLoadingView.mm index 8ad0fc0d327562..8ea5edb281225e 100644 --- a/packages/react-native/React/CoreModules/RCTDevLoadingView.mm +++ b/packages/react-native/React/CoreModules/RCTDevLoadingView.mm @@ -25,7 +25,7 @@ @interface RCTDevLoadingView () @end -#if RCT_DEV | RCT_ENABLE_LOADING_VIEW +#if RCT_DEV_MENU @implementation RCTDevLoadingView { UIWindow *_window; @@ -35,8 +35,6 @@ @implementation RCTDevLoadingView { dispatch_block_t _initialMessageBlock; } -@synthesize bundleManager = _bundleManager; - RCT_EXPORT_MODULE() - (instancetype)init @@ -85,25 +83,6 @@ - (void)showInitialMessageDelayed:(void (^)())initialMessage dispatch_time(DISPATCH_TIME_NOW, 0.2 * NSEC_PER_SEC), dispatch_get_main_queue(), self->_initialMessageBlock); } -- (UIColor *)dimColor:(UIColor *)c -{ - // Given a color, return a slightly lighter or darker color for dim effect. - CGFloat h, s, b, a; - if ([c getHue:&h saturation:&s brightness:&b alpha:&a]) - return [UIColor colorWithHue:h saturation:s brightness:b < 0.5 ? b * 1.25 : b * 0.75 alpha:a]; - return nil; -} - -- (NSString *)getTextForHost -{ - NSURL *bundleURL = _bundleManager.bundleURL; - if (bundleURL == nil || bundleURL.fileURL) { - return @"React Native"; - } - - return [NSString stringWithFormat:@"%@:%@", bundleURL.host, bundleURL.port]; -} - - (void)showMessage:(NSString *)message color:(UIColor *)color backgroundColor:(UIColor *)backgroundColor { if (!RCTDevLoadingViewGetEnabled() || self->_hiding) { diff --git a/packages/react-native/React/CoreModules/RCTDevMenu.mm b/packages/react-native/React/CoreModules/RCTDevMenu.mm index 17c2e874c103c4..f40cf4febf25af 100644 --- a/packages/react-native/React/CoreModules/RCTDevMenu.mm +++ b/packages/react-native/React/CoreModules/RCTDevMenu.mm @@ -284,46 +284,8 @@ - (void)setDefaultJSBundle withBundleURL:bundleManager.bundleURL withErrorMessage:@"Failed to open Flipper. Please check that Metro is running."]; }]]; - } else if (devSettings.isRemoteDebuggingAvailable) { -#else - if (devSettings.isRemoteDebuggingAvailable) { -#endif - // For remote debugging, we open up Chrome running the app in a web worker. - // Note that this requires async communication, which will not work for Turbo Modules. - [items addObject:[RCTDevMenuItem - buttonItemWithTitleBlock:^NSString * { - return devSettings.isDebuggingRemotely ? @"Stop Debugging" : @"Debug with Chrome"; - } - handler:^{ - devSettings.isDebuggingRemotely = !devSettings.isDebuggingRemotely; - }]]; - } else { - // If neither are available, we're defaulting to a message that tells you about remote debugging. - [items - addObject:[RCTDevMenuItem - buttonItemWithTitle:@"Debugger Unavailable" - handler:^{ - NSString *message = RCTTurboModuleEnabled() - ? @"Debugging with Chrome is not supported when TurboModules are enabled." - : @"Include the RCTWebSocket library to enable JavaScript debugging."; - UIAlertController *alertController = - [UIAlertController alertControllerWithTitle:@"Debugger Unavailable" - message:message - preferredStyle:UIAlertControllerStyleAlert]; - __weak __typeof__(alertController) weakAlertController = alertController; - [alertController - addAction:[UIAlertAction actionWithTitle:@"OK" - style:UIAlertActionStyleDefault - handler:^(__unused UIAlertAction *action) { - [weakAlertController - dismissViewControllerAnimated:YES - completion:nil]; - }]]; - [RCTPresentedViewController() presentViewController:alertController - animated:YES - completion:NULL]; - }]]; } +#endif } [items addObject:[RCTDevMenuItem @@ -428,10 +390,10 @@ - (void)setDefaultJSBundle ? UIAlertControllerStyleActionSheet : UIAlertControllerStyleAlert; - NSString *debugMenuType = self.bridge ? @"Bridge" : @"Bridgeless"; - NSString *debugMenuTitle = [NSString stringWithFormat:@"React Native Debug Menu (%@)", debugMenuType]; + NSString *devMenuType = self.bridge ? @"Bridge" : @"Bridgeless"; + NSString *devMenuTitle = [NSString stringWithFormat:@"React Native Dev Menu (%@)", devMenuType]; - _actionSheet = [UIAlertController alertControllerWithTitle:debugMenuTitle message:description preferredStyle:style]; + _actionSheet = [UIAlertController alertControllerWithTitle:devMenuTitle message:description preferredStyle:style]; NSArray *items = [self _menuItemsToPresent]; for (RCTDevMenuItem *item in items) { diff --git a/packages/react-native/React/CoreModules/RCTDevSettings.mm b/packages/react-native/React/CoreModules/RCTDevSettings.mm index e19a810d877364..d9b03ed38744b2 100644 --- a/packages/react-native/React/CoreModules/RCTDevSettings.mm +++ b/packages/react-native/React/CoreModules/RCTDevSettings.mm @@ -394,13 +394,9 @@ - (void)_profilingSettingDidChange #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" if (enabled) { - if (self.callableJSModules) { - [self.callableJSModules invokeModule:@"HMRClient" method:@"enable" withArgs:@[]]; - } + [self.callableJSModules invokeModule:@"HMRClient" method:@"enable" withArgs:@[]]; } else { - if (self.callableJSModules) { - [self.callableJSModules invokeModule:@"HMRClient" method:@"disable" withArgs:@[]]; - } + [self.callableJSModules invokeModule:@"HMRClient" method:@"disable" withArgs:@[]]; } #pragma clang diagnostic pop } @@ -483,22 +479,18 @@ - (void)setupHMRClientWithBundleURL:(NSURL *)bundleURL NSNumber *const port = urlComponents.port; NSString *const scheme = urlComponents.scheme; BOOL isHotLoadingEnabled = self.isHotLoadingEnabled; - if (self.callableJSModules) { - [self.callableJSModules invokeModule:@"HMRClient" - method:@"setup" - withArgs:@[ @"ios", path, host, RCTNullIfNil(port), @(isHotLoadingEnabled), scheme ]]; - } + [self.callableJSModules invokeModule:@"HMRClient" + method:@"setup" + withArgs:@[ @"ios", path, host, RCTNullIfNil(port), @(isHotLoadingEnabled), scheme ]]; } } - (void)setupHMRClientWithAdditionalBundleURL:(NSURL *)bundleURL { if (bundleURL && !bundleURL.fileURL) { // isHotLoadingAvailable check - if (self.callableJSModules) { - [self.callableJSModules invokeModule:@"HMRClient" - method:@"registerBundle" - withArgs:@[ [bundleURL absoluteString] ]]; - } + [self.callableJSModules invokeModule:@"HMRClient" + method:@"registerBundle" + withArgs:@[ [bundleURL absoluteString] ]]; } } diff --git a/packages/react-native/React/CoreModules/RCTSourceCode.mm b/packages/react-native/React/CoreModules/RCTSourceCode.mm index 2589b34d3daafc..ad5008429f8928 100644 --- a/packages/react-native/React/CoreModules/RCTSourceCode.mm +++ b/packages/react-native/React/CoreModules/RCTSourceCode.mm @@ -9,8 +9,6 @@ #import -#import - #import "CoreModulesPlugins.h" using namespace facebook::react; @@ -22,7 +20,6 @@ @implementation RCTSourceCode RCT_EXPORT_MODULE() -@synthesize bridge = _bridge; @synthesize bundleManager = _bundleManager; + (BOOL)requiresMainQueueSetup diff --git a/packages/react-native/React/CxxBridge/JSCExecutorFactory.h b/packages/react-native/React/CxxBridge/JSCExecutorFactory.h index 17b64037c72ef5..902b44e7049645 100644 --- a/packages/react-native/React/CxxBridge/JSCExecutorFactory.h +++ b/packages/react-native/React/CxxBridge/JSCExecutorFactory.h @@ -9,8 +9,7 @@ #include -namespace facebook { -namespace react { +namespace facebook::react { class JSCExecutorFactory : public JSExecutorFactory { public: @@ -25,5 +24,4 @@ class JSCExecutorFactory : public JSExecutorFactory { JSIExecutor::RuntimeInstaller runtimeInstaller_; }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/React/CxxBridge/JSCExecutorFactory.mm b/packages/react-native/React/CxxBridge/JSCExecutorFactory.mm index 78584cd4e6c121..6173ae5ccffac4 100644 --- a/packages/react-native/React/CxxBridge/JSCExecutorFactory.mm +++ b/packages/react-native/React/CxxBridge/JSCExecutorFactory.mm @@ -11,8 +11,7 @@ #import -namespace facebook { -namespace react { +namespace facebook::react { std::unique_ptr JSCExecutorFactory::createJSExecutor( std::shared_ptr delegate, @@ -22,5 +21,4 @@ facebook::jsc::makeJSCRuntime(), delegate, JSIExecutor::defaultTimeoutInvoker, runtimeInstaller_); } -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/React/CxxBridge/NSDataBigString.h b/packages/react-native/React/CxxBridge/NSDataBigString.h index c7f5ae7f61eac4..b8c571f8182607 100644 --- a/packages/react-native/React/CxxBridge/NSDataBigString.h +++ b/packages/react-native/React/CxxBridge/NSDataBigString.h @@ -9,8 +9,7 @@ #include -namespace facebook { -namespace react { +namespace facebook::react { class NSDataBigString : public JSBigString { public: @@ -38,5 +37,4 @@ class NSDataBigString : public JSBigString { size_t m_length; }; -} -} +} // namespace facebook::react diff --git a/packages/react-native/React/CxxBridge/NSDataBigString.mm b/packages/react-native/React/CxxBridge/NSDataBigString.mm index 5708fa78a24306..620d97ecf3b0a8 100644 --- a/packages/react-native/React/CxxBridge/NSDataBigString.mm +++ b/packages/react-native/React/CxxBridge/NSDataBigString.mm @@ -7,8 +7,7 @@ #import "NSDataBigString.h" -namespace facebook { -namespace react { +namespace facebook::react { static NSData *ensureNullTerminated(NSData *source) { @@ -39,5 +38,4 @@ m_data = ensureNullTerminated(data); } -} -} +} // namespace facebook::react diff --git a/packages/react-native/React/CxxBridge/RCTCxxBridge.mm b/packages/react-native/React/CxxBridge/RCTCxxBridge.mm index 45c29a24fc9467..d47c4aece7d309 100644 --- a/packages/react-native/React/CxxBridge/RCTCxxBridge.mm +++ b/packages/react-native/React/CxxBridge/RCTCxxBridge.mm @@ -64,7 +64,7 @@ #import #endif -#if (RCT_DEV | RCT_ENABLE_LOADING_VIEW) && __has_include() +#if RCT_DEV_MENU && __has_include() #import #endif @@ -245,14 +245,14 @@ - (void)setRCTTurboModuleRegistry:(id)turboModuleRegistr [_objCModuleRegistry setTurboModuleRegistry:_turboModuleRegistry]; } -- (void)attachBridgeAPIsToTurboModule:(id)module +- (void)attachBridgeAPIsToObjCModule:(id)module { RCTBridgeModuleDecorator *bridgeModuleDecorator = [[RCTBridgeModuleDecorator alloc] initWithViewRegistry:_viewRegistry_DEPRECATED moduleRegistry:_objCModuleRegistry bundleManager:_bundleManager callableJSModules:_callableJSModules]; - [bridgeModuleDecorator attachInteropAPIsToModule:(id)module]; + [bridgeModuleDecorator attachInteropAPIsToModule:module]; } - (std::shared_ptr)jsMessageThread @@ -476,7 +476,7 @@ - (void)start dispatch_group_enter(prepareBridge); __block NSData *sourceCode; -#if (RCT_DEV | RCT_ENABLE_LOADING_VIEW) && __has_include() +#if RCT_DEV_MENU && __has_include() { id loadingView = [self moduleForName:@"DevLoadingView" lazilyLoadIfNecessary:YES]; [loadingView showWithURL:self.bundleURL]; @@ -493,7 +493,7 @@ - (void)start dispatch_group_leave(prepareBridge); } onProgress:^(RCTLoadingProgress *progressData) { -#if (RCT_DEV | RCT_ENABLE_LOADING_VIEW) && __has_include() +#if RCT_DEV_MENU && __has_include() id loadingView = [weakSelf moduleForName:@"DevLoadingView" lazilyLoadIfNecessary:YES]; [loadingView updateProgress:progressData]; @@ -1092,7 +1092,7 @@ - (void)loadAndExecuteSplitBundleURL:(NSURL *)bundleURL __weak __typeof(self) weakSelf = self; [RCTJavaScriptLoader loadBundleAtURL:bundleURL onProgress:^(RCTLoadingProgress *progressData) { -#if (RCT_DEV_MENU | RCT_ENABLE_LOADING_VIEW) && __has_include() +#if (RCT_DEV_MENU | RCT_DEV_MENU) && __has_include() id loadingView = [weakSelf moduleForName:@"DevLoadingView" lazilyLoadIfNecessary:YES]; [loadingView updateProgress:progressData]; diff --git a/packages/react-native/React/CxxBridge/RCTCxxBridgeDelegate.h b/packages/react-native/React/CxxBridge/RCTCxxBridgeDelegate.h index 0285b70f217ee8..e2d48db4548d57 100644 --- a/packages/react-native/React/CxxBridge/RCTCxxBridgeDelegate.h +++ b/packages/react-native/React/CxxBridge/RCTCxxBridgeDelegate.h @@ -9,13 +9,11 @@ #import -namespace facebook { -namespace react { +namespace facebook::react { class JSExecutorFactory; -} -} +} // namespace facebook::react // This is a separate class so non-C++ implementations don't need to // take a C++ dependency. diff --git a/packages/react-native/React/CxxBridge/RCTJSIExecutorRuntimeInstaller.h b/packages/react-native/React/CxxBridge/RCTJSIExecutorRuntimeInstaller.h index 2a40f8316ba2d4..a258102a21fff0 100644 --- a/packages/react-native/React/CxxBridge/RCTJSIExecutorRuntimeInstaller.h +++ b/packages/react-native/React/CxxBridge/RCTJSIExecutorRuntimeInstaller.h @@ -9,8 +9,7 @@ #include -namespace facebook { -namespace react { +namespace facebook::react { /** * Creates a lambda used to bind a JSIRuntime in the context of @@ -19,5 +18,4 @@ namespace react { JSIExecutor::RuntimeInstaller RCTJSIExecutorRuntimeInstaller( JSIExecutor::RuntimeInstaller runtimeInstallerToWrap); -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/React/CxxBridge/RCTJSIExecutorRuntimeInstaller.mm b/packages/react-native/React/CxxBridge/RCTJSIExecutorRuntimeInstaller.mm index 0372d4190167d8..5212cdd47af90c 100644 --- a/packages/react-native/React/CxxBridge/RCTJSIExecutorRuntimeInstaller.mm +++ b/packages/react-native/React/CxxBridge/RCTJSIExecutorRuntimeInstaller.mm @@ -10,8 +10,7 @@ #import #include -namespace facebook { -namespace react { +namespace facebook::react { JSIExecutor::RuntimeInstaller RCTJSIExecutorRuntimeInstaller(JSIExecutor::RuntimeInstaller runtimeInstallerToWrap) { @@ -29,5 +28,4 @@ }; } -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/React/CxxBridge/RCTMessageThread.h b/packages/react-native/React/CxxBridge/RCTMessageThread.h index c68fc281a405ce..cbd85025c9f8e4 100644 --- a/packages/react-native/React/CxxBridge/RCTMessageThread.h +++ b/packages/react-native/React/CxxBridge/RCTMessageThread.h @@ -13,8 +13,7 @@ #import #import -namespace facebook { -namespace react { +namespace facebook::react { class RCTMessageThread : public MessageQueueThread, public std::enable_shared_from_this { @@ -36,5 +35,4 @@ class RCTMessageThread : public MessageQueueThread, std::atomic_bool m_shutdown; }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/React/CxxBridge/RCTMessageThread.mm b/packages/react-native/React/CxxBridge/RCTMessageThread.mm index 48b2a604e7ea00..d234aaaa8cfd43 100644 --- a/packages/react-native/React/CxxBridge/RCTMessageThread.mm +++ b/packages/react-native/React/CxxBridge/RCTMessageThread.mm @@ -20,8 +20,7 @@ // particular, the sync functions are only used for bridge setup and // teardown, and quitSynchronous is guaranteed to be called. -namespace facebook { -namespace react { +namespace facebook::react { RCTMessageThread::RCTMessageThread(NSRunLoop *runLoop, RCTJavaScriptCompleteBlock errorBlock) : m_cfRunLoop([runLoop getCFRunLoop]), m_errorBlock(errorBlock), m_shutdown(false) @@ -110,5 +109,4 @@ CFRetain(m_cfRunLoop); } -} -} +} // namespace facebook::react diff --git a/packages/react-native/React/CxxBridge/RCTObjcExecutor.h b/packages/react-native/React/CxxBridge/RCTObjcExecutor.h index 9cba372d4b0fae..87ad0858f505d0 100644 --- a/packages/react-native/React/CxxBridge/RCTObjcExecutor.h +++ b/packages/react-native/React/CxxBridge/RCTObjcExecutor.h @@ -12,8 +12,7 @@ #import #import -namespace facebook { -namespace react { +namespace facebook::react { class RCTObjcExecutorFactory : public JSExecutorFactory { public: @@ -29,5 +28,4 @@ class RCTObjcExecutorFactory : public JSExecutorFactory { RCTJavaScriptCompleteBlock m_errorBlock; }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/React/CxxBridge/RCTObjcExecutor.mm b/packages/react-native/React/CxxBridge/RCTObjcExecutor.mm index df22d637bde3e6..0aa453803cf79b 100644 --- a/packages/react-native/React/CxxBridge/RCTObjcExecutor.mm +++ b/packages/react-native/React/CxxBridge/RCTObjcExecutor.mm @@ -20,8 +20,7 @@ #import #import -namespace facebook { -namespace react { +namespace facebook::react { namespace { @@ -144,5 +143,4 @@ virtual void setGlobalVariable(std::string propName, std::unique_ptr(new RCTObjcExecutor(m_jse, m_errorBlock, jsQueue, delegate)); } -} -} +} // namespace facebook::react diff --git a/packages/react-native/React/CxxLogUtils/RCTDefaultCxxLogFunction.h b/packages/react-native/React/CxxLogUtils/RCTDefaultCxxLogFunction.h index 2c745d5e7eded2..36a2abad2429f9 100644 --- a/packages/react-native/React/CxxLogUtils/RCTDefaultCxxLogFunction.h +++ b/packages/react-native/React/CxxLogUtils/RCTDefaultCxxLogFunction.h @@ -9,10 +9,8 @@ #import -namespace facebook { -namespace react { +namespace facebook::react { void RCTDefaultCxxLogFunction(ReactNativeLogLevel level, const char *message); -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/React/CxxLogUtils/RCTDefaultCxxLogFunction.mm b/packages/react-native/React/CxxLogUtils/RCTDefaultCxxLogFunction.mm index 449c7b3b3a37fb..a9f172cb344c2d 100644 --- a/packages/react-native/React/CxxLogUtils/RCTDefaultCxxLogFunction.mm +++ b/packages/react-native/React/CxxLogUtils/RCTDefaultCxxLogFunction.mm @@ -9,8 +9,7 @@ #import #import -namespace facebook { -namespace react { +namespace facebook::react { void RCTDefaultCxxLogFunction(ReactNativeLogLevel level, const char *message) { @@ -35,5 +34,4 @@ void RCTDefaultCxxLogFunction(ReactNativeLogLevel level, const char *message) } } -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/React/CxxModule/DispatchMessageQueueThread.h b/packages/react-native/React/CxxModule/DispatchMessageQueueThread.h index 76eaa15fd975b9..a8b755bd52c54e 100644 --- a/packages/react-native/React/CxxModule/DispatchMessageQueueThread.h +++ b/packages/react-native/React/CxxModule/DispatchMessageQueueThread.h @@ -10,8 +10,7 @@ #include #include -namespace facebook { -namespace react { +namespace facebook::react { // RCTNativeModule arranges for native methods to be invoked on a queue which // is not the JS thread. C++ modules don't use RCTNativeModule, so this little @@ -43,5 +42,4 @@ class DispatchMessageQueueThread : public MessageQueueThread { RCTModuleData *moduleData_; }; -} -} +} // namespace facebook::react diff --git a/packages/react-native/React/CxxModule/RCTCxxModule.h b/packages/react-native/React/CxxModule/RCTCxxModule.h index 75d95a30901d97..093aafee890bfe 100644 --- a/packages/react-native/React/CxxModule/RCTCxxModule.h +++ b/packages/react-native/React/CxxModule/RCTCxxModule.h @@ -11,13 +11,9 @@ #import -namespace facebook { -namespace xplat { -namespace module { +namespace facebook::xplat::module { class CxxModule; -} -} -} +} // namespace facebook::react::module /** * Subclass RCTCxxModule to use cross-platform CxxModule on iOS. diff --git a/packages/react-native/React/CxxModule/RCTCxxUtils.h b/packages/react-native/React/CxxModule/RCTCxxUtils.h index cc1454f07601ff..b4411088e19f5c 100644 --- a/packages/react-native/React/CxxModule/RCTCxxUtils.h +++ b/packages/react-native/React/CxxModule/RCTCxxUtils.h @@ -13,8 +13,7 @@ @class RCTBridge; @class RCTModuleData; -namespace facebook { -namespace react { +namespace facebook::react { class Instance; class NativeModule; @@ -25,5 +24,4 @@ createNativeModules(NSArray *modules, RCTBridge *bridge, const NSError *tryAndReturnError(const std::function &func); NSString *deriveSourceURL(NSURL *url); -} -} +} // namespace facebook::react diff --git a/packages/react-native/React/CxxModule/RCTCxxUtils.mm b/packages/react-native/React/CxxModule/RCTCxxUtils.mm index 03f0ad0c83d8df..efb1f1a105c53b 100644 --- a/packages/react-native/React/CxxModule/RCTCxxUtils.mm +++ b/packages/react-native/React/CxxModule/RCTCxxUtils.mm @@ -17,8 +17,7 @@ #import "RCTCxxModule.h" #import "RCTNativeModule.h" -namespace facebook { -namespace react { +namespace facebook::react { using facebook::jsi::JSError; @@ -101,5 +100,4 @@ return sourceUrl ?: @""; } -} -} +} // namespace facebook::react diff --git a/packages/react-native/React/CxxModule/RCTNativeModule.h b/packages/react-native/React/CxxModule/RCTNativeModule.h index a83b16dd7b79c0..730839a9b52e08 100644 --- a/packages/react-native/React/CxxModule/RCTNativeModule.h +++ b/packages/react-native/React/CxxModule/RCTNativeModule.h @@ -8,8 +8,7 @@ #import #import -namespace facebook { -namespace react { +namespace facebook::react { class RCTNativeModule : public NativeModule { public: @@ -30,5 +29,4 @@ class RCTNativeModule : public NativeModule { RCTModuleData *m_moduleData; }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/React/CxxModule/RCTNativeModule.mm b/packages/react-native/React/CxxModule/RCTNativeModule.mm index f400d6968d69ec..3f86bc87cb1c6a 100644 --- a/packages/react-native/React/CxxModule/RCTNativeModule.mm +++ b/packages/react-native/React/CxxModule/RCTNativeModule.mm @@ -26,8 +26,7 @@ enum SchedulingContext { Sync, Async }; } -namespace facebook { -namespace react { +namespace facebook::react { static MethodCallResult invokeInner( RCTBridge *bridge, @@ -235,5 +234,4 @@ static MethodCallResult invokeInner( return std::nullopt; } -} -} +} // namespace facebook::react diff --git a/packages/react-native/React/CxxUtils/RCTFollyConvert.h b/packages/react-native/React/CxxUtils/RCTFollyConvert.h index 7a0c239539769d..7da61aa9bd55a6 100644 --- a/packages/react-native/React/CxxUtils/RCTFollyConvert.h +++ b/packages/react-native/React/CxxUtils/RCTFollyConvert.h @@ -9,11 +9,9 @@ #include -namespace facebook { -namespace react { +namespace facebook::react { folly::dynamic convertIdToFollyDynamic(id json); id convertFollyDynamicToId(const folly::dynamic &dyn); -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/React/CxxUtils/RCTFollyConvert.mm b/packages/react-native/React/CxxUtils/RCTFollyConvert.mm index 4e881970903207..255c16422603ab 100644 --- a/packages/react-native/React/CxxUtils/RCTFollyConvert.mm +++ b/packages/react-native/React/CxxUtils/RCTFollyConvert.mm @@ -10,8 +10,7 @@ #import #import -namespace facebook { -namespace react { +namespace facebook::react { id convertFollyDynamicToId(const folly::dynamic &dyn) { @@ -114,5 +113,4 @@ id convertFollyDynamicToId(const folly::dynamic &dyn) return nil; } -} -} +} // namespace facebook::react diff --git a/packages/react-native/React/DevSupport/RCTDevLoadingViewSetEnabled.m b/packages/react-native/React/DevSupport/RCTDevLoadingViewSetEnabled.m index 66361cfdd9bf28..9c121db16e2bd1 100644 --- a/packages/react-native/React/DevSupport/RCTDevLoadingViewSetEnabled.m +++ b/packages/react-native/React/DevSupport/RCTDevLoadingViewSetEnabled.m @@ -7,7 +7,7 @@ #import "RCTDevLoadingViewSetEnabled.h" -#if RCT_DEV | RCT_ENABLE_LOADING_VIEW +#if RCT_DEV_MENU static BOOL isDevLoadingViewEnabled = YES; #else static BOOL isDevLoadingViewEnabled = NO; diff --git a/packages/react-native/React/Fabric/Mounting/ComponentViews/Image/RCTImageComponentView.mm b/packages/react-native/React/Fabric/Mounting/ComponentViews/Image/RCTImageComponentView.mm index 9d7b67f07d4dea..8b5b3d1b22ad28 100644 --- a/packages/react-native/React/Fabric/Mounting/ComponentViews/Image/RCTImageComponentView.mm +++ b/packages/react-native/React/Fabric/Mounting/ComponentViews/Image/RCTImageComponentView.mm @@ -14,6 +14,7 @@ #import #import #import +#import #import #import @@ -97,8 +98,18 @@ - (void)updateState:(State::Shared const &)state oldState:(State::Shared const & - (void)_setStateAndResubscribeImageResponseObserver:(ImageShadowNode::ConcreteState::Shared const &)state { if (_state) { - auto &observerCoordinator = _state->getData().getImageRequest().getObserverCoordinator(); + auto const &imageRequest = _state->getData().getImageRequest(); + auto &observerCoordinator = imageRequest.getObserverCoordinator(); observerCoordinator.removeObserver(_imageResponseObserverProxy); + if (CoreFeatures::cancelImageDownloadsOnRecycle) { + // Cancelling image request because we are no longer observing it. + // This is not 100% correct place to do this because we may want to + // re-create RCTImageComponentView with the same image and if it + // was cancelled before downloaded, download is not resumed. + // This will only become issue if we decouple life cycle of a + // ShadowNode from ComponentView, which is not something we do now. + imageRequest.cancel(); + } } _state = state; diff --git a/packages/react-native/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm b/packages/react-native/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm index e5755844e7eec3..d8ee6cb3d8b0bb 100644 --- a/packages/react-native/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm +++ b/packages/react-native/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm @@ -492,7 +492,14 @@ - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL } std::static_pointer_cast(_eventEmitter)->onScrollEndDrag([self _scrollViewMetrics]); + [self _updateStateWithContentOffset]; + + if (!decelerate) { + // ScrollView will not decelerate and `scrollViewDidEndDecelerating` will not be called. + // `_isUserTriggeredScrolling` must be set to NO here. + _isUserTriggeredScrolling = NO; + } } - (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView diff --git a/packages/react-native/React/Fabric/Mounting/RCTComponentViewFactory.mm b/packages/react-native/React/Fabric/Mounting/RCTComponentViewFactory.mm index 0fe7f13d286722..216c2c0b3329f8 100644 --- a/packages/react-native/React/Fabric/Mounting/RCTComponentViewFactory.mm +++ b/packages/react-native/React/Fabric/Mounting/RCTComponentViewFactory.mm @@ -49,7 +49,7 @@ void RCTInstallNativeComponentRegistryBinding(facebook::jsi::Runtime &runtime) return [[RCTComponentViewFactory currentComponentViewFactory] registerComponentIfPossible:componentNameByReactViewName(name)]; }; - NativeComponentRegistryBinding::install(runtime, std::move(hasComponentProvider)); + bindHasComponentProvider(runtime, std::move(hasComponentProvider)); } static Class RCTComponentViewClassWithName(const char *componentName) diff --git a/packages/react-native/React/Fabric/RCTImageResponseObserverProxy.h b/packages/react-native/React/Fabric/RCTImageResponseObserverProxy.h index b12b3485ceb4d5..523396478ee186 100644 --- a/packages/react-native/React/Fabric/RCTImageResponseObserverProxy.h +++ b/packages/react-native/React/Fabric/RCTImageResponseObserverProxy.h @@ -13,8 +13,7 @@ NS_ASSUME_NONNULL_BEGIN -namespace facebook { -namespace react { +namespace facebook::react { class RCTImageResponseObserverProxy final : public ImageResponseObserver { public: @@ -28,7 +27,6 @@ class RCTImageResponseObserverProxy final : public ImageResponseObserver { __weak id delegate_; }; -} // namespace react -} // namespace facebook +} // namespace facebook::react NS_ASSUME_NONNULL_END diff --git a/packages/react-native/React/Fabric/RCTImageResponseObserverProxy.mm b/packages/react-native/React/Fabric/RCTImageResponseObserverProxy.mm index 609dbba9085328..d195d4fd81c8d9 100644 --- a/packages/react-native/React/Fabric/RCTImageResponseObserverProxy.mm +++ b/packages/react-native/React/Fabric/RCTImageResponseObserverProxy.mm @@ -12,8 +12,7 @@ #import #import -namespace facebook { -namespace react { +namespace facebook::react { RCTImageResponseObserverProxy::RCTImageResponseObserverProxy(id delegate) : delegate_(delegate) @@ -49,5 +48,4 @@ }); } -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/React/Fabric/RCTSurfacePresenter.mm b/packages/react-native/React/Fabric/RCTSurfacePresenter.mm index d52cbdfe7632bc..77bc364889fd37 100644 --- a/packages/react-native/React/Fabric/RCTSurfacePresenter.mm +++ b/packages/react-native/React/Fabric/RCTSurfacePresenter.mm @@ -281,8 +281,8 @@ - (RCTScheduler *)_createScheduler CoreFeatures::useNativeState = true; } - if (reactNativeConfig && reactNativeConfig->getBool("react_fabric:enable_nstextstorage_caching")) { - CoreFeatures::cacheNSTextStorage = true; + if (reactNativeConfig && reactNativeConfig->getBool("react_fabric:cancel_image_downloads_on_recycle")) { + CoreFeatures::cancelImageDownloadsOnRecycle = true; } auto componentRegistryFactory = diff --git a/packages/react-native/React/Fabric/Utils/PlatformRunLoopObserver.h b/packages/react-native/React/Fabric/Utils/PlatformRunLoopObserver.h index 98505f239aca71..2141d3943dd69a 100644 --- a/packages/react-native/React/Fabric/Utils/PlatformRunLoopObserver.h +++ b/packages/react-native/React/Fabric/Utils/PlatformRunLoopObserver.h @@ -12,8 +12,7 @@ #include -namespace facebook { -namespace react { +namespace facebook::react { /* * Concrete iOS-specific implementation of `RunLoopObserver` using @@ -50,5 +49,4 @@ class MainRunLoopObserver final : public PlatformRunLoopObserver { : PlatformRunLoopObserver(activities, owner, CFRunLoopGetMain()) {} }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/React/Fabric/Utils/PlatformRunLoopObserver.mm b/packages/react-native/React/Fabric/Utils/PlatformRunLoopObserver.mm index 9f6268df447370..cf731e0b86aed9 100644 --- a/packages/react-native/React/Fabric/Utils/PlatformRunLoopObserver.mm +++ b/packages/react-native/React/Fabric/Utils/PlatformRunLoopObserver.mm @@ -9,8 +9,7 @@ #import -namespace facebook { -namespace react { +namespace facebook::react { static CFRunLoopActivity toCFRunLoopActivity(RunLoopObserver::Activity activity) { @@ -93,5 +92,4 @@ static CFRunLoopActivity toCFRunLoopActivity(RunLoopObserver::Activity activity) return CFRunLoopGetCurrent() == runLoop_; } -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/React/Fabric/Utils/RCTIdentifierPool.h b/packages/react-native/React/Fabric/Utils/RCTIdentifierPool.h index 92a35b79e22171..89c984e90d9dba 100644 --- a/packages/react-native/React/Fabric/Utils/RCTIdentifierPool.h +++ b/packages/react-native/React/Fabric/Utils/RCTIdentifierPool.h @@ -9,8 +9,7 @@ #include -namespace facebook { -namespace react { +namespace facebook::react { template class RCTIdentifierPool { @@ -40,5 +39,4 @@ class RCTIdentifierPool { int lastIndex; }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/React/React-RCTFabric.podspec b/packages/react-native/React/React-RCTFabric.podspec index 944e50a66bd769..0c399c1797afd3 100644 --- a/packages/react-native/React/React-RCTFabric.podspec +++ b/packages/react-native/React/React-RCTFabric.podspec @@ -27,6 +27,7 @@ header_search_paths = [ "\"$(PODS_ROOT)/DoubleConversion\"", "\"$(PODS_ROOT)/RCT-Folly\"", "\"$(PODS_ROOT)/Headers/Private/React-Core\"", + "\"$(PODS_ROOT)/Headers/Private/Yoga\"", "\"$(PODS_ROOT)/Headers/Public/React-Codegen\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/React-Codegen/React_Codegen.framework/Headers\"", @@ -34,6 +35,7 @@ header_search_paths = [ if ENV['USE_FRAMEWORKS'] header_search_paths << "\"${PODS_CONFIGURATION_BUILD_DIR}/React-Fabric/React_Fabric.framework/Headers\"" + header_search_paths << "\"${PODS_CONFIGURATION_BUILD_DIR}/React-FabricImage/React_FabricImage.framework/Headers\"" header_search_paths << "\"${PODS_CONFIGURATION_BUILD_DIR}/React-Fabric/React_Fabric.framework/Headers/react/renderer/textlayoutmanager/platform/ios\"" header_search_paths << "\"${PODS_CONFIGURATION_BUILD_DIR}/React-Fabric/React_Fabric.framework/Headers/react/renderer/components/textinput/iostextinput\"" header_search_paths << "\"${PODS_CONFIGURATION_BUILD_DIR}/React-Fabric/React_Fabric.framework/Headers/react/renderer/imagemanager/platform/ios\"" @@ -58,7 +60,7 @@ Pod::Spec.new do |s| s.compiler_flags = folly_compiler_flags + ' ' + boost_compiler_flags s.header_dir = "React" s.module_name = "RCTFabric" - s.framework = "JavaScriptCore" + s.framework = ["JavaScriptCore", "MobileCoreServices"] s.pod_target_xcconfig = { "HEADER_SEARCH_PATHS" => header_search_paths, "OTHER_CFLAGS" => "$(inherited) -DRN_FABRIC_ENABLED" + " " + folly_flags, @@ -71,7 +73,18 @@ Pod::Spec.new do |s| s.dependency "React-Fabric", version s.dependency "React-RCTImage", version s.dependency "React-ImageManager" + s.dependency "React-graphics" s.dependency "RCT-Folly/Fabric", folly_version + s.dependency "glog" + s.dependency "Yoga" + s.dependency "React-RCTText" + s.dependency "React-FabricImage" + + if ENV["USE_HERMES"] == nil || ENV["USE_HERMES"] == "1" + s.dependency "hermes-engine" + else + s.dependency "React-jsi" + end s.test_spec 'Tests' do |test_spec| test_spec.source_files = "Tests/**/*.{mm}" diff --git a/packages/react-native/React/Views/RCTShadowView.m b/packages/react-native/React/Views/RCTShadowView.m index baca3cef65e4bf..7f8a47a22c9828 100644 --- a/packages/react-native/React/Views/RCTShadowView.m +++ b/packages/react-native/React/Views/RCTShadowView.m @@ -50,7 +50,7 @@ + (YGConfigRef)yogaConfig dispatch_once(&onceToken, ^{ yogaConfig = YGConfigNew(); YGConfigSetPointScaleFactor(yogaConfig, RCTScreenScale()); - YGConfigSetUseLegacyStretchBehaviour(yogaConfig, true); + YGConfigSetErrata(yogaConfig, YGErrataAll); }); return yogaConfig; } diff --git a/packages/react-native/ReactAndroid/build.gradle b/packages/react-native/ReactAndroid/build.gradle index 6f5cff2885209a..084cfa62942683 100644 --- a/packages/react-native/ReactAndroid/build.gradle +++ b/packages/react-native/ReactAndroid/build.gradle @@ -444,9 +444,14 @@ android { ndkVersion rootProject.ext.ndkVersion } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + defaultConfig { - minSdkVersion(21) - targetSdkVersion(33) + minSdk = 21 + targetSdk = 33 versionCode(1) versionName("1.0") @@ -659,13 +664,8 @@ android { } testOptions { - unitTests.all { - // Robolectric tests are downloading JARs at runtime. This allows to specify - // a local file mirror with REACT_NATIVE_ROBOLECTRIC_MIRROR to go in offline more. - if (System.getenv("REACT_NATIVE_ROBOLECTRIC_MIRROR") != null) { - systemProperty 'robolectric.offline', 'true' - systemProperty 'robolectric.dependency.dir', System.getenv("REACT_NATIVE_ROBOLECTRIC_MIRROR") - } + unitTests { + includeAndroidResources = true } } } @@ -723,11 +723,14 @@ react { jsRootDir = file("../Libraries") } +kotlin { + jvmToolchain(11) +} + tasks.withType(Test).all { // We add --add-opens flags to make sure we can run PowerMock tests on JDK >= 17 if (JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_17)) { jvmArgs += [ - "-XX:+AllowRedefinitionToAddDeleteMethods", "--illegal-access=permit", "--add-opens=java.base/java.lang=ALL-UNNAMED", "--add-opens=java.base/java.xml.internal=ALL-UNNAMED", diff --git a/packages/react-native/ReactAndroid/cmake-utils/default-app-setup/OnLoad.cpp b/packages/react-native/ReactAndroid/cmake-utils/default-app-setup/OnLoad.cpp index 5e7df8b86bc062..db1206a855a825 100644 --- a/packages/react-native/ReactAndroid/cmake-utils/default-app-setup/OnLoad.cpp +++ b/packages/react-native/ReactAndroid/cmake-utils/default-app-setup/OnLoad.cpp @@ -33,8 +33,7 @@ #include #include -namespace facebook { -namespace react { +namespace facebook::react { void registerComponents( std::shared_ptr registry) { @@ -72,8 +71,7 @@ std::shared_ptr javaModuleProvider( return rncli_ModuleProvider(name, params); } -} // namespace react -} // namespace facebook +} // namespace facebook::react JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) { return facebook::jni::initialize(vm, [] { diff --git a/packages/react-native/ReactAndroid/hermes-engine/build.gradle b/packages/react-native/ReactAndroid/hermes-engine/build.gradle index 3ad31d9debe078..2761a584427eb7 100644 --- a/packages/react-native/ReactAndroid/hermes-engine/build.gradle +++ b/packages/react-native/ReactAndroid/hermes-engine/build.gradle @@ -125,8 +125,8 @@ repositories { } android { - compileSdkVersion 31 - buildToolsVersion = "31.0.0" + compileSdkVersion 33 + buildToolsVersion = "33.0.0" namespace "com.facebook.hermes" // Used to override the NDK path/version on internal CI or by allowing @@ -139,7 +139,7 @@ android { } defaultConfig { - minSdkVersion 21 + minSdk = 21 externalNativeBuild { cmake { @@ -190,6 +190,15 @@ android { } } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + + kotlin { + jvmToolchain(11) + } + sourceSets { main { manifest.srcFile "$hermesDir/android/hermes/src/main/AndroidManifest.xml" diff --git a/packages/react-native/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactIntegrationTestCase.java b/packages/react-native/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactIntegrationTestCase.java index e923c7a112b9b1..0c722420c0959a 100644 --- a/packages/react-native/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactIntegrationTestCase.java +++ b/packages/react-native/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactIntegrationTestCase.java @@ -76,14 +76,11 @@ public void shutDownContext() { final SimpleSettableFuture semaphore = new SimpleSettableFuture<>(); UiThreadUtil.runOnUiThread( - new Runnable() { - @Override - public void run() { - if (contextToDestroy != null) { - contextToDestroy.destroy(); - } - semaphore.set(null); + () -> { + if (contextToDestroy != null) { + contextToDestroy.destroy(); } + semaphore.set(null); }); semaphore.getOrThrow(); } @@ -137,14 +134,10 @@ protected TimingModule createTimingModule() { final SimpleSettableFuture simpleSettableFuture = new SimpleSettableFuture(); UiThreadUtil.runOnUiThread( - new Runnable() { - @Override - public void run() { - ReactChoreographer.initialize(); - TimingModule timingModule = - new TimingModule(getContext(), mock(DevSupportManager.class)); - simpleSettableFuture.set(timingModule); - } + () -> { + ReactChoreographer.initialize(); + TimingModule timingModule = new TimingModule(getContext(), mock(DevSupportManager.class)); + simpleSettableFuture.set(timingModule); }); try { return simpleSettableFuture.get(5000, TimeUnit.MILLISECONDS); @@ -188,15 +181,12 @@ protected void tearDown() throws Exception { protected static void initializeJavaModule(final BaseJavaModule javaModule) { final Semaphore semaphore = new Semaphore(0); UiThreadUtil.runOnUiThread( - new Runnable() { - @Override - public void run() { - javaModule.initialize(); - if (javaModule instanceof LifecycleEventListener) { - ((LifecycleEventListener) javaModule).onHostResume(); - } - semaphore.release(); + () -> { + javaModule.initialize(); + if (javaModule instanceof LifecycleEventListener) { + ((LifecycleEventListener) javaModule).onHostResume(); } + semaphore.release(); }); try { SoftAssertions.assertCondition( diff --git a/packages/react-native/ReactAndroid/src/androidTest/js/TextInputTestModule.js b/packages/react-native/ReactAndroid/src/androidTest/js/TextInputTestModule.js index 68155efa64de45..321b1aea209b2c 100644 --- a/packages/react-native/ReactAndroid/src/androidTest/js/TextInputTestModule.js +++ b/packages/react-native/ReactAndroid/src/androidTest/js/TextInputTestModule.js @@ -47,7 +47,7 @@ class TokenizedTextExample extends React.Component { if (token[0].length === 0) { index = 1; } - parts.push(_text.substr(0, index)); + parts.push(_text.slice(0, index)); parts.push(token[0]); index = index + token[0].length; _text = _text.slice(index); diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/hermes/reactexecutor/HermesExecutor.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/hermes/reactexecutor/HermesExecutor.java index b0e4f24d10d912..c8d81b725d282e 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/hermes/reactexecutor/HermesExecutor.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/hermes/reactexecutor/HermesExecutor.java @@ -26,11 +26,7 @@ public static void loadLibrary() throws UnsatisfiedLinkError { SoLoader.loadLibrary("hermes"); SoLoader.loadLibrary("hermes_executor"); // libhermes_executor is built differently for Debug & Release so we load the proper mode. - if (ReactBuildConfig.DEBUG == true) { - mode_ = "Debug"; - } else { - mode_ = "Release"; - } + mode_ = ReactBuildConfig.DEBUG ? "Debug" : "Release"; } } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java index c7804a09eb6a57..53b8e507d4a79c 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java @@ -92,7 +92,6 @@ import com.facebook.react.modules.core.DeviceEventManagerModule; import com.facebook.react.modules.core.ReactChoreographer; import com.facebook.react.modules.debug.interfaces.DeveloperSettings; -import com.facebook.react.modules.fabric.ReactFabric; import com.facebook.react.packagerconnection.RequestHandler; import com.facebook.react.surface.ReactStage; import com.facebook.react.turbomodule.core.TurboModuleManager; @@ -102,6 +101,7 @@ import com.facebook.react.uimanager.ReactRoot; import com.facebook.react.uimanager.UIManagerHelper; import com.facebook.react.uimanager.ViewManager; +import com.facebook.react.uimanager.common.UIManagerType; import com.facebook.react.views.imagehelper.ResourceDrawableIdHelper; import com.facebook.soloader.SoLoader; import com.facebook.systrace.Systrace; @@ -555,6 +555,7 @@ private void toggleElementInspector() { * @deprecated Use {@link #onHostPause(Activity)} instead. */ @ThreadConfined(UI) + @Deprecated public void onHostPause() { UiThreadUtil.assertOnUiThread(); @@ -669,6 +670,7 @@ public void onViewDetachedFromWindow(View v) { * @deprecated use {@link #onHostDestroy(Activity)} instead */ @ThreadConfined(UI) + @Deprecated public void onHostDestroy() { UiThreadUtil.assertOnUiThread(); @@ -855,7 +857,10 @@ private void clearReactRoot(ReactRoot reactRoot) { * with the provided reactRoot reactRoot will be started asynchronously, i.e this method won't * block. This reactRoot will then be tracked by this manager and in case of catalyst instance * restart it will be re-attached. + * + * @deprecated This method should be internal to ReactRootView and ReactInstanceManager */ + @Deprecated @ThreadConfined(UI) public void attachRootView(ReactRoot reactRoot) { UiThreadUtil.assertOnUiThread(); @@ -865,6 +870,8 @@ public void attachRootView(ReactRoot reactRoot) { // Ideally reactRoot should be initialized with id == NO_ID if (mAttachedReactRoots.add(reactRoot)) { clearReactRoot(reactRoot); + } else { + FLog.e(ReactConstants.TAG, "ReactRoot was attached multiple times"); } // If react context is being created in the background, JS application will be started @@ -872,9 +879,7 @@ public void attachRootView(ReactRoot reactRoot) { // reactRoot list. ReactContext currentContext = getCurrentReactContext(); if (mCreateReactContextThread == null && currentContext != null) { - if (reactRoot.getState().compareAndSet(ReactRoot.STATE_STOPPED, ReactRoot.STATE_STARTED)) { - attachRootViewToInstance(reactRoot); - } + attachRootViewToInstance(reactRoot); } } @@ -882,18 +887,20 @@ public void attachRootView(ReactRoot reactRoot) { * Detach given {@param reactRoot} from current catalyst instance. It's safe to call this method * multiple times on the same {@param reactRoot} - in that case view will be detached with the * first call. + * + * @deprecated This method should be internal to ReactRootView and ReactInstanceManager */ + @Deprecated @ThreadConfined(UI) public void detachRootView(ReactRoot reactRoot) { UiThreadUtil.assertOnUiThread(); - synchronized (mAttachedReactRoots) { - if (mAttachedReactRoots.contains(reactRoot)) { - ReactContext currentContext = getCurrentReactContext(); - mAttachedReactRoots.remove(reactRoot); - if (currentContext != null && currentContext.hasActiveReactInstance()) { - detachViewFromInstance(reactRoot, currentContext.getCatalystInstance()); - } - } + if (!mAttachedReactRoots.remove(reactRoot)) { + return; + } + + ReactContext reactContext = mCurrentReactContext; + if (reactContext != null && reactContext.hasActiveReactInstance()) { + detachRootViewFromInstance(reactRoot, reactContext); } } @@ -1150,9 +1157,7 @@ private void setupReactContext(final ReactApplicationContext reactContext) { ReactMarker.logMarker(ATTACH_MEASURED_ROOT_VIEWS_START); for (ReactRoot reactRoot : mAttachedReactRoots) { - if (reactRoot.getState().compareAndSet(ReactRoot.STATE_STOPPED, ReactRoot.STATE_STARTED)) { - attachRootViewToInstance(reactRoot); - } + attachRootViewToInstance(reactRoot); } ReactMarker.logMarker(ATTACH_MEASURED_ROOT_VIEWS_END); } @@ -1194,6 +1199,11 @@ private void setupReactContext(final ReactApplicationContext reactContext) { private void attachRootViewToInstance(final ReactRoot reactRoot) { FLog.d(ReactConstants.TAG, "ReactInstanceManager.attachRootViewToInstance()"); + if (!reactRoot.getState().compareAndSet(ReactRoot.STATE_STOPPED, ReactRoot.STATE_STARTED)) { + // Already started + return; + } + Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "attachRootViewToInstance"); @Nullable @@ -1210,7 +1220,6 @@ private void attachRootViewToInstance(final ReactRoot reactRoot) { @Nullable Bundle initialProperties = reactRoot.getAppProperties(); final int rootTag; - if (reactRoot.getUIManagerType() == FABRIC) { rootTag = uiManager.startSurface( @@ -1245,18 +1254,48 @@ private void attachRootViewToInstance(final ReactRoot reactRoot) { Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE); } - private void detachViewFromInstance(ReactRoot reactRoot, CatalystInstance catalystInstance) { - FLog.d(ReactConstants.TAG, "ReactInstanceManager.detachViewFromInstance()"); + private void detachRootViewFromInstance(ReactRoot reactRoot, ReactContext reactContext) { + FLog.d(ReactConstants.TAG, "ReactInstanceManager.detachRootViewFromInstance()"); UiThreadUtil.assertOnUiThread(); - if (reactRoot.getUIManagerType() == FABRIC) { - catalystInstance - .getJSModule(ReactFabric.class) - .unmountComponentAtNode(reactRoot.getRootViewTag()); + + if (!reactRoot.getState().compareAndSet(ReactRoot.STATE_STARTED, ReactRoot.STATE_STOPPED)) { + // ReactRoot was already stopped + return; + } + + @UIManagerType int uiManagerType = reactRoot.getUIManagerType(); + if (uiManagerType == UIManagerType.FABRIC) { + // Stop surface in Fabric. + // Calling FabricUIManager.stopSurface causes the C++ Binding.stopSurface + // to be called synchronously over the JNI, which causes an empty tree + // 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. + final int surfaceId = reactRoot.getRootViewTag(); + if (surfaceId != View.NO_ID) { + UIManager uiManager = UIManagerHelper.getUIManager(reactContext, uiManagerType); + if (uiManager != null) { + uiManager.stopSurface(surfaceId); + } else { + FLog.w(ReactConstants.TAG, "Failed to stop surface, UIManager has already gone away"); + reactRoot.getRootViewGroup().removeAllViews(); + } + } else { + ReactSoftExceptionLogger.logSoftException( + TAG, + new RuntimeException( + "detachRootViewFromInstance called with ReactRootView with invalid id")); + reactRoot.getRootViewGroup().removeAllViews(); + } } else { - catalystInstance + reactContext + .getCatalystInstance() .getJSModule(AppRegistry.class) .unmountApplicationComponentAtRootTag(reactRoot.getRootViewTag()); } + + // The view is no longer attached, so mark it as such by resetting its ID. + reactRoot.getRootViewGroup().setId(View.NO_ID); } @ThreadConfined(UI) @@ -1269,7 +1308,11 @@ private void tearDownReactContext(ReactContext reactContext) { synchronized (mAttachedReactRoots) { for (ReactRoot reactRoot : mAttachedReactRoots) { - clearReactRoot(reactRoot); + if (ReactFeatureFlags.unmountApplicationOnInstanceDetach) { + detachRootViewFromInstance(reactRoot, reactContext); + } else { + clearReactRoot(reactRoot); + } } } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactPackageTurboModuleManagerDelegate.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactPackageTurboModuleManagerDelegate.java index c0d7e7cfdc561a..73c4d6468f5c79 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactPackageTurboModuleManagerDelegate.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactPackageTurboModuleManagerDelegate.java @@ -44,12 +44,6 @@ private static boolean shouldCreateLegacyModules() { && ReactFeatureFlags.unstable_useTurboModuleInterop; } - private static boolean shouldRouteTurboModulesThroughInteropLayer() { - return ReactFeatureFlags.enableBridgelessArchitecture - && ReactFeatureFlags.unstable_useTurboModuleInterop - && ReactFeatureFlags.unstable_useTurboModuleInteropForAllTurboModules; - } - protected ReactPackageTurboModuleManagerDelegate( ReactApplicationContext reactApplicationContext, List packages) { super(); @@ -58,11 +52,7 @@ protected ReactPackageTurboModuleManagerDelegate( if (reactPackage instanceof TurboReactPackage) { final TurboReactPackage turboPkg = (TurboReactPackage) reactPackage; final ModuleProvider moduleProvider = - new ModuleProvider() { - public NativeModule getModule(String moduleName) { - return turboPkg.getModule(moduleName, applicationContext); - } - }; + moduleName -> turboPkg.getModule(moduleName, applicationContext); mModuleProviders.add(moduleProvider); mPackageModuleInfos.put( moduleProvider, turboPkg.getReactModuleInfoProvider().getReactModuleInfos()); @@ -79,11 +69,9 @@ public NativeModule getModule(String moduleName) { } final ModuleProvider moduleProvider = - new ModuleProvider() { - public NativeModule getModule(String moduleName) { - Provider provider = moduleSpecProviderMap.get(moduleName); - return provider != null ? provider.get() : null; - } + moduleName -> { + Provider provider = moduleSpecProviderMap.get(moduleName); + return provider != null ? provider.get() : null; }; mModuleProviders.add(moduleProvider); @@ -136,12 +124,7 @@ public NativeModule getModule(String moduleName) { moduleMap.put(moduleName, module); } - final ModuleProvider moduleProvider = - new ModuleProvider() { - public NativeModule getModule(String moduleName) { - return moduleMap.get(moduleName); - } - }; + final ModuleProvider moduleProvider = moduleMap::get; mModuleProviders.add(moduleProvider); mPackageModuleInfos.put(moduleProvider, reactModuleInfoMap); @@ -152,10 +135,6 @@ public NativeModule getModule(String moduleName) { @Nullable @Override public TurboModule getModule(String moduleName) { - if (shouldRouteTurboModulesThroughInteropLayer()) { - return null; - } - NativeModule resolvedModule = null; for (final ModuleProvider moduleProvider : mModuleProviders) { @@ -181,13 +160,34 @@ public TurboModule getModule(String moduleName) { } // Skip TurboModule-incompatible modules - if (!(resolvedModule instanceof TurboModule)) { + boolean isLegacyModule = !(resolvedModule instanceof TurboModule); + if (isLegacyModule) { return null; } return (TurboModule) resolvedModule; } + public boolean unstable_isModuleRegistered(String moduleName) { + for (final ModuleProvider moduleProvider : mModuleProviders) { + final ReactModuleInfo moduleInfo = mPackageModuleInfos.get(moduleProvider).get(moduleName); + if (moduleInfo != null && moduleInfo.isTurboModule()) { + return true; + } + } + return false; + } + + public boolean unstable_isLegacyModuleRegistered(String moduleName) { + for (final ModuleProvider moduleProvider : mModuleProviders) { + final ReactModuleInfo moduleInfo = mPackageModuleInfos.get(moduleProvider).get(moduleName); + if (moduleInfo != null && !moduleInfo.isTurboModule()) { + return true; + } + } + return false; + } + @Nullable @Override public NativeModule getLegacyModule(String moduleName) { @@ -201,7 +201,7 @@ public NativeModule getLegacyModule(String moduleName) { try { final ReactModuleInfo moduleInfo = mPackageModuleInfos.get(moduleProvider).get(moduleName); if (moduleInfo != null - && (!moduleInfo.isTurboModule() || shouldRouteTurboModulesThroughInteropLayer()) + && !moduleInfo.isTurboModule() && (resolvedModule == null || moduleInfo.canOverrideExistingModule())) { final NativeModule module = moduleProvider.getModule(moduleName); @@ -221,20 +221,13 @@ public NativeModule getLegacyModule(String moduleName) { // Skip TurboModule-compatible modules boolean isLegacyModule = !(resolvedModule instanceof TurboModule); - if (!(isLegacyModule || shouldRouteTurboModulesThroughInteropLayer())) { + if (!isLegacyModule) { return null; } return resolvedModule; } - @Deprecated - @Nullable - @Override - public CxxModuleWrapper getLegacyCxxModule(String moduleName) { - return null; - } - @Override public List getEagerInitModuleNames() { List moduleNames = new ArrayList<>(); diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java index 8be37b052acbd3..f0a0b7dbef5a23 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java @@ -611,41 +611,6 @@ private void updateRootLayoutSpecs( @ThreadConfined(UI) public void unmountReactApplication() { UiThreadUtil.assertOnUiThread(); - // Stop surface in Fabric. - // Calling FabricUIManager.stopSurface causes the C++ Binding.stopSurface - // to be called synchronously over the JNI, which causes an empty tree - // 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 (hasActiveReactInstance()) { - final ReactContext reactApplicationContext = getCurrentReactContext(); - if (reactApplicationContext != null && isFabric()) { - @Nullable - UIManager uiManager = - UIManagerHelper.getUIManager(reactApplicationContext, getUIManagerType()); - if (uiManager != null) { - final int surfaceId = this.getId(); - - // In case of "retry" or error dialogues being shown, this ReactRootView could be - // reused (with the same surfaceId, or a different one). Ensure the ReactRootView - // is marked as unused in case of that. - setId(NO_ID); - - // Remove all children from ReactRootView - removeAllViews(); - - if (surfaceId == NO_ID) { - ReactSoftExceptionLogger.logSoftException( - TAG, - new RuntimeException( - "unmountReactApplication called on ReactRootView with invalid id")); - } else { - uiManager.stopSurface(surfaceId); - } - } - } - } - if (mReactInstanceManager != null && mIsAttachedToInstance) { mReactInstanceManager.detachRootView(this); mIsAttachedToInstance = false; diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java index d377ceb595394d..0329ae8e92b0b1 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java @@ -457,7 +457,7 @@ public T getJSModule(Class jsInterface) { @Override public boolean hasNativeModule(Class nativeModuleInterface) { String moduleName = getNameFromAnnotation(nativeModuleInterface); - return getTurboModuleRegistry() != null && getTurboModuleRegistry().hasNativeModule(moduleName) + return getTurboModuleRegistry() != null && getTurboModuleRegistry().hasModule(moduleName) ? true : mNativeModuleRegistry.hasModule(moduleName); } @@ -482,7 +482,7 @@ private TurboModuleRegistry getTurboModuleRegistry() { @Nullable public NativeModule getNativeModule(String moduleName) { if (getTurboModuleRegistry() != null) { - NativeModule module = getTurboModuleRegistry().getNativeModule(moduleName); + NativeModule module = getTurboModuleRegistry().getModule(moduleName); if (module != null) { return module; } @@ -509,7 +509,7 @@ public Collection getNativeModules() { nativeModules.addAll(mNativeModuleRegistry.getAllModules()); if (getTurboModuleRegistry() != null) { - for (NativeModule module : getTurboModuleRegistry().getNativeModules()) { + for (NativeModule module : getTurboModuleRegistry().getModules()) { nativeModules.add(module); } } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/FallbackJSBundleLoader.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/FallbackJSBundleLoader.java index e2c669cb462389..c07c67b02f611c 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/FallbackJSBundleLoader.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/FallbackJSBundleLoader.java @@ -26,14 +26,14 @@ public final class FallbackJSBundleLoader extends JSBundleLoader { /* package */ static final String TAG = "FallbackJSBundleLoader"; // Loaders to delegate to, with the preferred one at the top. - private Stack mLoaders; + private final Stack mLoaders; // Reasons why we fell-back on previous loaders, in order of occurrence. private final ArrayList mRecoveredErrors = new ArrayList<>(); /** @param loaders Loaders for the sources to try, in descending order of preference. */ public FallbackJSBundleLoader(List loaders) { - mLoaders = new Stack(); + mLoaders = new Stack<>(); ListIterator it = loaders.listIterator(loaders.size()); while (it.hasPrevious()) { mLoaders.push(it.previous()); diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/JSBundleLoader.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/JSBundleLoader.java index 6c3844205c21bf..800eeffbdb66f4 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/JSBundleLoader.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/JSBundleLoader.java @@ -9,11 +9,9 @@ import android.content.Context; import com.facebook.react.common.DebugServerException; +import java.util.Objects; -/** - * A class that stores JS bundle information and allows a {@link JSBundleLoaderDelegate} (e.g. - * {@link CatalystInstance}) to load a correct bundle through {@link ReactBridge}. - */ +/** A class that stores JS bundle information and allows a {@link JSBundleLoaderDelegate}. */ public abstract class JSBundleLoader { /** @@ -67,7 +65,8 @@ public String loadScript(JSBundleLoaderDelegate delegate) { delegate.loadScriptFromFile(cachedFileLocation, sourceURL, false); return sourceURL; } catch (Exception e) { - throw DebugServerException.makeGeneric(sourceURL, e.getMessage(), e); + throw DebugServerException.makeGeneric( + sourceURL, Objects.toString(e.getMessage(), ""), e); } } }; @@ -86,7 +85,8 @@ public String loadScript(JSBundleLoaderDelegate delegate) { delegate.loadSplitBundleFromFile(cachedFileLocation, sourceURL); return sourceURL; } catch (Exception e) { - throw DebugServerException.makeGeneric(sourceURL, e.getMessage(), e); + throw DebugServerException.makeGeneric( + sourceURL, Objects.toString(e.getMessage(), ""), e); } } }; diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeModule.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeModule.java index 89e528d707de64..c5b1dfcf5439f6 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeModule.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeModule.java @@ -52,6 +52,7 @@ interface NativeMethod { * * @deprecated use {@link #invalidate()} instead. */ + @Deprecated void onCatalystInstanceDestroy(); /** Allow NativeModule to clean up. Called before {CatalystInstance#onHostDestroy} */ diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactContext.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactContext.java index b361bac736f31c..dfe32f2dd92704 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactContext.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactContext.java @@ -21,6 +21,7 @@ import com.facebook.infer.annotation.Assertions; import com.facebook.infer.annotation.ThreadConfined; import com.facebook.proguard.annotations.DoNotStrip; +import com.facebook.react.bridge.interop.InteropModuleRegistry; import com.facebook.react.bridge.queue.MessageQueueThread; import com.facebook.react.bridge.queue.ReactQueueConfiguration; import com.facebook.react.common.LifecycleState; @@ -69,6 +70,8 @@ public interface RCTDeviceEventEmitter extends JavaScriptModule { private @Nullable JSExceptionHandler mJSExceptionHandler; private @Nullable JSExceptionHandler mExceptionHandlerWrapper; private @Nullable WeakReference mCurrentActivity; + + private @Nullable InteropModuleRegistry mInteropModuleRegistry; private boolean mIsInitialized = false; public ReactContext(Context base) { @@ -93,6 +96,7 @@ public void initializeWithInstance(CatalystInstance catalystInstance) { ReactQueueConfiguration queueConfig = catalystInstance.getReactQueueConfiguration(); initializeMessageQueueThreads(queueConfig); + initializeInteropModules(); } /** Initialize message queue threads using a ReactQueueConfiguration. */ @@ -120,6 +124,14 @@ public synchronized void initializeMessageQueueThreads(ReactQueueConfiguration q mIsInitialized = true; } + protected void initializeInteropModules() { + mInteropModuleRegistry = new InteropModuleRegistry(); + } + + protected void initializeInteropModules(ReactContext reactContext) { + mInteropModuleRegistry = reactContext.mInteropModuleRegistry; + } + public void resetPerfStats() { if (mNativeModulesMessageQueueThread != null) { mNativeModulesMessageQueueThread.resetPerfStats(); @@ -163,6 +175,10 @@ public T getJSModule(Class jsInterface) { } throw new IllegalStateException(EARLY_JS_ACCESS_EXCEPTION_MESSAGE); } + if (mInteropModuleRegistry != null + && mInteropModuleRegistry.shouldReturnInteropModule(jsInterface)) { + return mInteropModuleRegistry.getInteropModule(jsInterface); + } return mCatalystInstance.getJSModule(jsInterface); } @@ -500,6 +516,7 @@ public boolean startActivityForResult(Intent intent, int code, Bundle bundle) { } /** @deprecated DO NOT USE, this method will be removed in the near future. */ + @Deprecated public boolean isBridgeless() { return false; } @@ -543,4 +560,17 @@ public void registerSegment(int segmentId, String path, Callback callback) { Assertions.assertNotNull(mCatalystInstance).registerSegment(segmentId, path); Assertions.assertNotNull(callback).invoke(); } + + /** + * Register a {@link JavaScriptModule} within the Interop Layer so that can be consumed whenever + * getJSModule is invoked. + * + *

This method is internal to React Native and should not be used externally. + */ + public void internal_registerInteropModule( + Class interopModuleInterface, Object interopModule) { + if (mInteropModuleRegistry != null) { + mInteropModuleRegistry.registerInteropModule(interopModuleInterface, interopModule); + } + } } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/interop/InteropModuleRegistry.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/interop/InteropModuleRegistry.java new file mode 100644 index 00000000000000..f47199edc63d80 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/interop/InteropModuleRegistry.java @@ -0,0 +1,56 @@ +/* + * 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. + */ + +package com.facebook.react.bridge.interop; + +import androidx.annotation.Nullable; +import com.facebook.react.bridge.JavaScriptModule; +import com.facebook.react.config.ReactFeatureFlags; +import java.util.HashMap; + +/** + * A utility class that takes care of returning {@link JavaScriptModule} which are used for the + * Fabric Interop Layer. This allows us to override the returned classes once the user is invoking + * `ReactContext.getJsModule()`. + * + *

Currently we only support a `RCTEventEmitter` re-implementation, being `InteropEventEmitter` + * but this class can support other re-implementation in the future. + */ +public class InteropModuleRegistry { + + @SuppressWarnings("rawtypes") + private final HashMap supportedModules; + + public InteropModuleRegistry() { + this.supportedModules = new HashMap<>(); + } + + public boolean shouldReturnInteropModule(Class requestedModule) { + return checkReactFeatureFlagsConditions() && supportedModules.containsKey(requestedModule); + } + + @Nullable + public T getInteropModule(Class requestedModule) { + if (checkReactFeatureFlagsConditions()) { + //noinspection unchecked + return (T) supportedModules.get(requestedModule); + } else { + return null; + } + } + + public void registerInteropModule( + Class interopModuleInterface, Object interopModule) { + if (checkReactFeatureFlagsConditions()) { + supportedModules.put(interopModuleInterface, interopModule); + } + } + + private boolean checkReactFeatureFlagsConditions() { + return ReactFeatureFlags.enableFabricRenderer && ReactFeatureFlags.unstable_useFabricInterop; + } +} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/BindingsInstaller.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/BindingsInstaller.java deleted file mode 100644 index 53d1c59e84d78b..00000000000000 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/BindingsInstaller.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -package com.facebook.react.bridgeless; - -import com.facebook.jni.HybridData; -import com.facebook.proguard.annotations.DoNotStrip; -import com.facebook.proguard.annotations.DoNotStripAny; -import com.facebook.soloader.SoLoader; - -@DoNotStripAny -public abstract class BindingsInstaller { - static { - SoLoader.loadLibrary("rninstance"); - } - - @DoNotStrip private final HybridData mHybridData; - - protected BindingsInstaller(HybridData hybridData) { - mHybridData = hybridData; - } -} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/BindingsInstaller.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/BindingsInstaller.kt new file mode 100644 index 00000000000000..8225c484bdcf56 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/BindingsInstaller.kt @@ -0,0 +1,22 @@ +/* + * 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. + */ + +package com.facebook.react.bridgeless + +import com.facebook.jni.HybridData +import com.facebook.proguard.annotations.DoNotStrip +import com.facebook.proguard.annotations.DoNotStripAny +import com.facebook.soloader.SoLoader + +@DoNotStripAny +abstract class BindingsInstaller(@field:DoNotStrip private val mHybridData: HybridData) { + companion object { + init { + SoLoader.loadLibrary("rninstance") + } + } +} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/BridgelessAtomicRef.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/BridgelessAtomicRef.java index 4ceb305c30f52f..d613b497c9e1bd 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/BridgelessAtomicRef.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/BridgelessAtomicRef.java @@ -12,9 +12,10 @@ import android.annotation.SuppressLint; import androidx.annotation.Nullable; import com.facebook.infer.annotation.Nullsafe; +import java.util.Objects; @Nullsafe(Nullsafe.Mode.LOCAL) -public class BridgelessAtomicRef { +class BridgelessAtomicRef { interface Provider { T get(); @@ -30,8 +31,8 @@ enum State { Failure } - volatile State state; - volatile String failureMessage; + private volatile State state; + private volatile String failureMessage; public BridgelessAtomicRef(@Nullable T initialValue) { mValue = initialValue; @@ -77,7 +78,7 @@ public T getOrCreate(BridgelessAtomicRef.Provider provider) { synchronized (this) { state = State.Failure; String message = ex.getMessage(); - failureMessage = message != null ? message : "null"; + failureMessage = Objects.toString(message, "null"); notifyAll(); } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/BridgelessDevSupportManager.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/BridgelessDevSupportManager.java index fe387acefaf81c..70aeee79789958 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/BridgelessDevSupportManager.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/BridgelessDevSupportManager.java @@ -10,13 +10,13 @@ import android.app.Activity; import android.content.Context; import android.view.View; -import bolts.Continuation; -import bolts.Task; import com.facebook.infer.annotation.Nullsafe; import com.facebook.react.bridge.JSBundleLoader; import com.facebook.react.bridge.JavaJSExecutor; import com.facebook.react.bridge.JavaScriptExecutorFactory; import com.facebook.react.bridge.ReactContext; +import com.facebook.react.bridgeless.internal.bolts.Continuation; +import com.facebook.react.bridgeless.internal.bolts.Task; import com.facebook.react.devsupport.DevSupportManagerBase; import com.facebook.react.devsupport.HMRClient; import com.facebook.react.devsupport.ReactInstanceDevHelper; @@ -30,7 +30,7 @@ * APIs for asynchronously loading the JS bundle. */ @Nullsafe(Nullsafe.Mode.LOCAL) -public class BridgelessDevSupportManager extends DevSupportManagerBase { +class BridgelessDevSupportManager extends DevSupportManagerBase { private final ReactHost mReactHost; diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/BridgelessReactContext.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/BridgelessReactContext.java index bfbc1f4ce44d54..b8ee4f666babaa 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/BridgelessReactContext.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/BridgelessReactContext.java @@ -151,7 +151,7 @@ public Collection getNativeModules() { @Override public void handleException(Exception e) { - mReactHost.handleException(e); + mReactHost.handleHostException(e); } public DefaultHardwareBackBtnHandler getDefaultHardwareBackBtnHandler() { diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/BridgelessReactStateTracker.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/BridgelessReactStateTracker.java index adf7a11c5edd29..3bdae47d1b0b2d 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/BridgelessReactStateTracker.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/BridgelessReactStateTracker.java @@ -14,22 +14,19 @@ import java.util.List; @Nullsafe(Nullsafe.Mode.LOCAL) -public class BridgelessReactStateTracker { - final List mStates = Collections.synchronizedList(new ArrayList()); - final boolean mShouldTrackStates; +class BridgelessReactStateTracker { + private static final String TAG = "BridgelessReact"; + private final List mStates = Collections.synchronizedList(new ArrayList<>()); + private final boolean mShouldTrackStates; BridgelessReactStateTracker(boolean shouldTrackStates) { mShouldTrackStates = shouldTrackStates; } - public void enterState(String state) { - FLog.w("BridgelessReact", state); + void enterState(String state) { + FLog.w(TAG, state); if (mShouldTrackStates) { mStates.add(state); } } - - public void assertStateOrder(String... expectedStates) { - // TODO: Implement - } } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/JSEngineInstance.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/JSEngineInstance.java index d4adeef240de27..c7c2e32ebdea1c 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/JSEngineInstance.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/JSEngineInstance.java @@ -18,7 +18,7 @@ public abstract class JSEngineInstance { SoLoader.loadLibrary("rninstance"); } - @DoNotStrip private HybridData mHybridData; + @DoNotStrip private final HybridData mHybridData; protected JSEngineInstance(HybridData hybridData) { mHybridData = hybridData; diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/JSTimerExecutor.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/JSTimerExecutor.java index 5dbfd5b215f58f..8d474db2a4b85f 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/JSTimerExecutor.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/JSTimerExecutor.java @@ -16,25 +16,25 @@ import com.facebook.soloader.SoLoader; @Nullsafe(Nullsafe.Mode.LOCAL) -public class JSTimerExecutor implements JavaScriptTimerExecutor { +class JSTimerExecutor implements JavaScriptTimerExecutor { static { SoLoader.loadLibrary("rninstance"); } - @DoNotStrip private HybridData mHybridData; + @DoNotStrip private final HybridData mHybridData; public JSTimerExecutor(HybridData hybridData) { mHybridData = hybridData; } + private native void callTimers(WritableNativeArray timerIDs); + @Override public void callTimers(WritableArray timerIDs) { callTimers((WritableNativeArray) timerIDs); } - private native void callTimers(WritableNativeArray timerIDs); - @Override public void callIdleCallbacks(double frameTime) { // TODO T52558331 diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/README.md b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/README.md new file mode 100644 index 00000000000000..60660d655988c9 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/README.md @@ -0,0 +1,3 @@ +# Bridgeless Mode for Android + +This library is not ready for integration for production nor local experimentation. Expect breaking changes regularly if you use any of these APIs. Use at your own risk! diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/ReactHost.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/ReactHost.java index 9b10fd7c58f4a6..e822d6c7bd1f21 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/ReactHost.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/ReactHost.java @@ -16,9 +16,6 @@ import android.app.Activity; import android.content.Context; import androidx.annotation.Nullable; -import bolts.Continuation; -import bolts.Task; -import bolts.TaskCompletionSource; import com.facebook.common.logging.FLog; import com.facebook.infer.annotation.Assertions; import com.facebook.infer.annotation.Nullsafe; @@ -41,6 +38,9 @@ import com.facebook.react.bridge.queue.QueueThreadExceptionHandler; import com.facebook.react.bridge.queue.ReactQueueConfiguration; import com.facebook.react.bridgeless.exceptionmanager.ReactJsExceptionHandler; +import com.facebook.react.bridgeless.internal.bolts.Continuation; +import com.facebook.react.bridgeless.internal.bolts.Task; +import com.facebook.react.bridgeless.internal.bolts.TaskCompletionSource; import com.facebook.react.common.LifecycleState; import com.facebook.react.common.build.ReactBuildConfig; import com.facebook.react.config.ReactFeatureFlags; @@ -54,6 +54,7 @@ import com.facebook.react.uimanager.events.BlackHoleEventDispatcher; import com.facebook.react.uimanager.events.EventDispatcher; import com.facebook.react.views.imagehelper.ResourceDrawableIdHelper; +import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -80,37 +81,33 @@ public class ReactHost { // TODO T61403233 Make this configurable by product code private static final boolean DEV = ReactBuildConfig.DEBUG; - + private static final String TAG = "ReactHost"; private static final int BRIDGELESS_MARKER_INSTANCE_KEY = 1; - public static final String TAG = "ReactHost"; - private final Context mContext; - private final ReactInstanceDelegate mReactInstanceDelegate; + private final ReactHostDelegate mReactHostDelegate; private final ComponentFactory mComponentFactory; private final ReactJsExceptionHandler mReactJsExceptionHandler; private final DevSupportManager mDevSupportManager; private final Executor mBGExecutor; private final Executor mUIExecutor; private final QueueThreadExceptionHandler mQueueThreadExceptionHandler; - private final Set mAttachedSurfaces = - Collections.synchronizedSet(new HashSet()); + private final Set mAttachedSurfaces = Collections.synchronizedSet(new HashSet<>()); private final MemoryPressureRouter mMemoryPressureRouter; - private final MemoryPressureListener mMemoryPressureListener; + private MemoryPressureListener mMemoryPressureListener; private final boolean mAllowPackagerServerAccess; private final boolean mUseDevSupport; private final Collection mReactInstanceEventListeners = - Collections.synchronizedList(new ArrayList()); + Collections.synchronizedList(new ArrayList<>()); private final BridgelessAtomicRef> mReactInstanceTaskRef = new BridgelessAtomicRef<>( Task.forResult( nullsafeFIXME( - (ReactInstance) null, - "forResult parameter supports null, but is not annotated as @Nullable"))); + null, "forResult parameter supports null, but is not annotated as @Nullable"))); private final BridgelessAtomicRef mBridgelessReactContextRef = - new BridgelessAtomicRef<>(null); + new BridgelessAtomicRef<>(); private final AtomicReference mActivity = new AtomicReference<>(); private @Nullable DefaultHardwareBackBtnHandler mDefaultHardwareBackBtnHandler; @@ -119,12 +116,12 @@ public class ReactHost { private final ReactLifecycleStateManager mReactLifecycleStateManager = new ReactLifecycleStateManager(mBridgelessReactStateTracker); - private static AtomicInteger mCounter = new AtomicInteger(0); + private static final AtomicInteger mCounter = new AtomicInteger(0); private final int mId = mCounter.getAndIncrement(); public ReactHost( Context context, - ReactInstanceDelegate delegate, + ReactHostDelegate delegate, ComponentFactory componentFactory, boolean allowPackagerServerAccess, ReactJsExceptionHandler reactJsExceptionHandler, @@ -142,7 +139,7 @@ public ReactHost( public ReactHost( Context context, - ReactInstanceDelegate delegate, + ReactHostDelegate delegate, ComponentFactory componentFactory, Executor bgExecutor, Executor uiExecutor, @@ -150,12 +147,12 @@ public ReactHost( boolean allowPackagerServerAccess, boolean useDevSupport) { mContext = context; - mReactInstanceDelegate = delegate; + mReactHostDelegate = delegate; mComponentFactory = componentFactory; mBGExecutor = bgExecutor; mUIExecutor = uiExecutor; mReactJsExceptionHandler = reactJsExceptionHandler; - mQueueThreadExceptionHandler = ReactHost.this::handleException; + mQueueThreadExceptionHandler = ReactHost.this::handleHostException; mMemoryPressureRouter = new MemoryPressureRouter(context); mMemoryPressureListener = level -> @@ -166,13 +163,26 @@ public ReactHost( if (DEV) { mDevSupportManager = new BridgelessDevSupportManager( - ReactHost.this, mContext, mReactInstanceDelegate.getJSMainModulePath()); + ReactHost.this, mContext, mReactHostDelegate.getJSMainModulePath()); } else { mDevSupportManager = new DisabledDevSupportManager(); } mUseDevSupport = useDevSupport; } + private MemoryPressureListener createMemoryPressureListener(ReactInstance reactInstance) { + WeakReference weakReactInstance = new WeakReference<>(reactInstance); + return (level) -> { + mBGExecutor.execute( + () -> { + @Nullable ReactInstance strongReactInstance = weakReactInstance.get(); + if (strongReactInstance != null) { + strongReactInstance.handleMemoryPressure(level); + } + }); + }; + } + public LifecycleState getLifecycleState() { return mReactLifecycleStateManager.getLifecycleState(); } @@ -197,7 +207,7 @@ public Task preload() { @ThreadConfined("ReactHost") private @Nullable Task mPreloadTask = null; - public Task old_preload() { + private Task old_preload() { final String method = "old_preload()"; return Task.call( () -> { @@ -211,7 +221,7 @@ public Task old_preload() { destroy( "old_preload() failure: " + task.getError().getMessage(), task.getError()); - mReactInstanceDelegate.handleException(task.getError()); + mReactHostDelegate.handleInstanceException(task.getError()); } return task; @@ -225,7 +235,7 @@ public Task old_preload() { .continueWithTask(Task::getResult); } - public Task new_preload() { + private Task new_preload() { final String method = "new_preload()"; return Task.call( () -> { @@ -236,7 +246,7 @@ public Task new_preload() { .continueWithTask( (task) -> { if (task.isFaulted()) { - mReactInstanceDelegate.handleException(task.getError()); + mReactHostDelegate.handleInstanceException(task.getError()); // Wait for destroy to finish return new_getOrCreateDestroyTask( "new_preload() failure: " + task.getError().getMessage(), @@ -403,7 +413,7 @@ private void moveToHostDestroy(@Nullable ReactContext currentContext) { * * @return The {@link BridgelessReactContext} associated with ReactInstance. */ - public @Nullable BridgelessReactContext getCurrentReactContext() { + public @Nullable ReactContext getCurrentReactContext() { return mBridgelessReactContextRef.getNullable(); } @@ -411,7 +421,8 @@ public DevSupportManager getDevSupportManager() { return assertNotNull(mDevSupportManager); } - public @Nullable Activity getCurrentActivity() { + @Nullable + /* package */ Activity getCurrentActivity() { return mActivity.get(); } @@ -423,7 +434,7 @@ public DevSupportManager getDevSupportManager() { * @return The real {@link EventDispatcher} if the instance is alive; otherwise, a {@link * BlackHoleEventDispatcher}. */ - public EventDispatcher getEventDispatcher() { + /* package */ EventDispatcher getEventDispatcher() { final ReactInstance reactInstance = mReactInstanceTaskRef.get().getResult(); if (reactInstance == null) { return BlackHoleEventDispatcher.get(); @@ -432,7 +443,8 @@ public EventDispatcher getEventDispatcher() { return reactInstance.getEventDispatcher(); } - public @Nullable FabricUIManager getUIManager() { + /* package */ @Nullable + FabricUIManager getUIManager() { final ReactInstance reactInstance = mReactInstanceTaskRef.get().getResult(); if (reactInstance == null) { return null; @@ -484,7 +496,7 @@ public MemoryPressureRouter getMemoryPressureRouter() { return mMemoryPressureRouter; } - public boolean isInstanceInitialized() { + /* package */ boolean isInstanceInitialized() { final ReactInstance reactInstance = mReactInstanceTaskRef.get().getResult(); return reactInstance != null; } @@ -554,12 +566,12 @@ public void removeReactInstanceEventListener(ReactInstanceEventListener listener }); } - /*package */ void handleException(Exception e) { - final String method = "handleException(message = \"" + e.getMessage() + "\")"; + /* package */ void handleHostException(Exception e) { + final String method = "handleHostException(message = \"" + e.getMessage() + "\")"; log(method); destroy(method, e); - mReactInstanceDelegate.handleException(e); + mReactHostDelegate.handleInstanceException(e); } /** @@ -598,13 +610,13 @@ public void removeReactInstanceEventListener(ReactInstanceEventListener listener } } - boolean isSurfaceAttached(ReactSurface surface) { + /* package */ boolean isSurfaceAttached(ReactSurface surface) { synchronized (mAttachedSurfaces) { return mAttachedSurfaces.contains(surface); } } - boolean isSurfaceWithModuleNameAttached(String moduleName) { + /* package */ boolean isSurfaceWithModuleNameAttached(String moduleName) { synchronized (mAttachedSurfaces) { for (ReactSurface surface : mAttachedSurfaces) { if (surface.getModuleName().equals(moduleName)) { @@ -615,7 +627,7 @@ boolean isSurfaceWithModuleNameAttached(String moduleName) { } } - interface VeniceThenable { + /* package */ interface VeniceThenable { void then(T t); } @@ -678,7 +690,7 @@ private Task callAfterGetOrCreateReactInstance( .continueWith( task -> { if (task.isFaulted()) { - handleException(task.getError()); + handleHostException(task.getError()); } return null; }, @@ -699,11 +711,8 @@ private BridgelessReactContext getOrCreateReactContext() { * *

If the ReactInstance is reloading, will return the reload task. If the ReactInstance is * destroying, will wait until destroy is finished, before creating. - * - * @return */ private Task getOrCreateReactInstanceTask() { - final String method = "getOrCreateReactInstanceTask()"; if (ReactFeatureFlags.enableBridgelessArchitectureNewCreateReloadDestroy) { return Task.call(this::waitThen_new_getOrCreateReactInstanceTask, mBGExecutor) .continueWithTask(Task::getResult); @@ -770,13 +779,17 @@ private Task new_getOrCreateReactInstanceTask() { final ReactInstance instance = new ReactInstance( reactContext, - mReactInstanceDelegate, + mReactHostDelegate, mComponentFactory, devSupportManager, mQueueThreadExceptionHandler, mReactJsExceptionHandler, mUseDevSupport); + if (ReactFeatureFlags + .unstable_bridgelessArchitectureMemoryPressureHackyBoltsFix) { + mMemoryPressureListener = createMemoryPressureListener(instance); + } mMemoryPressureRouter.addMemoryPressureListener(mMemoryPressureListener); log(method, "Loading JS Bundle"); @@ -860,13 +873,17 @@ private Task old_getOrCreateReactInstanceTask() { final ReactInstance instance = new ReactInstance( reactContext, - mReactInstanceDelegate, + mReactHostDelegate, mComponentFactory, devSupportManager, mQueueThreadExceptionHandler, mReactJsExceptionHandler, mUseDevSupport); + if (ReactFeatureFlags + .unstable_bridgelessArchitectureMemoryPressureHackyBoltsFix) { + mMemoryPressureListener = createMemoryPressureListener(instance); + } mMemoryPressureRouter.addMemoryPressureListener(mMemoryPressureListener); log(method, "Loading JS Bundle"); @@ -890,10 +907,10 @@ private Task old_getOrCreateReactInstanceTask() { mBGExecutor) .onSuccess( task -> { - /** - * Call ReactContext.onHostResume() only when already in the resumed state which - * aligns with the bridge https://fburl.com/diffusion/2qhxmudv. - */ + /* + Call ReactContext.onHostResume() only when already in the resumed state which + aligns with the bridge https://fburl.com/diffusion/2qhxmudv. + */ mReactLifecycleStateManager.resumeReactContextIfHostResumed( reactContext, mActivity.get()); @@ -928,7 +945,7 @@ private Task getJSBundleLoader() { // Since metro is running, fetch the JS bundle from the server return loadJSBundleFromMetro(); } - return Task.forResult(mReactInstanceDelegate.getJSBundleLoader(mContext)); + return Task.forResult(mReactHostDelegate.getJSBundleLoader(mContext)); }, mBGExecutor); } else { @@ -943,7 +960,7 @@ private Task getJSBundleLoader() { * throws an exception, the task will fault, and we'll go through the ReactHost error * reporting pipeline. */ - return Task.call(() -> mReactInstanceDelegate.getJSBundleLoader(mContext)); + return Task.call(() -> mReactHostDelegate.getJSBundleLoader(mContext)); } } @@ -1401,7 +1418,7 @@ private void old_destroyReactInstanceAndContext(final String callingMethod, fina // Noop on redundant calls to destroyReactInstance() if (instance == null) { - log(method, "ReactInstance nil"); + log(method, "ReactInstance is null"); return; } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/ReactHostDelegate.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/ReactHostDelegate.kt new file mode 100644 index 00000000000000..890682936e0edc --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/ReactHostDelegate.kt @@ -0,0 +1,62 @@ +/* + * 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. + */ + +package com.facebook.react.bridgeless + +import android.content.Context +import com.facebook.infer.annotation.ThreadSafe +import com.facebook.react.ReactPackage +import com.facebook.react.bridge.JSBundleLoader +import com.facebook.react.bridge.ReactApplicationContext +import com.facebook.react.common.annotations.UnstableReactNativeAPI +import com.facebook.react.fabric.ReactNativeConfig +import com.facebook.react.turbomodule.core.TurboModuleManager +import com.facebook.react.turbomodule.core.TurboModuleManagerDelegate + +/** TODO: add javadoc for class and methods */ +@ThreadSafe +@UnstableReactNativeAPI +interface ReactHostDelegate { + val jSMainModulePath: String + + val bindingsInstaller: BindingsInstaller + + val reactPackages: List + + fun getJSBundleLoader(context: Context): JSBundleLoader + + fun getTurboModuleManagerDelegate(context: ReactApplicationContext): TurboModuleManagerDelegate + + fun getJSEngineInstance(context: ReactApplicationContext): JSEngineInstance + + fun handleInstanceException(e: Exception) + + fun getReactNativeConfig(turboModuleManager: TurboModuleManager): ReactNativeConfig + + @UnstableReactNativeAPI + class ReactHostDelegateBase( + override val jSMainModulePath: String, + override val bindingsInstaller: BindingsInstaller, + override val reactPackages: List, + private val jsBundleLoader: JSBundleLoader, + private val turboModuleManagerDelegate: TurboModuleManagerDelegate, + private val jsEngineInstance: JSEngineInstance, + private val reactNativeConfig: ReactNativeConfig, + private val exceptionHandler: (Exception) -> Unit = {} + ) : ReactHostDelegate { + override fun getJSBundleLoader(context: Context) = jsBundleLoader + + override fun getTurboModuleManagerDelegate(context: ReactApplicationContext) = + turboModuleManagerDelegate + + override fun getJSEngineInstance(context: ReactApplicationContext) = jsEngineInstance + + override fun getReactNativeConfig(turboModuleManager: TurboModuleManager) = reactNativeConfig + + override fun handleInstanceException(e: Exception) = exceptionHandler(e) + } +} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/ReactInstance.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/ReactInstance.java index 944512441fe93e..eb3f86afcbb656 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/ReactInstance.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/ReactInstance.java @@ -9,6 +9,7 @@ import android.content.res.AssetManager; import android.view.View; +import androidx.annotation.NonNull; import com.facebook.common.logging.FLog; import com.facebook.infer.annotation.Nullsafe; import com.facebook.infer.annotation.ThreadConfined; @@ -68,13 +69,13 @@ */ @Nullsafe(Nullsafe.Mode.LOCAL) @ThreadSafe -public final class ReactInstance { +final class ReactInstance { private static final String TAG = ReactInstance.class.getSimpleName(); - @DoNotStrip private HybridData mHybridData; + @DoNotStrip private final HybridData mHybridData; - private final ReactInstanceDelegate mDelegate; + private final ReactHostDelegate mDelegate; private final BridgelessReactContext mBridgelessReactContext; private final ReactQueueConfiguration mQueueConfiguration; @@ -88,7 +89,7 @@ public final class ReactInstance { /* package */ ReactInstance( BridgelessReactContext bridgelessReactContext, - ReactInstanceDelegate delegate, + ReactHostDelegate delegate, ComponentFactory componentFactory, DevSupportManager devSupportManager, QueueThreadExceptionHandler exceptionHandler, @@ -171,17 +172,15 @@ public void onHostDestroy() { new ComponentNameResolverManager( // Use unbuffered RuntimeExecutor to install binding unbufferedRuntimeExecutor, - new ComponentNameResolver() { - @Override - public String[] getComponentNames() { - Collection viewManagerNames = getViewManagerNames(); - if (viewManagerNames == null) { - FLog.e(TAG, "No ViewManager names found"); - return new String[0]; - } - return viewManagerNames.toArray(new String[0]); - } - }); + (ComponentNameResolver) + () -> { + Collection viewManagerNames = getViewManagerNames(); + if (viewManagerNames.size() < 1) { + FLog.e(TAG, "No ViewManager names found"); + return new String[0]; + } + return viewManagerNames.toArray(new String[0]); + }); // Set up TurboModules Systrace.beginSection( @@ -198,7 +197,7 @@ public String[] getComponentNames() { // Eagerly initialize TurboModules for (String moduleName : mTurboModuleManager.getEagerInitModuleNames()) { - mTurboModuleManager.getNativeModule(moduleName); + mTurboModuleManager.getModule(moduleName); } Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE); @@ -221,7 +220,7 @@ public Collection getViewManagerNames() { } }); - EventBeatManager eventBeatManager = new EventBeatManager(mBridgelessReactContext); + EventBeatManager eventBeatManager = new EventBeatManager(); mFabricUIManager = new FabricUIManager(mBridgelessReactContext, viewManagerRegistry, eventBeatManager); @@ -290,17 +289,13 @@ public void setSourceURLs(String deviceURL, String remoteURL) { public boolean hasNativeModule(Class nativeModuleInterface) { ReactModule annotation = nativeModuleInterface.getAnnotation(ReactModule.class); if (annotation != null) { - return mTurboModuleManager.hasNativeModule(annotation.name()); + return mTurboModuleManager.hasModule(annotation.name()); } return false; } public Collection getNativeModules() { - Collection nativeModules = new ArrayList<>(); - for (NativeModule module : mTurboModuleManager.getNativeModules()) { - nativeModules.add(module); - } - return nativeModules; + return new ArrayList<>(mTurboModuleManager.getModules()); } public @Nullable T getNativeModule(Class nativeModuleInterface) { @@ -313,7 +308,7 @@ public Collection getNativeModules() { public @Nullable NativeModule getNativeModule(String nativeModuleName) { synchronized (mTurboModuleManager) { - return mTurboModuleManager.getNativeModule(nativeModuleName); + return mTurboModuleManager.getModule(nativeModuleName); } } @@ -340,11 +335,10 @@ public Collection getNativeModules() { "Starting surface without a view is not supported, use prerenderSurface instead."); } - /** - * This is a temporary mitigation for 646912b2590a6d5e760316cc064d1e27, - * - *

TODO T83828172 investigate why surface.getView() has id NOT equal to View.NO_ID - */ + /* + This is a temporary mitigation for 646912b2590a6d5e760316cc064d1e27, +

TODO T83828172 investigate why surface.getView() has id NOT equal to View.NO_ID + */ if (view.getId() != View.NO_ID) { ReactSoftExceptionLogger.logSoftException( TAG, @@ -467,7 +461,7 @@ public void registerSegment(int segmentId, String path) { return null; } - private Collection getViewManagerNames() { + private @NonNull Collection getViewManagerNames() { Set uniqueNames = new HashSet<>(); if (mDelegate != null) { List packages = mDelegate.getReactPackages(); diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/ReactInstanceDelegate.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/ReactInstanceDelegate.java deleted file mode 100644 index 1c9a9e15134276..00000000000000 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/ReactInstanceDelegate.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -package com.facebook.react.bridgeless; - -import android.content.Context; -import com.facebook.infer.annotation.ThreadSafe; -import com.facebook.react.ReactPackage; -import com.facebook.react.bridge.JSBundleLoader; -import com.facebook.react.bridge.ReactApplicationContext; -import com.facebook.react.fabric.ReactNativeConfig; -import com.facebook.react.turbomodule.core.TurboModuleManager; -import com.facebook.react.turbomodule.core.TurboModuleManagerDelegate; -import com.facebook.react.uimanager.ViewManager; -import java.util.List; - -@ThreadSafe -public interface ReactInstanceDelegate { - String getJSMainModulePath(); - - JSBundleLoader getJSBundleLoader(Context context); - - BindingsInstaller getBindingsInstaller(); - - TurboModuleManagerDelegate getTurboModuleManagerDelegate(ReactApplicationContext context); - - List getViewManagers(ReactApplicationContext context); - - JSEngineInstance getJSEngineInstance(ReactApplicationContext context); - - void handleException(Exception e); - - ReactNativeConfig getReactNativeConfig(TurboModuleManager turboModuleManager); - - List getReactPackages(); -} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/ReactSurface.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/ReactSurface.java index b9b5138f3be3f2..c7898a1c5767ba 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/ReactSurface.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/ReactSurface.java @@ -13,13 +13,13 @@ import android.view.View; import android.view.View.MeasureSpec; import androidx.annotation.UiThread; -import bolts.Task; import com.facebook.infer.annotation.Nullsafe; import com.facebook.infer.annotation.ThreadSafe; import com.facebook.react.bridge.Arguments; import com.facebook.react.bridge.NativeMap; import com.facebook.react.bridge.UiThreadUtil; import com.facebook.react.bridge.WritableNativeMap; +import com.facebook.react.bridgeless.internal.bolts.Task; import com.facebook.react.common.annotations.VisibleForTesting; import com.facebook.react.fabric.SurfaceHandler; import com.facebook.react.fabric.SurfaceHandlerBinding; @@ -32,7 +32,6 @@ @Nullsafe(Nullsafe.Mode.LOCAL) @ThreadSafe public class ReactSurface { - private static final String TAG = "ReactSurface"; private final AtomicReference mSurfaceView = new AtomicReference<>(null); @@ -180,14 +179,11 @@ public String getModuleName() { public void clear() { UiThreadUtil.runOnUiThread( - new Runnable() { - @Override - public void run() { - ReactSurfaceView view = getView(); - if (view != null) { - view.removeAllViews(); - view.setId(View.NO_ID); - } + () -> { + ReactSurfaceView view = getView(); + if (view != null) { + view.removeAllViews(); + view.setId(View.NO_ID); } }); } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/ReactSurfaceView.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/ReactSurfaceView.java index eae0988ba7e515..5d6832624c0c6e 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/ReactSurfaceView.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/ReactSurfaceView.java @@ -25,6 +25,7 @@ import com.facebook.react.uimanager.common.UIManagerType; import com.facebook.react.uimanager.events.EventDispatcher; import com.facebook.systrace.Systrace; +import java.util.Objects; /** A view created by {@link ReactSurface} that's responsible for rendering a React component. */ @Nullsafe(Nullsafe.Mode.LOCAL) @@ -161,10 +162,11 @@ public void onChildEndedNativeGesture(View childView, MotionEvent ev) { @Override public void handleException(Throwable t) { - if (mSurface.getReactHost() != null) { - String errorMessage = t.getMessage() == null ? "" : t.getMessage(); + ReactHost reactHost = mSurface.getReactHost(); + if (reactHost != null) { + String errorMessage = Objects.toString(t.getMessage(), ""); Exception e = new IllegalViewOperationException(errorMessage, this, t); - mSurface.getReactHost().handleException(e); + reactHost.handleHostException(e); } } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/exceptionmanager/ReactJsExceptionHandler.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/exceptionmanager/ReactJsExceptionHandler.java index 470bf037bbb6de..a05e6471911a9b 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/exceptionmanager/ReactJsExceptionHandler.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/exceptionmanager/ReactJsExceptionHandler.java @@ -13,5 +13,5 @@ @DoNotStripAny public interface ReactJsExceptionHandler { - public void reportJsException(ReadableMapBuffer errorMap); + void reportJsException(ReadableMapBuffer errorMap); } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/internal/bolts/AggregateException.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/internal/bolts/AggregateException.java new file mode 100644 index 00000000000000..99d0351547da04 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/internal/bolts/AggregateException.java @@ -0,0 +1,125 @@ +/* + * 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. + */ + +package com.facebook.react.bridgeless.internal.bolts; + +import java.io.PrintStream; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +/** + * Aggregates multiple {@code Throwable}s that may be thrown in the process of a task's execution. + * + * @see Task#whenAll(java.util.Collection) + */ +public class AggregateException extends Exception { + private static final long serialVersionUID = 1L; + + private static final String DEFAULT_MESSAGE = "There were multiple errors."; + + private List innerThrowables; + + /** + * Constructs a new {@code AggregateException} with the current stack trace, the specified detail + * message and with references to the inner throwables that are the cause of this exception. + * + * @param detailMessage The detail message for this exception. + * @param innerThrowables The exceptions that are the cause of the current exception. + */ + public AggregateException(String detailMessage, Throwable[] innerThrowables) { + this(detailMessage, Arrays.asList(innerThrowables)); + } + + /** + * Constructs a new {@code AggregateException} with the current stack trace, the specified detail + * message and with references to the inner throwables that are the cause of this exception. + * + * @param detailMessage The detail message for this exception. + * @param innerThrowables The exceptions that are the cause of the current exception. + */ + public AggregateException(String detailMessage, List innerThrowables) { + super( + detailMessage, + innerThrowables != null && innerThrowables.size() > 0 ? innerThrowables.get(0) : null); + this.innerThrowables = Collections.unmodifiableList(innerThrowables); + } + + /** + * Constructs a new {@code AggregateException} with the current stack trace and with references to + * the inner throwables that are the cause of this exception. + * + * @param innerThrowables The exceptions that are the cause of the current exception. + */ + public AggregateException(List innerThrowables) { + this(DEFAULT_MESSAGE, innerThrowables); + } + + /** + * Returns a read-only {@link List} of the {@link Throwable} instances that caused the current + * exception. + */ + public List getInnerThrowables() { + return innerThrowables; + } + + @Override + public void printStackTrace(PrintStream err) { + super.printStackTrace(err); + + int currentIndex = -1; + for (Throwable throwable : innerThrowables) { + err.append("\n"); + err.append(" Inner throwable #"); + err.append(Integer.toString(++currentIndex)); + err.append(": "); + throwable.printStackTrace(err); + err.append("\n"); + } + } + + @Override + public void printStackTrace(PrintWriter err) { + super.printStackTrace(err); + + int currentIndex = -1; + for (Throwable throwable : innerThrowables) { + err.append("\n"); + err.append(" Inner throwable #"); + err.append(Integer.toString(++currentIndex)); + err.append(": "); + throwable.printStackTrace(err); + err.append("\n"); + } + } + + /** @deprecated Please use {@link #getInnerThrowables()} instead. */ + @Deprecated + public List getErrors() { + List errors = new ArrayList(); + if (innerThrowables == null) { + return errors; + } + + for (Throwable cause : innerThrowables) { + if (cause instanceof Exception) { + errors.add((Exception) cause); + } else { + errors.add(new Exception(cause)); + } + } + return errors; + } + + /** @deprecated Please use {@link #getInnerThrowables()} instead. */ + @Deprecated + public Throwable[] getCauses() { + return innerThrowables.toArray(new Throwable[innerThrowables.size()]); + } +} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/internal/bolts/AndroidExecutors.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/internal/bolts/AndroidExecutors.java new file mode 100644 index 00000000000000..3d87da1bc3a27e --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/internal/bolts/AndroidExecutors.java @@ -0,0 +1,135 @@ +/* + * 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. + */ + +package com.facebook.react.bridgeless.internal.bolts; + +import android.annotation.SuppressLint; +import android.os.Build; +import android.os.Handler; +import android.os.Looper; +import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +/** + * This was created because the helper methods in {@link java.util.concurrent.Executors} do not work + * as people would normally expect. + * + *

Normally, you would think that a cached thread pool would create new threads when necessary, + * queue them when the pool is full, and kill threads when they've been inactive for a certain + * period of time. This is not how {@link java.util.concurrent.Executors#newCachedThreadPool()} + * works. + * + *

Instead, {@link java.util.concurrent.Executors#newCachedThreadPool()} executes all tasks on a + * new or cached thread immediately because corePoolSize is 0, SynchronousQueue is a queue with size + * 0 and maxPoolSize is Integer.MAX_VALUE. This is dangerous because it can create an unchecked + * amount of threads. + */ +/* package */ final class AndroidExecutors { + + private static final AndroidExecutors INSTANCE = new AndroidExecutors(); + + private final Executor uiThread; + + private AndroidExecutors() { + uiThread = new UIThreadExecutor(); + } + + /** + * Nexus 5: Quad-Core Moto X: Dual-Core + * + *

AsyncTask: CORE_POOL_SIZE = CPU_COUNT + 1 MAX_POOL_SIZE = CPU_COUNT * 2 + 1 + * + *

https://github.com/android/platform_frameworks_base/commit/719c44e03b97e850a46136ba336d729f5fbd1f47 + */ + private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors(); + /* package */ static final int CORE_POOL_SIZE = CPU_COUNT + 1; + /* package */ static final int MAX_POOL_SIZE = CPU_COUNT * 2 + 1; + /* package */ static final long KEEP_ALIVE_TIME = 1L; + + /** + * Creates a proper Cached Thread Pool. Tasks will reuse cached threads if available or create new + * threads until the core pool is full. tasks will then be queued. If an task cannot be queued, a + * new thread will be created unless this would exceed max pool size, then the task will be + * rejected. Threads will time out after 1 second. + * + *

Core thread timeout is only available on android-9+. + * + * @return the newly created thread pool + */ + public static ExecutorService newCachedThreadPool() { + ThreadPoolExecutor executor = + new ThreadPoolExecutor( + CORE_POOL_SIZE, + MAX_POOL_SIZE, + KEEP_ALIVE_TIME, + TimeUnit.SECONDS, + new LinkedBlockingQueue()); + + allowCoreThreadTimeout(executor, true); + + return executor; + } + + /** + * Creates a proper Cached Thread Pool. Tasks will reuse cached threads if available or create new + * threads until the core pool is full. tasks will then be queued. If an task cannot be queued, a + * new thread will be created unless this would exceed max pool size, then the task will be + * rejected. Threads will time out after 1 second. + * + *

Core thread timeout is only available on android-9+. + * + * @param threadFactory the factory to use when creating new threads + * @return the newly created thread pool + */ + public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) { + ThreadPoolExecutor executor = + new ThreadPoolExecutor( + CORE_POOL_SIZE, + MAX_POOL_SIZE, + KEEP_ALIVE_TIME, + TimeUnit.SECONDS, + new LinkedBlockingQueue(), + threadFactory); + + allowCoreThreadTimeout(executor, true); + + return executor; + } + + /** + * Compatibility helper function for {@link + * java.util.concurrent.ThreadPoolExecutor#allowCoreThreadTimeOut(boolean)} + * + *

Only available on android-9+. + * + * @param executor the {@link java.util.concurrent.ThreadPoolExecutor} + * @param value true if should time out, else false + */ + @SuppressLint("NewApi") + public static void allowCoreThreadTimeout(ThreadPoolExecutor executor, boolean value) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) { + executor.allowCoreThreadTimeOut(value); + } + } + + /** An {@link java.util.concurrent.Executor} that executes tasks on the UI thread. */ + public static Executor uiThread() { + return INSTANCE.uiThread; + } + + /** An {@link java.util.concurrent.Executor} that runs tasks on the UI thread. */ + private static class UIThreadExecutor implements Executor { + @Override + public void execute(Runnable command) { + new Handler(Looper.getMainLooper()).post(command); + } + } +} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/internal/bolts/BoltsExecutors.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/internal/bolts/BoltsExecutors.java new file mode 100644 index 00000000000000..0f3fc9c354ad7d --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/internal/bolts/BoltsExecutors.java @@ -0,0 +1,118 @@ +/* + * 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. + */ + +package com.facebook.react.bridgeless.internal.bolts; + +import java.util.Locale; +import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; + +/** Collection of {@link Executor}s to use in conjunction with {@link Task}. */ +/* package */ final class BoltsExecutors { + + private static final BoltsExecutors INSTANCE = new BoltsExecutors(); + + private static boolean isAndroidRuntime() { + String javaRuntimeName = System.getProperty("java.runtime.name"); + if (javaRuntimeName == null) { + return false; + } + return javaRuntimeName.toLowerCase(Locale.US).contains("android"); + } + + private final ExecutorService background; + private final ScheduledExecutorService scheduled; + private final Executor immediate; + + private BoltsExecutors() { + background = + !isAndroidRuntime() + ? java.util.concurrent.Executors.newCachedThreadPool() + : AndroidExecutors.newCachedThreadPool(); + scheduled = Executors.newSingleThreadScheduledExecutor(); + immediate = new ImmediateExecutor(); + } + + /** An {@link java.util.concurrent.Executor} that executes tasks in parallel. */ + public static ExecutorService background() { + return INSTANCE.background; + } + + /* package */ static ScheduledExecutorService scheduled() { + return INSTANCE.scheduled; + } + + /** + * An {@link java.util.concurrent.Executor} that executes tasks in the current thread unless the + * stack runs too deep, at which point it will delegate to {@link BoltsExecutors#background} in + * order to trim the stack. + */ + /* package */ static Executor immediate() { + return INSTANCE.immediate; + } + + /** + * An {@link java.util.concurrent.Executor} that runs a runnable inline (rather than scheduling it + * on a thread pool) as long as the recursion depth is less than MAX_DEPTH. If the executor has + * recursed too deeply, it will instead delegate to the {@link Task#BACKGROUND_EXECUTOR} in order + * to trim the stack. + */ + private static class ImmediateExecutor implements Executor { + private static final int MAX_DEPTH = 15; + private ThreadLocal executionDepth = new ThreadLocal<>(); + + /** + * Increments the depth. + * + * @return the new depth value. + */ + private int incrementDepth() { + Integer oldDepth = executionDepth.get(); + if (oldDepth == null) { + oldDepth = 0; + } + int newDepth = oldDepth + 1; + executionDepth.set(newDepth); + return newDepth; + } + + /** + * Decrements the depth. + * + * @return the new depth value. + */ + private int decrementDepth() { + Integer oldDepth = executionDepth.get(); + if (oldDepth == null) { + oldDepth = 0; + } + int newDepth = oldDepth - 1; + if (newDepth == 0) { + executionDepth.remove(); + } else { + executionDepth.set(newDepth); + } + return newDepth; + } + + @Override + public void execute(Runnable command) { + int depth = incrementDepth(); + try { + if (depth <= MAX_DEPTH) { + command.run(); + } else { + BoltsExecutors.background().execute(command); + } + } finally { + decrementDepth(); + } + } + } +} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/internal/bolts/CancellationToken.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/internal/bolts/CancellationToken.java new file mode 100644 index 00000000000000..5baba3bd66fa83 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/internal/bolts/CancellationToken.java @@ -0,0 +1,73 @@ +/* + * 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. + */ + +package com.facebook.react.bridgeless.internal.bolts; + +import java.util.Locale; +import java.util.concurrent.CancellationException; + +/** + * Propagates notification that operations should be canceled. + * + *

Create an instance of {@code CancellationTokenSource} and pass the token returned from {@code + * CancellationTokenSource#getToken()} to the asynchronous operation(s). Call {@code + * CancellationTokenSource#cancel()} to cancel the operations. + * + *

A {@code CancellationToken} can only be cancelled once - it should not be passed to future + * operations once cancelled. + * + * @see CancellationTokenSource + * @see CancellationTokenSource#getToken() + * @see CancellationTokenSource#cancel() + * @see CancellationToken#register(Runnable) + */ +public class CancellationToken { + + private final CancellationTokenSource tokenSource; + + /* package */ CancellationToken(CancellationTokenSource tokenSource) { + this.tokenSource = tokenSource; + } + + /** + * @return {@code true} if the cancellation was requested from the source, {@code false} + * otherwise. + */ + public boolean isCancellationRequested() { + return tokenSource.isCancellationRequested(); + } + + /** + * Registers a runnable that will be called when this CancellationToken is canceled. If this token + * is already in the canceled state, the runnable will be run immediately and synchronously. + * + * @param action the runnable to be run when the token is cancelled. + * @return a {@link CancellationTokenRegistration} instance that can be used to unregister the + * action. + */ + public CancellationTokenRegistration register(Runnable action) { + return tokenSource.register(action); + } + + /** + * @throws CancellationException if this token has had cancellation requested. May be used to stop + * execution of a thread or runnable. + */ + public void throwIfCancellationRequested() throws CancellationException { + tokenSource.throwIfCancellationRequested(); + } + + @Override + public String toString() { + return String.format( + Locale.US, + "%s@%s[cancellationRequested=%s]", + getClass().getName(), + Integer.toHexString(hashCode()), + Boolean.toString(tokenSource.isCancellationRequested())); + } +} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/internal/bolts/CancellationTokenRegistration.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/internal/bolts/CancellationTokenRegistration.java new file mode 100644 index 00000000000000..67099fe7237746 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/internal/bolts/CancellationTokenRegistration.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +package com.facebook.react.bridgeless.internal.bolts; + +import java.io.Closeable; + +/** + * Represents a callback delegate that has been registered with a {@link CancellationToken}. + * + * @see CancellationToken#register(Runnable) + */ +public class CancellationTokenRegistration implements Closeable { + + private final Object lock = new Object(); + private CancellationTokenSource tokenSource; + private Runnable action; + private boolean closed; + + /* package */ CancellationTokenRegistration( + CancellationTokenSource tokenSource, Runnable action) { + this.tokenSource = tokenSource; + this.action = action; + } + + /** Unregisters the callback runnable from the cancellation token. */ + @Override + public void close() { + synchronized (lock) { + if (closed) { + return; + } + + closed = true; + tokenSource.unregister(this); + tokenSource = null; + action = null; + } + } + + /* package */ void runAction() { + synchronized (lock) { + throwIfClosed(); + action.run(); + close(); + } + } + + private void throwIfClosed() { + if (closed) { + throw new IllegalStateException("Object already closed"); + } + } +} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/internal/bolts/CancellationTokenSource.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/internal/bolts/CancellationTokenSource.java new file mode 100644 index 00000000000000..4b20b3ff0560ad --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/internal/bolts/CancellationTokenSource.java @@ -0,0 +1,213 @@ +/* + * 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. + */ + +package com.facebook.react.bridgeless.internal.bolts; + +import java.io.Closeable; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.concurrent.CancellationException; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +/** + * Signals to a {@link CancellationToken} that it should be canceled. To create a {@code + * CancellationToken} first create a {@code CancellationTokenSource} then call {@link #getToken()} + * to retrieve the token for the source. + * + * @see CancellationToken + * @see CancellationTokenSource#getToken() + */ +public class CancellationTokenSource implements Closeable { + + private final Object lock = new Object(); + private final List registrations = new ArrayList<>(); + private final ScheduledExecutorService executor = BoltsExecutors.scheduled(); + private ScheduledFuture scheduledCancellation; + private boolean cancellationRequested; + private boolean closed; + + /** Create a new {@code CancellationTokenSource}. */ + public CancellationTokenSource() {} + + /** + * @return {@code true} if cancellation has been requested for this {@code + * CancellationTokenSource}. + */ + public boolean isCancellationRequested() { + synchronized (lock) { + throwIfClosed(); + return cancellationRequested; + } + } + + /** @return the token that can be passed to asynchronous method to control cancellation. */ + public CancellationToken getToken() { + synchronized (lock) { + throwIfClosed(); + return new CancellationToken(this); + } + } + + /** Cancels the token if it has not already been cancelled. */ + public void cancel() { + List registrations; + synchronized (lock) { + throwIfClosed(); + if (cancellationRequested) { + return; + } + + cancelScheduledCancellation(); + + cancellationRequested = true; + registrations = new ArrayList<>(this.registrations); + } + notifyListeners(registrations); + } + + /** + * Schedules a cancel operation on this {@code CancellationTokenSource} after the specified number + * of milliseconds. + * + * @param delay The number of milliseconds to wait before completing the returned task. If delay + * is {@code 0} the cancel is executed immediately. If delay is {@code -1} any scheduled + * cancellation is stopped. + */ + public void cancelAfter(final long delay) { + cancelAfter(delay, TimeUnit.MILLISECONDS); + } + + private void cancelAfter(long delay, TimeUnit timeUnit) { + if (delay < -1) { + throw new IllegalArgumentException("Delay must be >= -1"); + } + + if (delay == 0) { + cancel(); + return; + } + + synchronized (lock) { + if (cancellationRequested) { + return; + } + + cancelScheduledCancellation(); + + if (delay != -1) { + scheduledCancellation = + executor.schedule( + new Runnable() { + @Override + public void run() { + synchronized (lock) { + scheduledCancellation = null; + } + cancel(); + } + }, + delay, + timeUnit); + } + } + } + + @Override + public void close() { + synchronized (lock) { + if (closed) { + return; + } + + cancelScheduledCancellation(); + + List registrations = new ArrayList<>(this.registrations); + for (CancellationTokenRegistration registration : registrations) { + registration.close(); + } + this.registrations.clear(); + closed = true; + } + } + + /* package */ CancellationTokenRegistration register(Runnable action) { + CancellationTokenRegistration ctr; + synchronized (lock) { + throwIfClosed(); + + ctr = new CancellationTokenRegistration(this, action); + if (cancellationRequested) { + ctr.runAction(); + } else { + registrations.add(ctr); + } + } + return ctr; + } + + /** + * @throws CancellationException if this token has had cancellation requested. May be used to stop + * execution of a thread or runnable. + */ + /* package */ void throwIfCancellationRequested() throws CancellationException { + synchronized (lock) { + throwIfClosed(); + if (cancellationRequested) { + throw new CancellationException(); + } + } + } + + /* package */ void unregister(CancellationTokenRegistration registration) { + synchronized (lock) { + throwIfClosed(); + registrations.remove(registration); + } + } + + // This method makes no attempt to perform any synchronization or state checks itself and once + // invoked will notify all runnables unconditionally. As such if you require the notification + // event + // to be synchronized with state changes you should provide external synchronization. + // If this is invoked without external synchronization there is a probability the token becomes + // cancelled concurrently. + private void notifyListeners(List registrations) { + for (CancellationTokenRegistration registration : registrations) { + registration.runAction(); + } + } + + @Override + public String toString() { + return String.format( + Locale.US, + "%s@%s[cancellationRequested=%s]", + getClass().getName(), + Integer.toHexString(hashCode()), + Boolean.toString(isCancellationRequested())); + } + + // This method makes no attempt to perform any synchronization itself - you should ensure + // accesses to this method are synchronized if you want to ensure correct behaviour in the + // face of a concurrent invocation of the close method. + private void throwIfClosed() { + if (closed) { + throw new IllegalStateException("Object already closed"); + } + } + + // Performs no synchronization. + private void cancelScheduledCancellation() { + if (scheduledCancellation != null) { + scheduledCancellation.cancel(true); + scheduledCancellation = null; + } + } +} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/internal/bolts/Capture.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/internal/bolts/Capture.java new file mode 100644 index 00000000000000..1689c354bb9e46 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/internal/bolts/Capture.java @@ -0,0 +1,31 @@ +/* + * 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. + */ + +package com.facebook.react.bridgeless.internal.bolts; + +/** + * Provides a class that can be used for capturing variables in an anonymous class implementation. + * + * @param + */ +public class Capture { + private T value; + + public Capture() {} + + public Capture(T value) { + this.value = value; + } + + public T get() { + return value; + } + + public void set(T value) { + this.value = value; + } +} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/internal/bolts/Continuation.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/internal/bolts/Continuation.java new file mode 100644 index 00000000000000..c271f9d70c3248 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/internal/bolts/Continuation.java @@ -0,0 +1,20 @@ +/* + * 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. + */ + +package com.facebook.react.bridgeless.internal.bolts; + +/** + * A function to be called after a task completes. + * + *

If you wish to have the Task from a Continuation that does not return a Task be cancelled then + * throw a {@link java.util.concurrent.CancellationException} from the Continuation. + * + * @see Task + */ +public interface Continuation { + TContinuationResult then(Task task) throws Exception; +} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/internal/bolts/ExecutorException.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/internal/bolts/ExecutorException.java new file mode 100644 index 00000000000000..146acdbc1e635a --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/internal/bolts/ExecutorException.java @@ -0,0 +1,19 @@ +/* + * 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. + */ + +package com.facebook.react.bridgeless.internal.bolts; + +/** + * This is a wrapper class for emphasizing that task failed due to bad {@code Executor}, rather than + * the continuation block it self. + */ +public class ExecutorException extends RuntimeException { + + public ExecutorException(Exception e) { + super("An exception was thrown by an Executor", e); + } +} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/internal/bolts/Task.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/internal/bolts/Task.java new file mode 100644 index 00000000000000..499afcab9d1c4c --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/internal/bolts/Task.java @@ -0,0 +1,1013 @@ +/* + * 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. + */ + +package com.facebook.react.bridgeless.internal.bolts; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.CancellationException; +import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * Represents the result of an asynchronous operation. + * + * @param The type of the result of the task. + */ +public class Task { + /** An {@link java.util.concurrent.Executor} that executes tasks in parallel. */ + public static final ExecutorService BACKGROUND_EXECUTOR = BoltsExecutors.background(); + + /** + * An {@link java.util.concurrent.Executor} that executes tasks in the current thread unless the + * stack runs too deep, at which point it will delegate to {@link Task#BACKGROUND_EXECUTOR} in + * order to trim the stack. + */ + private static final Executor IMMEDIATE_EXECUTOR = BoltsExecutors.immediate(); + + /** An {@link java.util.concurrent.Executor} that executes tasks on the UI thread. */ + public static final Executor UI_THREAD_EXECUTOR = AndroidExecutors.uiThread(); + + /** + * Interface for handlers invoked when a failed {@code Task} is about to be finalized, but the + * exception has not been consumed. + * + *

The handler will execute in the GC thread, so if the handler needs to do anything time + * consuming or complex it is a good idea to fire off a {@code Task} to handle the exception. + * + * @see #getUnobservedExceptionHandler + * @see #setUnobservedExceptionHandler + */ + public interface UnobservedExceptionHandler { + /** + * Method invoked when the given task has an unobserved exception. + * + *

Any exception thrown by this method will be ignored. + * + * @param t the task + * @param e the exception + */ + void unobservedException(Task t, UnobservedTaskException e); + } + + // null unless explicitly set + private static volatile UnobservedExceptionHandler unobservedExceptionHandler; + + /** Returns the handler invoked when a task has an unobserved exception or {@code null}. */ + public static UnobservedExceptionHandler getUnobservedExceptionHandler() { + return unobservedExceptionHandler; + } + + /** + * Set the handler invoked when a task has an unobserved exception. + * + * @param eh the object to use as an unobserved exception handler. If null then + * unobserved exceptions will be ignored. + */ + public static void setUnobservedExceptionHandler(UnobservedExceptionHandler eh) { + unobservedExceptionHandler = eh; + } + + private final Object lock = new Object(); + private boolean complete; + private boolean cancelled; + private TResult result; + private Exception error; + private boolean errorHasBeenObserved; + private UnobservedErrorNotifier unobservedErrorNotifier; + private List> continuations = new ArrayList<>(); + + /* package */ Task() {} + + private Task(TResult result) { + trySetResult(result); + } + + private Task(boolean cancelled) { + if (cancelled) { + trySetCancelled(); + } else { + trySetResult(null); + } + } + + public static TaskCompletionSource create() { + Task task = new Task<>(); + return new TaskCompletionSource(); + } + + /** + * @return {@code true} if the task completed (has a result, an error, or was cancelled. {@code + * false} otherwise. + */ + public boolean isCompleted() { + synchronized (lock) { + return complete; + } + } + + /** @return {@code true} if the task was cancelled, {@code false} otherwise. */ + public boolean isCancelled() { + synchronized (lock) { + return cancelled; + } + } + + /** @return {@code true} if the task has an error, {@code false} otherwise. */ + public boolean isFaulted() { + synchronized (lock) { + return getError() != null; + } + } + + /** @return The result of the task, if set. {@code null} otherwise. */ + public TResult getResult() { + synchronized (lock) { + return result; + } + } + + /** @return The error for the task, if set. {@code null} otherwise. */ + public Exception getError() { + synchronized (lock) { + if (error != null) { + errorHasBeenObserved = true; + if (unobservedErrorNotifier != null) { + unobservedErrorNotifier.setObserved(); + unobservedErrorNotifier = null; + } + } + return error; + } + } + + /** Blocks until the task is complete. */ + public void waitForCompletion() throws InterruptedException { + synchronized (lock) { + if (!isCompleted()) { + lock.wait(); + } + } + } + + /** + * Blocks until the task is complete or times out. + * + * @return {@code true} if the task completed (has a result, an error, or was cancelled). {@code + * false} otherwise. + */ + public boolean waitForCompletion(long duration, TimeUnit timeUnit) throws InterruptedException { + synchronized (lock) { + if (!isCompleted()) { + lock.wait(timeUnit.toMillis(duration)); + } + return isCompleted(); + } + } + + /** Creates a completed task with the given value. */ + @SuppressWarnings("unchecked") + public static Task forResult(TResult value) { + if (value == null) { + return (Task) TASK_NULL; + } + if (value instanceof Boolean) { + return (Task) ((Boolean) value ? TASK_TRUE : TASK_FALSE); + } + TaskCompletionSource tcs = new TaskCompletionSource<>(); + tcs.setResult(value); + return tcs.getTask(); + } + + /** Creates a faulted task with the given error. */ + public static Task forError(Exception error) { + TaskCompletionSource tcs = new TaskCompletionSource<>(); + tcs.setError(error); + return tcs.getTask(); + } + + /** Creates a cancelled task. */ + @SuppressWarnings("unchecked") + public static Task cancelled() { + return (Task) TASK_CANCELLED; + } + + /** + * Creates a task that completes after a time delay. + * + * @param delay The number of milliseconds to wait before completing the returned task. Zero and + * negative values are treated as requests for immediate execution. + */ + public static Task delay(long delay) { + return delay(delay, BoltsExecutors.scheduled(), null); + } + + /** + * Creates a task that completes after a time delay. + * + * @param delay The number of milliseconds to wait before completing the returned task. Zero and + * negative values are treated as requests for immediate execution. + * @param cancellationToken The optional cancellation token that will be checked prior to + * completing the returned task. + */ + public static Task delay(long delay, CancellationToken cancellationToken) { + return delay(delay, BoltsExecutors.scheduled(), cancellationToken); + } + + /* package */ static Task delay( + long delay, ScheduledExecutorService executor, final CancellationToken cancellationToken) { + if (cancellationToken != null && cancellationToken.isCancellationRequested()) { + return Task.cancelled(); + } + + if (delay <= 0) { + return Task.forResult(null); + } + + final TaskCompletionSource tcs = new TaskCompletionSource<>(); + final ScheduledFuture scheduled = + executor.schedule( + new Runnable() { + @Override + public void run() { + tcs.trySetResult(null); + } + }, + delay, + TimeUnit.MILLISECONDS); + + if (cancellationToken != null) { + cancellationToken.register( + new Runnable() { + @Override + public void run() { + scheduled.cancel(true); + tcs.trySetCancelled(); + } + }); + } + + return tcs.getTask(); + } + + /** + * Makes a fluent cast of a Task's result possible, avoiding an extra continuation just to cast + * the type of the result. + */ + public Task cast() { + @SuppressWarnings("unchecked") + Task task = (Task) this; + return task; + } + + /** Turns a Task into a Task, dropping any result. */ + public Task makeVoid() { + return this.continueWithTask( + new Continuation>() { + @Override + public Task then(Task task) throws Exception { + if (task.isCancelled()) { + return Task.cancelled(); + } + if (task.isFaulted()) { + return Task.forError(task.getError()); + } + return Task.forResult(null); + } + }); + } + + /** + * Invokes the callable on a background thread, returning a Task to represent the operation. + * + *

If you want to cancel the resulting Task throw a {@link + * java.util.concurrent.CancellationException} from the callable. + */ + public static Task callInBackground(Callable callable) { + return call(callable, BACKGROUND_EXECUTOR, null); + } + + /** Invokes the callable on a background thread, returning a Task to represent the operation. */ + public static Task callInBackground( + Callable callable, CancellationToken ct) { + return call(callable, BACKGROUND_EXECUTOR, ct); + } + + /** + * Invokes the callable using the given executor, returning a Task to represent the operation. + * + *

If you want to cancel the resulting Task throw a {@link + * java.util.concurrent.CancellationException} from the callable. + */ + public static Task call(final Callable callable, Executor executor) { + return call(callable, executor, null); + } + + /** Invokes the callable using the given executor, returning a Task to represent the operation. */ + public static Task call( + final Callable callable, Executor executor, final CancellationToken ct) { + final TaskCompletionSource tcs = new TaskCompletionSource<>(); + try { + executor.execute( + new Runnable() { + @Override + public void run() { + if (ct != null && ct.isCancellationRequested()) { + tcs.setCancelled(); + return; + } + + try { + tcs.setResult(callable.call()); + } catch (CancellationException e) { + tcs.setCancelled(); + } catch (Exception e) { + tcs.setError(e); + } + } + }); + } catch (Exception e) { + tcs.setError(new ExecutorException(e)); + } + + return tcs.getTask(); + } + + /** + * Invokes the callable on the current thread, producing a Task. + * + *

If you want to cancel the resulting Task throw a {@link + * java.util.concurrent.CancellationException} from the callable. + */ + public static Task call(final Callable callable) { + return call(callable, IMMEDIATE_EXECUTOR, null); + } + + /** Invokes the callable on the current thread, producing a Task. */ + public static Task call( + final Callable callable, CancellationToken ct) { + return call(callable, IMMEDIATE_EXECUTOR, ct); + } + + /** + * Creates a task that will complete when any of the supplied tasks have completed. + * + *

The returned task will complete when any of the supplied tasks has completed. The returned + * task will always end in the completed state with its result set to the first task to complete. + * This is true even if the first task to complete ended in the canceled or faulted state. + * + * @param tasks The tasks to wait on for completion. + * @return A task that represents the completion of one of the supplied tasks. The return task's + * result is the task that completed. + */ + public static Task> whenAnyResult( + Collection> tasks) { + if (tasks.size() == 0) { + return Task.forResult(null); + } + + final TaskCompletionSource> firstCompleted = new TaskCompletionSource<>(); + final AtomicBoolean isAnyTaskComplete = new AtomicBoolean(false); + + for (Task task : tasks) { + task.continueWith( + new Continuation() { + @Override + public Void then(Task task) { + if (isAnyTaskComplete.compareAndSet(false, true)) { + firstCompleted.setResult(task); + } else { + Throwable ensureObserved = task.getError(); + } + return null; + } + }); + } + return firstCompleted.getTask(); + } + + /** + * Creates a task that will complete when any of the supplied tasks have completed. + * + *

The returned task will complete when any of the supplied tasks has completed. The returned + * task will always end in the completed state with its result set to the first task to complete. + * This is true even if the first task to complete ended in the canceled or faulted state. + * + * @param tasks The tasks to wait on for completion. + * @return A task that represents the completion of one of the supplied tasks. The return task's + * Result is the task that completed. + */ + @SuppressWarnings("unchecked") + public static Task> whenAny(Collection> tasks) { + if (tasks.size() == 0) { + return Task.forResult(null); + } + + final TaskCompletionSource> firstCompleted = new TaskCompletionSource<>(); + final AtomicBoolean isAnyTaskComplete = new AtomicBoolean(false); + + for (Task task : tasks) { + ((Task) task) + .continueWith( + new Continuation() { + @Override + public Void then(Task task) { + if (isAnyTaskComplete.compareAndSet(false, true)) { + firstCompleted.setResult(task); + } else { + Throwable ensureObserved = task.getError(); + } + return null; + } + }); + } + return firstCompleted.getTask(); + } + + /** + * Creates a task that completes when all of the provided tasks are complete. + * + *

If any of the supplied tasks completes in a faulted state, the returned task will also + * complete in a faulted state, where its exception will resolve to that {@link + * java.lang.Exception} if a single task fails or an {@link AggregateException} of all the {@link + * java.lang.Exception}s if multiple tasks fail. + * + *

If none of the supplied tasks faulted but at least one of them was cancelled, the returned + * task will end as cancelled. + * + *

If none of the tasks faulted and none of the tasks were cancelled, the resulting task will + * end completed. The result of the returned task will be set to a list containing all of the + * results of the supplied tasks in the same order as they were provided (e.g. if the input tasks + * collection contained t1, t2, t3, the output task's result will return an {@code + * List<TResult>} where {@code list.get(0) == t1.getResult(), list.get(1) == t2.getResult(), + * and list.get(2) == t3.getResult()}). + * + *

If the supplied collection contains no tasks, the returned task will immediately transition + * to a completed state before it's returned to the caller. The returned {@code + * List<TResult>} will contain 0 elements. + * + * @param tasks The tasks that the return value will wait for before completing. + * @return A Task that will resolve to {@code List<TResult>} when all the tasks are + * resolved. + */ + public static Task> whenAllResult( + final Collection> tasks) { + return whenAll(tasks) + .onSuccess( + new Continuation>() { + @Override + public List then(Task task) throws Exception { + if (tasks.size() == 0) { + return Collections.emptyList(); + } + + List results = new ArrayList<>(); + for (Task individualTask : tasks) { + results.add(individualTask.getResult()); + } + return results; + } + }); + } + + /** + * Creates a task that completes when all of the provided tasks are complete. + * + *

If any of the supplied tasks completes in a faulted state, the returned task will also + * complete in a faulted state, where its exception will resolve to that {@link + * java.lang.Exception} if a single task fails or an {@link AggregateException} of all the {@link + * java.lang.Exception}s if multiple tasks fail. + * + *

If none of the supplied tasks faulted but at least one of them was cancelled, the returned + * task will end as cancelled. + * + *

If none of the tasks faulted and none of the tasks were canceled, the resulting task will + * end in the completed state. + * + *

If the supplied collection contains no tasks, the returned task will immediately transition + * to a completed state before it's returned to the caller. + * + * @param tasks The tasks that the return value will wait for before completing. + * @return A Task that will resolve to {@code Void} when all the tasks are resolved. + */ + public static Task whenAll(Collection> tasks) { + if (tasks.size() == 0) { + return Task.forResult(null); + } + + final TaskCompletionSource allFinished = new TaskCompletionSource<>(); + final ArrayList causes = new ArrayList<>(); + final Object errorLock = new Object(); + final AtomicInteger count = new AtomicInteger(tasks.size()); + final AtomicBoolean isCancelled = new AtomicBoolean(false); + + for (Task task : tasks) { + @SuppressWarnings("unchecked") + Task t = (Task) task; + t.continueWith( + new Continuation() { + @Override + public Void then(Task task) { + if (task.isFaulted()) { + synchronized (errorLock) { + causes.add(task.getError()); + } + } + + if (task.isCancelled()) { + isCancelled.set(true); + } + + if (count.decrementAndGet() == 0) { + if (causes.size() != 0) { + if (causes.size() == 1) { + allFinished.setError(causes.get(0)); + } else { + Exception error = + new AggregateException( + String.format("There were %d exceptions.", causes.size()), causes); + allFinished.setError(error); + } + } else if (isCancelled.get()) { + allFinished.setCancelled(); + } else { + allFinished.setResult(null); + } + } + return null; + } + }); + } + + return allFinished.getTask(); + } + + /** + * Continues a task with the equivalent of a Task-based while loop, where the body of the loop is + * a task continuation. + */ + public Task continueWhile( + Callable predicate, Continuation> continuation) { + return continueWhile(predicate, continuation, IMMEDIATE_EXECUTOR, null); + } + + /** + * Continues a task with the equivalent of a Task-based while loop, where the body of the loop is + * a task continuation. + */ + public Task continueWhile( + Callable predicate, + Continuation> continuation, + CancellationToken ct) { + return continueWhile(predicate, continuation, IMMEDIATE_EXECUTOR, ct); + } + + /** + * Continues a task with the equivalent of a Task-based while loop, where the body of the loop is + * a task continuation. + */ + public Task continueWhile( + final Callable predicate, + final Continuation> continuation, + final Executor executor) { + return continueWhile(predicate, continuation, executor, null); + } + + /** + * Continues a task with the equivalent of a Task-based while loop, where the body of the loop is + * a task continuation. + */ + public Task continueWhile( + final Callable predicate, + final Continuation> continuation, + final Executor executor, + final CancellationToken ct) { + final Capture>> predicateContinuation = new Capture<>(); + predicateContinuation.set( + new Continuation>() { + @Override + public Task then(Task task) throws Exception { + if (ct != null && ct.isCancellationRequested()) { + return Task.cancelled(); + } + + if (predicate.call()) { + return Task.forResult(null) + .onSuccessTask(continuation, executor) + .onSuccessTask(predicateContinuation.get(), executor); + } + return Task.forResult(null); + } + }); + return makeVoid().continueWithTask(predicateContinuation.get(), executor); + } + + /** + * Adds a continuation that will be scheduled using the executor, returning a new task that + * completes after the continuation has finished running. This allows the continuation to be + * scheduled on different thread. + */ + public Task continueWith( + final Continuation continuation, final Executor executor) { + return continueWith(continuation, executor, null); + } + + /** + * Adds a continuation that will be scheduled using the executor, returning a new task that + * completes after the continuation has finished running. This allows the continuation to be + * scheduled on different thread. + */ + public Task continueWith( + final Continuation continuation, + final Executor executor, + final CancellationToken ct) { + boolean completed; + final TaskCompletionSource tcs = new TaskCompletionSource<>(); + synchronized (lock) { + completed = this.isCompleted(); + if (!completed) { + this.continuations.add( + new Continuation() { + @Override + public Void then(Task task) { + completeImmediately(tcs, continuation, task, executor, ct); + return null; + } + }); + } + } + if (completed) { + completeImmediately(tcs, continuation, this, executor, ct); + } + return tcs.getTask(); + } + + /** + * Adds a synchronous continuation to this task, returning a new task that completes after the + * continuation has finished running. + */ + public Task continueWith( + Continuation continuation) { + return continueWith(continuation, IMMEDIATE_EXECUTOR, null); + } + + /** + * Adds a synchronous continuation to this task, returning a new task that completes after the + * continuation has finished running. + */ + public Task continueWith( + Continuation continuation, CancellationToken ct) { + return continueWith(continuation, IMMEDIATE_EXECUTOR, ct); + } + + /** + * Adds an Task-based continuation to this task that will be scheduled using the executor, + * returning a new task that completes after the task returned by the continuation has completed. + */ + public Task continueWithTask( + final Continuation> continuation, + final Executor executor) { + return continueWithTask(continuation, executor, null); + } + + /** + * Adds an Task-based continuation to this task that will be scheduled using the executor, + * returning a new task that completes after the task returned by the continuation has completed. + */ + public Task continueWithTask( + final Continuation> continuation, + final Executor executor, + final CancellationToken ct) { + boolean completed; + final TaskCompletionSource tcs = new TaskCompletionSource<>(); + synchronized (lock) { + completed = this.isCompleted(); + if (!completed) { + this.continuations.add( + new Continuation() { + @Override + public Void then(Task task) { + completeAfterTask(tcs, continuation, task, executor, ct); + return null; + } + }); + } + } + if (completed) { + completeAfterTask(tcs, continuation, this, executor, ct); + } + return tcs.getTask(); + } + + /** + * Adds an asynchronous continuation to this task, returning a new task that completes after the + * task returned by the continuation has completed. + */ + public Task continueWithTask( + Continuation> continuation) { + return continueWithTask(continuation, IMMEDIATE_EXECUTOR, null); + } + + /** + * Adds an asynchronous continuation to this task, returning a new task that completes after the + * task returned by the continuation has completed. + */ + public Task continueWithTask( + Continuation> continuation, CancellationToken ct) { + return continueWithTask(continuation, IMMEDIATE_EXECUTOR, ct); + } + + /** + * Runs a continuation when a task completes successfully, forwarding along {@link + * java.lang.Exception} or cancellation. + */ + public Task onSuccess( + final Continuation continuation, Executor executor) { + return onSuccess(continuation, executor, null); + } + + /** + * Runs a continuation when a task completes successfully, forwarding along {@link + * java.lang.Exception} or cancellation. + */ + public Task onSuccess( + final Continuation continuation, + Executor executor, + final CancellationToken ct) { + return continueWithTask( + new Continuation>() { + @Override + public Task then(Task task) { + if (ct != null && ct.isCancellationRequested()) { + return Task.cancelled(); + } + + if (task.isFaulted()) { + return Task.forError(task.getError()); + } else if (task.isCancelled()) { + return Task.cancelled(); + } else { + return task.continueWith(continuation); + } + } + }, + executor); + } + + /** + * Runs a continuation when a task completes successfully, forwarding along {@link + * java.lang.Exception}s or cancellation. + */ + public Task onSuccess( + final Continuation continuation) { + return onSuccess(continuation, IMMEDIATE_EXECUTOR, null); + } + + /** + * Runs a continuation when a task completes successfully, forwarding along {@link + * java.lang.Exception}s or cancellation. + */ + public Task onSuccess( + final Continuation continuation, CancellationToken ct) { + return onSuccess(continuation, IMMEDIATE_EXECUTOR, ct); + } + + /** + * Runs a continuation when a task completes successfully, forwarding along {@link + * java.lang.Exception}s or cancellation. + */ + public Task onSuccessTask( + final Continuation> continuation, Executor executor) { + return onSuccessTask(continuation, executor, null); + } + + /** + * Runs a continuation when a task completes successfully, forwarding along {@link + * java.lang.Exception}s or cancellation. + */ + public Task onSuccessTask( + final Continuation> continuation, + Executor executor, + final CancellationToken ct) { + return continueWithTask( + new Continuation>() { + @Override + public Task then(Task task) { + if (ct != null && ct.isCancellationRequested()) { + return Task.cancelled(); + } + + if (task.isFaulted()) { + return Task.forError(task.getError()); + } else if (task.isCancelled()) { + return Task.cancelled(); + } else { + return task.continueWithTask(continuation); + } + } + }, + executor); + } + + /** + * Runs a continuation when a task completes successfully, forwarding along {@link + * java.lang.Exception}s or cancellation. + */ + public Task onSuccessTask( + final Continuation> continuation) { + return onSuccessTask(continuation, IMMEDIATE_EXECUTOR); + } + + /** + * Runs a continuation when a task completes successfully, forwarding along {@link + * java.lang.Exception}s or cancellation. + */ + public Task onSuccessTask( + final Continuation> continuation, CancellationToken ct) { + return onSuccessTask(continuation, IMMEDIATE_EXECUTOR, ct); + } + + /** + * Handles the non-async (i.e. the continuation doesn't return a Task) continuation case, passing + * the results of the given Task through to the given continuation and using the results of that + * call to set the result of the TaskContinuationSource. + * + * @param tcs The TaskContinuationSource that will be orchestrated by this call. + * @param continuation The non-async continuation. + * @param task The task being completed. + * @param executor The executor to use when running the continuation (allowing the continuation to + * be scheduled on a different thread). + */ + private static void completeImmediately( + final TaskCompletionSource tcs, + final Continuation continuation, + final Task task, + Executor executor, + final CancellationToken ct) { + try { + executor.execute( + new Runnable() { + @Override + public void run() { + if (ct != null && ct.isCancellationRequested()) { + tcs.setCancelled(); + return; + } + + try { + TContinuationResult result = continuation.then(task); + tcs.setResult(result); + } catch (CancellationException e) { + tcs.setCancelled(); + } catch (Exception e) { + tcs.setError(e); + } + } + }); + } catch (Exception e) { + tcs.setError(new ExecutorException(e)); + } + } + + /** + * Handles the async (i.e. the continuation does return a Task) continuation case, passing the + * results of the given Task through to the given continuation to get a new Task. The + * TaskCompletionSource's results are only set when the new Task has completed, unwrapping the + * results of the task returned by the continuation. + * + * @param tcs The TaskContinuationSource that will be orchestrated by this call. + * @param continuation The async continuation. + * @param task The task being completed. + * @param executor The executor to use when running the continuation (allowing the continuation to + * be scheduled on a different thread). + */ + private static void completeAfterTask( + final TaskCompletionSource tcs, + final Continuation> continuation, + final Task task, + final Executor executor, + final CancellationToken ct) { + try { + executor.execute( + new Runnable() { + @Override + public void run() { + if (ct != null && ct.isCancellationRequested()) { + tcs.setCancelled(); + return; + } + + try { + Task result = continuation.then(task); + if (result == null) { + tcs.setResult(null); + } else { + result.continueWith( + new Continuation() { + @Override + public Void then(Task task) { + if (ct != null && ct.isCancellationRequested()) { + tcs.setCancelled(); + return null; + } + + if (task.isCancelled()) { + tcs.setCancelled(); + } else if (task.isFaulted()) { + tcs.setError(task.getError()); + } else { + tcs.setResult(task.getResult()); + } + return null; + } + }); + } + } catch (CancellationException e) { + tcs.setCancelled(); + } catch (Exception e) { + tcs.setError(e); + } + } + }); + } catch (Exception e) { + tcs.setError(new ExecutorException(e)); + } + } + + private void runContinuations() { + synchronized (lock) { + for (Continuation continuation : continuations) { + try { + continuation.then(this); + } catch (RuntimeException e) { + throw e; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + continuations = null; + } + } + + /** Sets the cancelled flag on the Task if the Task hasn't already been completed. */ + /* package */ boolean trySetCancelled() { + synchronized (lock) { + if (complete) { + return false; + } + complete = true; + cancelled = true; + lock.notifyAll(); + runContinuations(); + return true; + } + } + + /** Sets the result on the Task if the Task hasn't already been completed. */ + /* package */ boolean trySetResult(TResult result) { + synchronized (lock) { + if (complete) { + return false; + } + complete = true; + Task.this.result = result; + lock.notifyAll(); + runContinuations(); + return true; + } + } + + /** Sets the error on the Task if the Task hasn't already been completed. */ + /* package */ boolean trySetError(Exception error) { + synchronized (lock) { + if (complete) { + return false; + } + complete = true; + Task.this.error = error; + errorHasBeenObserved = false; + lock.notifyAll(); + runContinuations(); + if (!errorHasBeenObserved && getUnobservedExceptionHandler() != null) + unobservedErrorNotifier = new UnobservedErrorNotifier(this); + return true; + } + } + + private static Task TASK_NULL = new Task<>(null); + private static Task TASK_TRUE = new Task<>((Boolean) true); + private static Task TASK_FALSE = new Task<>((Boolean) false); + private static Task TASK_CANCELLED = new Task(true); +} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/internal/bolts/TaskCompletionSource.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/internal/bolts/TaskCompletionSource.java new file mode 100644 index 00000000000000..a82623161e9634 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/internal/bolts/TaskCompletionSource.java @@ -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. + */ + +package com.facebook.react.bridgeless.internal.bolts; + +/** + * Allows safe orchestration of a task's completion, preventing the consumer from prematurely + * completing the task. Essentially, it represents the producer side of a Task, providing + * access to the consumer side through the getTask() method while isolating the Task's completion + * mechanisms from the consumer. + */ +public class TaskCompletionSource { + + private final Task task; + + /** + * Creates a TaskCompletionSource that orchestrates a Task. This allows the creator of a task to + * be solely responsible for its completion. + */ + public TaskCompletionSource() { + task = new Task<>(); + } + + /** @return the Task associated with this TaskCompletionSource. */ + public Task getTask() { + return task; + } + + /** Sets the cancelled flag on the Task if the Task hasn't already been completed. */ + public boolean trySetCancelled() { + return task.trySetCancelled(); + } + + /** Sets the result on the Task if the Task hasn't already been completed. */ + public boolean trySetResult(TResult result) { + return task.trySetResult(result); + } + + /** Sets the error on the Task if the Task hasn't already been completed. */ + public boolean trySetError(Exception error) { + return task.trySetError(error); + } + + /** Sets the cancelled flag on the task, throwing if the Task has already been completed. */ + public void setCancelled() { + if (!trySetCancelled()) { + throw new IllegalStateException("Cannot cancel a completed task."); + } + } + + /** Sets the result of the Task, throwing if the Task has already been completed. */ + public void setResult(TResult result) { + if (!trySetResult(result)) { + throw new IllegalStateException("Cannot set the result of a completed task."); + } + } + + /** Sets the error of the Task, throwing if the Task has already been completed. */ + public void setError(Exception error) { + if (!trySetError(error)) { + throw new IllegalStateException("Cannot set the error on a completed task."); + } + } +} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/internal/bolts/UnobservedErrorNotifier.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/internal/bolts/UnobservedErrorNotifier.java new file mode 100644 index 00000000000000..808c497adeceec --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/internal/bolts/UnobservedErrorNotifier.java @@ -0,0 +1,40 @@ +/* + * 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. + */ + +package com.facebook.react.bridgeless.internal.bolts; + +/** + * This class is used to retain a faulted task until either its error is observed or it is + * finalized. If it is finalized with a task, then the uncaught exception handler is exected with an + * UnobservedTaskException. + */ +class UnobservedErrorNotifier { + private Task task; + + public UnobservedErrorNotifier(Task task) { + this.task = task; + } + + @Override + protected void finalize() throws Throwable { + try { + Task faultedTask = this.task; + if (faultedTask != null) { + Task.UnobservedExceptionHandler ueh = Task.getUnobservedExceptionHandler(); + if (ueh != null) { + ueh.unobservedException(faultedTask, new UnobservedTaskException(faultedTask.getError())); + } + } + } finally { + super.finalize(); + } + } + + public void setObserved() { + task = null; + } +} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/internal/bolts/UnobservedTaskException.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/internal/bolts/UnobservedTaskException.java new file mode 100644 index 00000000000000..793f49e5a8b4b8 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/internal/bolts/UnobservedTaskException.java @@ -0,0 +1,15 @@ +/* + * 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. + */ + +package com.facebook.react.bridgeless.internal.bolts; + +/** Used to signify that a Task's error went unobserved. */ +public class UnobservedTaskException extends RuntimeException { + public UnobservedTaskException(Throwable cause) { + super(cause); + } +} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/common/DebugServerException.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/common/DebugServerException.java index 33898324d69f83..4170256331f7d9 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/common/DebugServerException.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/common/DebugServerException.java @@ -9,6 +9,7 @@ import android.net.Uri; import android.text.TextUtils; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.facebook.common.logging.FLog; import org.json.JSONException; @@ -27,12 +28,13 @@ public class DebugServerException extends RuntimeException { + "\u2022 If you're on a physical device connected to the same machine, run 'adb reverse tcp: tcp:' to forward requests from your device\n" + "\u2022 If your device is on the same Wi-Fi network, set 'Debug server host & port for device' in 'Dev settings' to your machine's IP address and the port of the local dev server - e.g. 10.0.1.1:\n\n"; - public static DebugServerException makeGeneric(String url, String reason, Throwable t) { + public static DebugServerException makeGeneric( + @NonNull String url, @NonNull String reason, Throwable t) { return makeGeneric(url, reason, "", t); } public static DebugServerException makeGeneric( - String url, String reason, String extra, Throwable t) { + @NonNull String url, @NonNull String reason, @NonNull String extra, Throwable t) { Uri uri = Uri.parse(url); String message = GENERIC_ERROR_MESSAGE.replace("", String.valueOf(uri.getPort())); diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/common/annotations/UnstableReactNativeAPI.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/common/annotations/UnstableReactNativeAPI.kt new file mode 100644 index 00000000000000..3996580c313e4d --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/common/annotations/UnstableReactNativeAPI.kt @@ -0,0 +1,15 @@ +/* + * 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. + */ + +package com.facebook.react.common.annotations + +@Retention(AnnotationRetention.RUNTIME) +@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION) +@RequiresOptIn( + level = RequiresOptIn.Level.ERROR, + message = "This API is experimental and is likely to change or to be removed in the future") +annotation class UnstableReactNativeAPI diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/common/annotations/VisibleForTesting.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/common/annotations/VisibleForTesting.kt similarity index 78% rename from packages/react-native/ReactAndroid/src/main/java/com/facebook/react/common/annotations/VisibleForTesting.java rename to packages/react-native/ReactAndroid/src/main/java/com/facebook/react/common/annotations/VisibleForTesting.kt index 2b9e919775d4ea..5628249c45f290 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/common/annotations/VisibleForTesting.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/common/annotations/VisibleForTesting.kt @@ -5,10 +5,10 @@ * LICENSE file in the root directory of this source tree. */ -package com.facebook.react.common.annotations; +package com.facebook.react.common.annotations /** * Annotates a method that should have restricted visibility but it's required to be public for use * in test code only. */ -public @interface VisibleForTesting {} +annotation class VisibleForTesting diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/config/ReactFeatureFlags.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/config/ReactFeatureFlags.java index 2c5adaac55de57..3ee102049179f2 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/config/ReactFeatureFlags.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/config/ReactFeatureFlags.java @@ -42,12 +42,23 @@ public class ReactFeatureFlags { */ public static volatile boolean enableFabricRenderer = false; + /** + * Should this application enable the Fabric Interop Layer for Android? If yes, the application + * will behave so that it can accept non-Fabric components and render them on Fabric. This toggle + * is controlling extra logic such as custom event dispatching that are needed for the Fabric + * Interop Layer to work correctly. + */ + public static volatile boolean unstable_useFabricInterop = false; + /** * Feature flag to enable the new bridgeless architecture. Note: Enabling this will force enable * the following flags: `useTurboModules` & `enableFabricRenderer`. */ public static boolean enableBridgelessArchitecture = false; + /** Server-side gating for a hacky fix to an ANR in the bridgeless core, related to Bolts task. */ + public static boolean unstable_bridgelessArchitectureMemoryPressureHackyBoltsFix = false; + /** * Does the bridgeless architecture log soft exceptions. Could be useful for tracking down issues. */ @@ -86,9 +97,6 @@ public class ReactFeatureFlags { /** Feature Flag to enable the pending event queue in fabric before mounting views */ public static boolean enableFabricPendingEventQueue = false; - /** Feature Flag to enable caching mechanism of text measurement at shadow node level */ - public static boolean enableTextMeasureCachePerShadowNode = false; - /** * Feature flag that controls how turbo modules are exposed to JS * @@ -141,4 +149,10 @@ public class ReactFeatureFlags { * HostObject pattern */ public static boolean useNativeState = false; + + /** + * Unmount React application on ReactInstance detach. Controls rollout of change to align React + * application lifecycle with React Native instance. + */ + public static boolean unmountApplicationOnInstanceDetach = false; } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultNewArchitectureEntryPoint.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultNewArchitectureEntryPoint.kt index 4b5b71e4d9c03a..73cb1e0f1da939 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultNewArchitectureEntryPoint.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultNewArchitectureEntryPoint.kt @@ -31,6 +31,7 @@ object DefaultNewArchitectureEntryPoint { ) { ReactFeatureFlags.useTurboModules = turboModulesEnabled ReactFeatureFlags.enableFabricRenderer = fabricEnabled + ReactFeatureFlags.unstable_useFabricInterop = fabricEnabled this.privateFabricEnabled = fabricEnabled this.privateTurboModulesEnabled = turboModulesEnabled diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/BridgeDevSupportManager.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/BridgeDevSupportManager.java index 4d7110c91eb954..6b57090f41cbe5 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/BridgeDevSupportManager.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/BridgeDevSupportManager.java @@ -115,22 +115,6 @@ public void onOptionSelected() { toggleJSSamplingProfiler(); } }); - - if (!getDevSettings().isDeviceDebugEnabled()) { - // For remote debugging, we open up Chrome running the app in a web worker. - // Note that this requires async communication, which will not work for Turbo Modules. - addCustomDevOption( - getDevSettings().isRemoteJSDebugEnabled() - ? applicationContext.getString(com.facebook.react.R.string.catalyst_debug_stop) - : applicationContext.getString(com.facebook.react.R.string.catalyst_debug), - new DevOptionHandler() { - @Override - public void onOptionSelected() { - getDevSettings().setRemoteJSDebugEnabled(!getDevSettings().isRemoteJSDebugEnabled()); - handleReloadJS(); - } - }); - } } public DevLoadingViewManager getDevLoadingViewManager() { diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevInternalSettings.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevInternalSettings.java index a6e67bf56ed13b..a68feb63a276db 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevInternalSettings.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevInternalSettings.java @@ -10,18 +10,16 @@ import android.content.Context; import android.content.SharedPreferences; import android.preference.PreferenceManager; -import com.facebook.react.common.annotations.VisibleForTesting; import com.facebook.react.common.build.ReactBuildConfig; import com.facebook.react.modules.debug.interfaces.DeveloperSettings; import com.facebook.react.packagerconnection.PackagerConnectionSettings; /** - * Helper class for accessing developers settings that should not be accessed outside of the package + * Helper class for accessing developers settings that can not be accessed outside of the package * {@link com.facebook.react.devsupport}. For accessing some of the settings by external modules * this class implements an external interface {@link DeveloperSettings}. */ -@VisibleForTesting -public class DevInternalSettings +class DevInternalSettings implements DeveloperSettings, SharedPreferences.OnSharedPreferenceChangeListener { private static final String PREFS_FPS_DEBUG_KEY = "fps_debug"; @@ -45,19 +43,11 @@ public DevInternalSettings(Context applicationContext, Listener listener) { mPackagerConnectionSettings = new PackagerConnectionSettings(applicationContext); } - public PackagerConnectionSettings getPackagerConnectionSettings() { - return mPackagerConnectionSettings; - } - @Override public boolean isFpsDebugEnabled() { return mPreferences.getBoolean(PREFS_FPS_DEBUG_KEY, false); } - public void setFpsDebugEnabled(boolean enabled) { - mPreferences.edit().putBoolean(PREFS_FPS_DEBUG_KEY, enabled).apply(); - } - @Override public boolean isAnimationFpsDebugEnabled() { return mPreferences.getBoolean(PREFS_ANIMATIONS_DEBUG_KEY, false); @@ -68,15 +58,12 @@ public boolean isJSDevModeEnabled() { return mPreferences.getBoolean(PREFS_JS_DEV_MODE_DEBUG_KEY, true); } - public void setJSDevModeEnabled(boolean value) { - mPreferences.edit().putBoolean(PREFS_JS_DEV_MODE_DEBUG_KEY, value).apply(); - } - @Override public boolean isJSMinifyEnabled() { return mPreferences.getBoolean(PREFS_JS_MINIFY_DEBUG_KEY, false); } + @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { if (mListener != null) { if (PREFS_FPS_DEBUG_KEY.equals(key) @@ -88,22 +75,11 @@ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, Strin } } - public boolean isHotModuleReplacementEnabled() { - return mPreferences.getBoolean(PREFS_HOT_MODULE_REPLACEMENT_KEY, true); - } - - public void setHotModuleReplacementEnabled(boolean enabled) { - mPreferences.edit().putBoolean(PREFS_HOT_MODULE_REPLACEMENT_KEY, enabled).apply(); - } - + @Override public boolean isElementInspectorEnabled() { return mPreferences.getBoolean(PREFS_INSPECTOR_DEBUG_KEY, false); } - public void setElementInspectorEnabled(boolean enabled) { - mPreferences.edit().putBoolean(PREFS_INSPECTOR_DEBUG_KEY, enabled).apply(); - } - @Override public boolean isDeviceDebugEnabled() { return ReactBuildConfig.IS_INTERNAL_BUILD && ReactBuildConfig.DEBUG; @@ -129,6 +105,30 @@ public void addMenuItem(String title) { // Not supported. } + void setElementInspectorEnabled(boolean enabled) { + mPreferences.edit().putBoolean(PREFS_INSPECTOR_DEBUG_KEY, enabled).apply(); + } + + boolean isHotModuleReplacementEnabled() { + return mPreferences.getBoolean(PREFS_HOT_MODULE_REPLACEMENT_KEY, true); + } + + void setHotModuleReplacementEnabled(boolean enabled) { + mPreferences.edit().putBoolean(PREFS_HOT_MODULE_REPLACEMENT_KEY, enabled).apply(); + } + + void setJSDevModeEnabled(boolean value) { + mPreferences.edit().putBoolean(PREFS_JS_DEV_MODE_DEBUG_KEY, value).apply(); + } + + void setFpsDebugEnabled(boolean enabled) { + mPreferences.edit().putBoolean(PREFS_FPS_DEBUG_KEY, enabled).apply(); + } + + PackagerConnectionSettings getPackagerConnectionSettings() { + return mPackagerConnectionSettings; + } + public interface Listener { void onInternalSettingsChanged(); } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevServerHelper.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevServerHelper.java index fdd59211061abd..6ee95a79a664d5 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevServerHelper.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevServerHelper.java @@ -9,6 +9,7 @@ import android.content.Context; import android.os.AsyncTask; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.facebook.common.logging.FLog; import com.facebook.infer.annotation.Assertions; @@ -16,10 +17,12 @@ import com.facebook.react.common.ReactConstants; import com.facebook.react.devsupport.interfaces.DevBundleDownloadListener; import com.facebook.react.devsupport.interfaces.PackagerStatusCallback; +import com.facebook.react.modules.debug.interfaces.DeveloperSettings; import com.facebook.react.modules.systeminfo.AndroidInfoHelpers; import com.facebook.react.packagerconnection.FileIoHandler; import com.facebook.react.packagerconnection.JSPackagerClient; import com.facebook.react.packagerconnection.NotificationOnlyHandler; +import com.facebook.react.packagerconnection.PackagerConnectionSettings; import com.facebook.react.packagerconnection.ReconnectingWebSocket.ConnectionCallback; import com.facebook.react.packagerconnection.RequestHandler; import com.facebook.react.packagerconnection.RequestOnlyHandler; @@ -62,10 +65,6 @@ public class DevServerHelper { private static final String DEBUGGER_MSG_DISABLE = "{ \"id\":1,\"method\":\"Debugger.disable\" }"; - public interface OnServerContentChangeListener { - void onServerContentChanged(); - } - public interface PackagerCommandListener { void onPackagerConnected(); @@ -82,8 +81,6 @@ public interface PackagerCommandListener { Map customCommandHandlers(); } - public interface PackagerCustomCommandProvider {} - private enum BundleType { BUNDLE("bundle"), MAP("map"); @@ -99,7 +96,10 @@ public String typeID() { } } - private final DevInternalSettings mSettings; + private final DeveloperSettings mSettings; + + private final PackagerConnectionSettings mPackagerConnectionSettings; + private final OkHttpClient mClient; private final BundleDownloader mBundleDownloader; private final PackagerStatusCheck mPackagerStatusCheck; @@ -107,13 +107,15 @@ public String typeID() { private @Nullable JSPackagerClient mPackagerClient; private @Nullable InspectorPackagerConnection mInspectorPackagerConnection; - private InspectorPackagerConnection.BundleStatusProvider mBundlerStatusProvider; + private final InspectorPackagerConnection.BundleStatusProvider mBundlerStatusProvider; public DevServerHelper( - DevInternalSettings settings, + DeveloperSettings developerSettings, String packageName, - InspectorPackagerConnection.BundleStatusProvider bundleStatusProvider) { - mSettings = settings; + InspectorPackagerConnection.BundleStatusProvider bundleStatusProvider, + PackagerConnectionSettings packagerConnectionSettings) { + mSettings = developerSettings; + mPackagerConnectionSettings = packagerConnectionSettings; mBundlerStatusProvider = bundleStatusProvider; mClient = new OkHttpClient.Builder() @@ -181,10 +183,7 @@ public void onDisconnected() { mPackagerClient = new JSPackagerClient( - clientId, - mSettings.getPackagerConnectionSettings(), - handlers, - onPackagerConnectedCallback); + clientId, mPackagerConnectionSettings, handlers, onPackagerConnectedCallback); mPackagerClient.init(); return null; @@ -277,14 +276,14 @@ public String getWebsocketProxyURL() { return String.format( Locale.US, "ws://%s/debugger-proxy?role=client", - mSettings.getPackagerConnectionSettings().getDebugServerHost()); + mPackagerConnectionSettings.getDebugServerHost()); } private String getInspectorDeviceUrl() { return String.format( Locale.US, "http://%s/inspector/device?name=%s&app=%s", - mSettings.getPackagerConnectionSettings().getInspectorServerHost(), + mPackagerConnectionSettings.getInspectorServerHost(), AndroidInfoHelpers.getFriendlyDeviceName(), mPackageName); } @@ -315,8 +314,7 @@ public void downloadBundleFromURL( /** @return the host to use when connecting to the bundle server from the host itself. */ private String getHostForJSProxy() { // Use custom port if configured. Note that host stays "localhost". - String host = - Assertions.assertNotNull(mSettings.getPackagerConnectionSettings().getDebugServerHost()); + String host = Assertions.assertNotNull(mPackagerConnectionSettings.getDebugServerHost()); int portOffset = host.lastIndexOf(':'); if (portOffset > -1) { return "localhost" + host.substring(portOffset); @@ -345,13 +343,15 @@ private String createSplitBundleURL(String mainModuleID, String host) { private String createBundleURL( String mainModuleID, BundleType type, String host, boolean modulesOnly, boolean runModule) { + boolean dev = getDevMode(); return String.format( Locale.US, - "http://%s/%s.%s?platform=android&dev=%s&minify=%s&app=%s&modulesOnly=%s&runModule=%s", + "http://%s/%s.%s?platform=android&dev=%s&lazy=%s&minify=%s&app=%s&modulesOnly=%s&runModule=%s", host, mainModuleID, type.typeID(), - getDevMode(), + dev, // dev + dev, // lazy getJSMinifyMode(), mPackageName, modulesOnly ? "true" : "false", @@ -359,8 +359,7 @@ private String createBundleURL( } private String createBundleURL(String mainModuleID, BundleType type) { - return createBundleURL( - mainModuleID, type, mSettings.getPackagerConnectionSettings().getDebugServerHost()); + return createBundleURL(mainModuleID, type, mPackagerConnectionSettings.getDebugServerHost()); } private static String createResourceURL(String host, String resourcePath) { @@ -369,18 +368,15 @@ private static String createResourceURL(String host, String resourcePath) { public String getDevServerBundleURL(final String jsModulePath) { return createBundleURL( - jsModulePath, - BundleType.BUNDLE, - mSettings.getPackagerConnectionSettings().getDebugServerHost()); + jsModulePath, BundleType.BUNDLE, mPackagerConnectionSettings.getDebugServerHost()); } public String getDevServerSplitBundleURL(String jsModulePath) { - return createSplitBundleURL( - jsModulePath, mSettings.getPackagerConnectionSettings().getDebugServerHost()); + return createSplitBundleURL(jsModulePath, mPackagerConnectionSettings.getDebugServerHost()); } public void isPackagerRunning(final PackagerStatusCallback callback) { - String host = mSettings.getPackagerConnectionSettings().getDebugServerHost(); + String host = mPackagerConnectionSettings.getDebugServerHost(); if (host == null) { FLog.w(ReactConstants.TAG, "No packager host configured."); callback.onPackagerStatusFetched(false); @@ -393,7 +389,7 @@ private String createLaunchJSDevtoolsCommandUrl() { return String.format( Locale.US, "http://%s/launch-js-devtools", - mSettings.getPackagerConnectionSettings().getDebugServerHost()); + mPackagerConnectionSettings.getDebugServerHost()); } public void launchJSDevtools() { @@ -403,14 +399,13 @@ public void launchJSDevtools() { .enqueue( new Callback() { @Override - public void onFailure(Call call, IOException e) { + public void onFailure(@NonNull Call call, @NonNull IOException e) { // ignore HTTP call response, this is just to open a debugger page and there is no - // reason - // to report failures from here + // reason to report failures from here } @Override - public void onResponse(Call call, Response response) throws IOException { + public void onResponse(@NonNull Call call, @NonNull Response response) { // ignore HTTP call response - see above } }); @@ -440,23 +435,16 @@ public String getJSBundleURLForRemoteDebugging(String mainModuleName) { public @Nullable File downloadBundleResourceFromUrlSync( final String resourcePath, final File outputFile) { final String resourceURL = - createResourceURL( - mSettings.getPackagerConnectionSettings().getDebugServerHost(), resourcePath); + createResourceURL(mPackagerConnectionSettings.getDebugServerHost(), resourcePath); final Request request = new Request.Builder().url(resourceURL).build(); try (Response response = mClient.newCall(request).execute()) { if (!response.isSuccessful()) { return null; } - Sink output = null; - try { - output = Okio.sink(outputFile); + try (Sink output = Okio.sink(outputFile)) { Okio.buffer(response.body().source()).readAll(output); - } finally { - if (output != null) { - output.close(); - } } return outputFile; diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerBase.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerBase.java index 82cc5b393c90f8..b393db1675623d 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerBase.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerBase.java @@ -17,13 +17,13 @@ import android.content.IntentFilter; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; -import android.graphics.Color; import android.graphics.Typeface; import android.hardware.SensorManager; import android.util.Pair; import android.view.Gravity; import android.view.View; import android.widget.EditText; +import android.widget.LinearLayout; import android.widget.TextView; import android.widget.Toast; import androidx.annotation.Nullable; @@ -83,9 +83,6 @@ public interface CallbackWithBundleLoader { private static final String EXOPACKAGE_LOCATION_FORMAT = "/data/local/tmp/exopackage/%s//secondary-dex"; - public static final String EMOJI_HUNDRED_POINTS_SYMBOL = " \uD83D\uDCAF"; - public static final String EMOJI_FACE_WITH_NO_GOOD_GESTURE = " \uD83D\uDE45"; - private final Context mApplicationContext; private final ShakeDetector mShakeDetector; private final BroadcastReceiver mReloadAppBroadcastReceiver; @@ -104,24 +101,23 @@ public interface CallbackWithBundleLoader { private boolean mDevLoadingViewVisible = false; private int mPendingJSSplitBundleRequests = 0; private @Nullable ReactContext mCurrentContext; - private DevInternalSettings mDevSettings; + private final DevInternalSettings mDevSettings; private boolean mIsReceiverRegistered = false; private boolean mIsShakeDetectorStarted = false; private boolean mIsDevSupportEnabled = false; - private @Nullable RedBoxHandler mRedBoxHandler; + private @Nullable final RedBoxHandler mRedBoxHandler; private @Nullable String mLastErrorTitle; private @Nullable StackFrame[] mLastErrorStack; private @Nullable ErrorType mLastErrorType; private int mLastErrorCookie = 0; - private @Nullable DevBundleDownloadListener mBundleDownloadListener; + private @Nullable final DevBundleDownloadListener mBundleDownloadListener; private @Nullable List mErrorCustomizers; private @Nullable PackagerLocationCustomizer mPackagerLocationCustomizer; - private InspectorPackagerConnection.BundleStatus mBundleStatus; + private final InspectorPackagerConnection.BundleStatus mBundleStatus; - private @Nullable Map mCustomPackagerCommandHandlers; + private @Nullable final Map mCustomPackagerCommandHandlers; - private @Nullable Activity currentActivity; private @Nullable final SurfaceDelegateFactory mSurfaceDelegateFactory; public DevSupportManagerBase( @@ -138,38 +134,18 @@ public DevSupportManagerBase( mReactInstanceDevHelper = reactInstanceDevHelper; mApplicationContext = applicationContext; mJSAppBundleName = packagerPathForJSBundleName; - mDevSettings = - new DevInternalSettings( - applicationContext, - new DevInternalSettings.Listener() { - @Override - public void onInternalSettingsChanged() { - reloadSettings(); - } - }); + mDevSettings = new DevInternalSettings(applicationContext, this::reloadSettings); mBundleStatus = new InspectorPackagerConnection.BundleStatus(); mDevServerHelper = new DevServerHelper( mDevSettings, mApplicationContext.getPackageName(), - new InspectorPackagerConnection.BundleStatusProvider() { - @Override - public InspectorPackagerConnection.BundleStatus getBundleStatus() { - return mBundleStatus; - } - }); + () -> mBundleStatus, + mDevSettings.getPackagerConnectionSettings()); mBundleDownloadListener = devBundleDownloadListener; // Prepare shake gesture detector (will be started/stopped from #reload) - mShakeDetector = - new ShakeDetector( - new ShakeDetector.ShakeListener() { - @Override - public void onShake() { - showDevOptionsDialog(); - } - }, - minNumShakes); + mShakeDetector = new ShakeDetector(this::showDevOptionsDialog, minNumShakes); mCustomPackagerCommandHandlers = customPackagerCommandHandlers; @@ -280,38 +256,34 @@ public void registerErrorCustomizer(ErrorCustomizer errorCustomizer) { @Override public Pair processErrorCustomizers(Pair errorInfo) { - if (mErrorCustomizers == null) { - return errorInfo; - } else { + if (mErrorCustomizers != null) { for (ErrorCustomizer errorCustomizer : mErrorCustomizers) { Pair result = errorCustomizer.customizeErrorInfo(errorInfo); if (result != null) { errorInfo = result; } } - return errorInfo; } + return errorInfo; } @Override public void updateJSError( final String message, final ReadableArray details, final int errorCookie) { UiThreadUtil.runOnUiThread( - new Runnable() { - @Override - public void run() { - // Since we only show the first JS error in a succession of JS errors, make sure we only - // update the error message for that error message. This assumes that updateJSError - // belongs to the most recent showNewJSError - if (!mRedBoxSurfaceDelegate.isShowing() || errorCookie != mLastErrorCookie) { - return; - } - - // The RedBox surface delegate will always show the latest error - updateLastErrorInfo( - message, StackTraceHelper.convertJsStackTrace(details), errorCookie, ErrorType.JS); - mRedBoxSurfaceDelegate.show(); + () -> { + // Since we only show the first JS error in a succession of JS errors, make sure we only + // update the error message for that error message. This assumes that updateJSError + // belongs to the most recent showNewJSError + if ((mRedBoxSurfaceDelegate != null && !mRedBoxSurfaceDelegate.isShowing()) + || errorCookie != mLastErrorCookie) { + return; } + + // The RedBox surface delegate will always show the latest error + updateLastErrorInfo( + message, StackTraceHelper.convertJsStackTrace(details), errorCookie, ErrorType.JS); + mRedBoxSurfaceDelegate.show(); }); } @@ -345,32 +317,28 @@ private void showNewError( final int errorCookie, final ErrorType errorType) { UiThreadUtil.runOnUiThread( - new Runnable() { - @Override - public void run() { - // Keep a copy of the latest error to be shown by the RedBoxSurface - updateLastErrorInfo(message, stack, errorCookie, errorType); - - if (mRedBoxSurfaceDelegate == null) { - @Nullable SurfaceDelegate redBoxSurfaceDelegate = createSurfaceDelegate("RedBox"); - if (redBoxSurfaceDelegate != null) { - mRedBoxSurfaceDelegate = redBoxSurfaceDelegate; - } else { - mRedBoxSurfaceDelegate = - new RedBoxDialogSurfaceDelegate(DevSupportManagerBase.this); - } - - mRedBoxSurfaceDelegate.createContentView("RedBox"); + () -> { + // Keep a copy of the latest error to be shown by the RedBoxSurface + updateLastErrorInfo(message, stack, errorCookie, errorType); + + if (mRedBoxSurfaceDelegate == null) { + @Nullable SurfaceDelegate redBoxSurfaceDelegate = createSurfaceDelegate("RedBox"); + if (redBoxSurfaceDelegate != null) { + mRedBoxSurfaceDelegate = redBoxSurfaceDelegate; + } else { + mRedBoxSurfaceDelegate = new RedBoxDialogSurfaceDelegate(DevSupportManagerBase.this); } - if (mRedBoxSurfaceDelegate.isShowing()) { - // Sometimes errors cause multiple errors to be thrown in JS in quick succession. Only - // show the first and most actionable one. - return; - } + mRedBoxSurfaceDelegate.createContentView("RedBox"); + } - mRedBoxSurfaceDelegate.show(); + if (mRedBoxSurfaceDelegate.isShowing()) { + // Sometimes errors cause multiple errors to be thrown in JS in quick succession. Only + // show the first and most actionable one. + return; } + + mRedBoxSurfaceDelegate.show(); }); } @@ -411,62 +379,50 @@ public void onOptionSelected() { } options.put( mApplicationContext.getString(R.string.catalyst_debug_open), - new DevOptionHandler() { - @Override - public void onOptionSelected() { + () -> mDevServerHelper.openUrl( mCurrentContext, FLIPPER_DEBUGGER_URL, - mApplicationContext.getString(R.string.catalyst_open_flipper_error)); - } - }); + mApplicationContext.getString(R.string.catalyst_open_flipper_error))); options.put( mApplicationContext.getString(R.string.catalyst_devtools_open), - new DevOptionHandler() { - @Override - public void onOptionSelected() { + () -> mDevServerHelper.openUrl( mCurrentContext, FLIPPER_DEVTOOLS_URL, - mApplicationContext.getString(R.string.catalyst_open_flipper_error)); - } - }); + mApplicationContext.getString(R.string.catalyst_open_flipper_error))); } options.put( mApplicationContext.getString(R.string.catalyst_change_bundle_location), - new DevOptionHandler() { - @Override - public void onOptionSelected() { - Activity context = mReactInstanceDevHelper.getCurrentActivity(); - if (context == null || context.isFinishing()) { - FLog.e( - ReactConstants.TAG, - "Unable to launch change bundle location because react activity is not available"); - return; - } - - final EditText input = new EditText(context); - input.setHint("localhost:8081"); - - AlertDialog bundleLocationDialog = - new AlertDialog.Builder(context) - .setTitle( - mApplicationContext.getString(R.string.catalyst_change_bundle_location)) - .setView(input) - .setPositiveButton( - android.R.string.ok, - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - String host = input.getText().toString(); - mDevSettings.getPackagerConnectionSettings().setDebugServerHost(host); - handleReloadJS(); - } - }) - .create(); - bundleLocationDialog.show(); + () -> { + Activity context = mReactInstanceDevHelper.getCurrentActivity(); + if (context == null || context.isFinishing()) { + FLog.e( + ReactConstants.TAG, + "Unable to launch change bundle location because react activity is not available"); + return; } + + final EditText input = new EditText(context); + input.setHint("localhost:8081"); + + AlertDialog bundleLocationDialog = + new AlertDialog.Builder(context) + .setTitle(mApplicationContext.getString(R.string.catalyst_change_bundle_location)) + .setView(input) + .setPositiveButton( + android.R.string.ok, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + String host = input.getText().toString(); + mDevSettings.getPackagerConnectionSettings().setDebugServerHost(host); + handleReloadJS(); + } + }) + .create(); + bundleLocationDialog.show(); }); options.put( @@ -485,58 +441,49 @@ public void onOptionSelected() { mDevSettings.isHotModuleReplacementEnabled() ? mApplicationContext.getString(R.string.catalyst_hot_reloading_stop) : mApplicationContext.getString(R.string.catalyst_hot_reloading), - new DevOptionHandler() { - @Override - public void onOptionSelected() { - boolean nextEnabled = !mDevSettings.isHotModuleReplacementEnabled(); - mDevSettings.setHotModuleReplacementEnabled(nextEnabled); - if (mCurrentContext != null) { - if (nextEnabled) { - mCurrentContext.getJSModule(HMRClient.class).enable(); - } else { - mCurrentContext.getJSModule(HMRClient.class).disable(); - } - } - if (nextEnabled && !mDevSettings.isJSDevModeEnabled()) { - Toast.makeText( - mApplicationContext, - mApplicationContext.getString(R.string.catalyst_hot_reloading_auto_enable), - Toast.LENGTH_LONG) - .show(); - mDevSettings.setJSDevModeEnabled(true); - handleReloadJS(); + () -> { + boolean nextEnabled = !mDevSettings.isHotModuleReplacementEnabled(); + mDevSettings.setHotModuleReplacementEnabled(nextEnabled); + if (mCurrentContext != null) { + if (nextEnabled) { + mCurrentContext.getJSModule(HMRClient.class).enable(); + } else { + mCurrentContext.getJSModule(HMRClient.class).disable(); } } + if (nextEnabled && !mDevSettings.isJSDevModeEnabled()) { + Toast.makeText( + mApplicationContext, + mApplicationContext.getString(R.string.catalyst_hot_reloading_auto_enable), + Toast.LENGTH_LONG) + .show(); + mDevSettings.setJSDevModeEnabled(true); + handleReloadJS(); + } }); options.put( mDevSettings.isFpsDebugEnabled() ? mApplicationContext.getString(R.string.catalyst_perf_monitor_stop) : mApplicationContext.getString(R.string.catalyst_perf_monitor), - new DevOptionHandler() { - @Override - public void onOptionSelected() { - if (!mDevSettings.isFpsDebugEnabled()) { - // Request overlay permission if needed when "Show Perf Monitor" option is selected - Context context = mReactInstanceDevHelper.getCurrentActivity(); - if (context == null) { - FLog.e(ReactConstants.TAG, "Unable to get reference to react activity"); - } else { - DebugOverlayController.requestPermission(context); - } + () -> { + if (!mDevSettings.isFpsDebugEnabled()) { + // Request overlay permission if needed when "Show Perf Monitor" option is selected + Context context = mReactInstanceDevHelper.getCurrentActivity(); + if (context == null) { + FLog.e(ReactConstants.TAG, "Unable to get reference to react activity"); + } else { + DebugOverlayController.requestPermission(context); } - mDevSettings.setFpsDebugEnabled(!mDevSettings.isFpsDebugEnabled()); } + mDevSettings.setFpsDebugEnabled(!mDevSettings.isFpsDebugEnabled()); }); options.put( mApplicationContext.getString(R.string.catalyst_settings), - new DevOptionHandler() { - @Override - public void onOptionSelected() { - Intent intent = new Intent(mApplicationContext, DevSettingsActivity.class); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - mApplicationContext.startActivity(intent); - } + () -> { + Intent intent = new Intent(mApplicationContext, DevSettingsActivity.class); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + mApplicationContext.startActivity(intent); }); if (mCustomDevOptions.size() > 0) { @@ -553,33 +500,36 @@ public void onOptionSelected() { return; } - final TextView textView = new TextView(getApplicationContext()); - textView.setText("React Native DevMenu (" + getUniqueTag() + ")"); - textView.setPadding(0, 50, 0, 0); - textView.setGravity(Gravity.CENTER); - textView.setTextColor(Color.BLACK); - textView.setTextSize(17); - textView.setTypeface(textView.getTypeface(), Typeface.BOLD); + final LinearLayout header = new LinearLayout(context); + header.setOrientation(LinearLayout.VERTICAL); + + final TextView title = new TextView(context); + title.setText(context.getString(R.string.catalyst_dev_menu_header, getUniqueTag())); + title.setPadding(0, 50, 0, 0); + title.setGravity(Gravity.CENTER); + title.setTextSize(16); + title.setTypeface(title.getTypeface(), Typeface.BOLD); + + final TextView jsExecutorLabel = new TextView(context); + jsExecutorLabel.setText( + context.getString(R.string.catalyst_dev_menu_sub_header, getJSExecutorDescription())); + jsExecutorLabel.setPadding(0, 20, 0, 0); + jsExecutorLabel.setGravity(Gravity.CENTER); + jsExecutorLabel.setTextSize(14); + + header.addView(title); + header.addView(jsExecutorLabel); mDevOptionsDialog = new AlertDialog.Builder(context) - .setCustomTitle(textView) + .setCustomTitle(header) .setItems( options.keySet().toArray(new String[0]), - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - optionHandlers[which].onOptionSelected(); - mDevOptionsDialog = null; - } - }) - .setOnCancelListener( - new DialogInterface.OnCancelListener() { - @Override - public void onCancel(DialogInterface dialog) { - mDevOptionsDialog = null; - } + (dialog, which) -> { + optionHandlers[which].onOptionSelected(); + mDevOptionsDialog = null; }) + .setOnCancelListener(dialog -> mDevOptionsDialog = null) .create(); mDevOptionsDialog.show(); if (mCurrentContext != null) { @@ -587,10 +537,14 @@ public void onCancel(DialogInterface dialog) { } } + private String getJSExecutorDescription() { + return getReactInstanceDevHelper().getJavaScriptExecutorFactory().toString(); + } + /** - * {@link ReactInstanceDevCommandsHandler} is responsible for enabling/disabling dev support when - * a React view is attached/detached or when application state changes (e.g. the application is - * backgrounded). + * {@link com.facebook.react.ReactInstanceManager} is responsible for enabling/disabling dev + * support when a React view is attached/detached or when application state changes (e.g. the + * application is backgrounded). */ @Override public void setDevSupportEnabled(boolean isDevSupportEnabled) { @@ -609,7 +563,7 @@ public DevInternalSettings getDevSettings() { } @Override - public RedBoxHandler getRedBoxHandler() { + public @Nullable RedBoxHandler getRedBoxHandler() { return mRedBoxHandler; } @@ -725,13 +679,7 @@ public void reloadSettings() { if (UiThreadUtil.isOnUiThread()) { reload(); } else { - UiThreadUtil.runOnUiThread( - new Runnable() { - @Override - public void run() { - reload(); - } - }); + UiThreadUtil.runOnUiThread(this::reload); } } @@ -801,56 +749,42 @@ public void fetchSplitBundleAndCreateBundleLoader( final File bundleFile = new File(mJSSplitBundlesDir, bundlePath.replaceAll("/", "_") + ".jsbundle"); UiThreadUtil.runOnUiThread( - new Runnable() { - @Override - public void run() { - showSplitBundleDevLoadingView(bundleUrl); - mDevServerHelper.downloadBundleFromURL( - new DevBundleDownloadListener() { - @Override - public void onSuccess() { - UiThreadUtil.runOnUiThread( - new Runnable() { - @Override - public void run() { - hideSplitBundleDevLoadingView(); - } - }); - - @Nullable ReactContext context = mCurrentContext; - if (context == null || !context.hasActiveReactInstance()) { - return; - } - - JSBundleLoader bundleLoader = - JSBundleLoader.createCachedSplitBundleFromNetworkLoader( - bundleUrl, bundleFile.getAbsolutePath()); - - callback.onSuccess(bundleLoader); + () -> { + showSplitBundleDevLoadingView(bundleUrl); + mDevServerHelper.downloadBundleFromURL( + new DevBundleDownloadListener() { + @Override + public void onSuccess() { + UiThreadUtil.runOnUiThread(() -> hideSplitBundleDevLoadingView()); + + @Nullable ReactContext context = mCurrentContext; + if (context == null || !context.hasActiveReactInstance()) { + return; } - @Override - public void onProgress( - @Nullable String status, @Nullable Integer done, @Nullable Integer total) { - mDevLoadingViewManager.updateProgress(status, done, total); - } - - @Override - public void onFailure(Exception cause) { - UiThreadUtil.runOnUiThread( - new Runnable() { - @Override - public void run() { - hideSplitBundleDevLoadingView(); - } - }); - callback.onError(bundleUrl, cause); - } - }, - bundleFile, - bundleUrl, - null); - } + JSBundleLoader bundleLoader = + JSBundleLoader.createCachedSplitBundleFromNetworkLoader( + bundleUrl, bundleFile.getAbsolutePath()); + + callback.onSuccess(bundleLoader); + } + + @Override + public void onProgress( + @Nullable String status, @Nullable Integer done, @Nullable Integer total) { + mDevLoadingViewManager.updateProgress(status, done, total); + } + + @Override + public void onFailure(Exception cause) { + UiThreadUtil.runOnUiThread( + DevSupportManagerBase.this::hideSplitBundleDevLoadingView); + callback.onError(bundleUrl, cause); + } + }, + bundleFile, + bundleUrl, + null); }); } @@ -869,13 +803,7 @@ private void hideSplitBundleDevLoadingView() { @Override public void isPackagerRunning(final PackagerStatusCallback callback) { - Runnable checkPackagerRunning = - new Runnable() { - @Override - public void run() { - mDevServerHelper.isPackagerRunning(callback); - } - }; + Runnable checkPackagerRunning = () -> mDevServerHelper.isPackagerRunning(callback); if (mPackagerLocationCustomizer != null) { mPackagerLocationCustomizer.run(checkPackagerRunning); } else { @@ -946,18 +874,7 @@ private void updateLastErrorInfo( public void reloadJSFromServer(final String bundleURL) { reloadJSFromServer( bundleURL, - new BundleLoadCallback() { - @Override - public void onSuccess() { - UiThreadUtil.runOnUiThread( - new Runnable() { - @Override - public void run() { - mReactInstanceDevHelper.onJSBundleLoadedFromServer(); - } - }); - } - }); + () -> UiThreadUtil.runOnUiThread(mReactInstanceDevHelper::onJSBundleLoadedFromServer)); } public void reloadJSFromServer(final String bundleURL, final BundleLoadCallback callback) { @@ -1014,16 +931,12 @@ public void onFailure(final Exception cause) { private void reportBundleLoadingFailure(final Exception cause) { UiThreadUtil.runOnUiThread( - new Runnable() { - @Override - public void run() { - if (cause instanceof DebugServerException) { - DebugServerException debugServerException = (DebugServerException) cause; - showNewJavaError(debugServerException.getMessage(), cause); - } else { - showNewJavaError( - mApplicationContext.getString(R.string.catalyst_reload_error), cause); - } + () -> { + if (cause instanceof DebugServerException) { + DebugServerException debugServerException = (DebugServerException) cause; + showNewJavaError(debugServerException.getMessage(), cause); + } else { + showNewJavaError(mApplicationContext.getString(R.string.catalyst_reload_error), cause); } }); } @@ -1047,12 +960,9 @@ public void setHotModuleReplacementEnabled(final boolean isHotModuleReplacementE } UiThreadUtil.runOnUiThread( - new Runnable() { - @Override - public void run() { - mDevSettings.setHotModuleReplacementEnabled(isHotModuleReplacementEnabled); - handleReloadJS(); - } + () -> { + mDevSettings.setHotModuleReplacementEnabled(isHotModuleReplacementEnabled); + handleReloadJS(); }); } @@ -1063,12 +973,9 @@ public void setRemoteJSDebugEnabled(final boolean isRemoteJSDebugEnabled) { } UiThreadUtil.runOnUiThread( - new Runnable() { - @Override - public void run() { - mDevSettings.setRemoteJSDebugEnabled(isRemoteJSDebugEnabled); - handleReloadJS(); - } + () -> { + mDevSettings.setRemoteJSDebugEnabled(isRemoteJSDebugEnabled); + handleReloadJS(); }); } @@ -1078,13 +985,7 @@ public void setFpsDebugEnabled(final boolean isFpsDebugEnabled) { return; } - UiThreadUtil.runOnUiThread( - new Runnable() { - @Override - public void run() { - mDevSettings.setFpsDebugEnabled(isFpsDebugEnabled); - } - }); + UiThreadUtil.runOnUiThread(() -> mDevSettings.setFpsDebugEnabled(isFpsDebugEnabled)); } @Override @@ -1094,12 +995,9 @@ public void toggleElementInspector() { } UiThreadUtil.runOnUiThread( - new Runnable() { - @Override - public void run() { - mDevSettings.setElementInspectorEnabled(!mDevSettings.isElementInspectorEnabled()); - mReactInstanceDevHelper.toggleElementInspector(); - } + () -> { + mDevSettings.setElementInspectorEnabled(!mDevSettings.isElementInspectorEnabled()); + mReactInstanceDevHelper.toggleElementInspector(); }); } @@ -1150,35 +1048,17 @@ public void onPackagerDisconnected() { public void onPackagerReloadCommand() { // Disable debugger to resume the JsVM & avoid thread locks while reloading mDevServerHelper.disableDebugger(); - UiThreadUtil.runOnUiThread( - new Runnable() { - @Override - public void run() { - handleReloadJS(); - } - }); + UiThreadUtil.runOnUiThread(() -> handleReloadJS()); } @Override public void onPackagerDevMenuCommand() { - UiThreadUtil.runOnUiThread( - new Runnable() { - @Override - public void run() { - showDevOptionsDialog(); - } - }); + UiThreadUtil.runOnUiThread(() -> showDevOptionsDialog()); } @Override public void onCaptureHeapCommand(final Responder responder) { - UiThreadUtil.runOnUiThread( - new Runnable() { - @Override - public void run() { - handleCaptureHeap(responder); - } - }); + UiThreadUtil.runOnUiThread(() -> handleCaptureHeap(responder)); } @Override diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/PerftestDevSupportManager.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/PerftestDevSupportManager.java index 2be621fc38ff6a..d15eba912d99d8 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/PerftestDevSupportManager.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/PerftestDevSupportManager.java @@ -31,12 +31,8 @@ public void onInternalSettingsChanged() {} new DevServerHelper( mDevSettings, applicationContext.getPackageName(), - new InspectorPackagerConnection.BundleStatusProvider() { - @Override - public InspectorPackagerConnection.BundleStatus getBundleStatus() { - return mBundleStatus; - } - }); + (InspectorPackagerConnection.BundleStatusProvider) () -> mBundleStatus, + mDevSettings.getPackagerConnectionSettings()); } @Override diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricJSIModuleProvider.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricJSIModuleProvider.java index 2d162f957545f5..533b1368b92d8a 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricJSIModuleProvider.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricJSIModuleProvider.java @@ -36,7 +36,7 @@ public FabricJSIModuleProvider( @Override public UIManager get() { Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "FabricJSIModuleProvider.get"); - final EventBeatManager eventBeatManager = new EventBeatManager(mReactApplicationContext); + final EventBeatManager eventBeatManager = new EventBeatManager(); final FabricUIManager uiManager = createUIManager(eventBeatManager); Systrace.beginSection( diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java index 8e50e91a64d52e..f4e9e6e308e5a2 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java @@ -55,6 +55,7 @@ import com.facebook.react.fabric.events.EventBeatManager; import com.facebook.react.fabric.events.EventEmitterWrapper; import com.facebook.react.fabric.events.FabricEventEmitter; +import com.facebook.react.fabric.interop.InteropEventEmitter; import com.facebook.react.fabric.mounting.MountItemDispatcher; import com.facebook.react.fabric.mounting.MountingManager; import com.facebook.react.fabric.mounting.SurfaceMountingManager; @@ -77,6 +78,7 @@ import com.facebook.react.uimanager.events.EventCategoryDef; import com.facebook.react.uimanager.events.EventDispatcher; import com.facebook.react.uimanager.events.EventDispatcherImpl; +import com.facebook.react.uimanager.events.RCTEventEmitter; import com.facebook.react.views.text.TextLayoutManager; import com.facebook.react.views.text.TextLayoutManagerMapBuffer; import java.util.HashMap; @@ -104,51 +106,48 @@ public class FabricUIManager implements UIManager, LifecycleEventListener { public DevToolsReactPerfLogger mDevToolsReactPerfLogger; private static final DevToolsReactPerfLogger.DevToolsReactPerfLoggerListener FABRIC_PERF_LOGGER = - new DevToolsReactPerfLogger.DevToolsReactPerfLoggerListener() { - @Override - public void onFabricCommitEnd(DevToolsReactPerfLogger.FabricCommitPoint commitPoint) { - long commitDuration = commitPoint.getCommitDuration(); - long layoutDuration = commitPoint.getLayoutDuration(); - long diffDuration = commitPoint.getDiffDuration(); - long transactionEndDuration = commitPoint.getTransactionEndDuration(); - long batchExecutionDuration = commitPoint.getBatchExecutionDuration(); - - DevToolsReactPerfLogger.mStreamingCommitStats.add(commitDuration); - DevToolsReactPerfLogger.mStreamingLayoutStats.add(layoutDuration); - DevToolsReactPerfLogger.mStreamingDiffStats.add(diffDuration); - DevToolsReactPerfLogger.mStreamingTransactionEndStats.add(transactionEndDuration); - DevToolsReactPerfLogger.mStreamingBatchExecutionStats.add(batchExecutionDuration); - - FLog.i( - TAG, - "Statistics of Fabric commit #%d:\n" - + " - Total commit time: %d ms. Avg: %.2f. Median: %.2f ms. Max: %d ms.\n" - + " - Layout time: %d ms. Avg: %.2f. Median: %.2f ms. Max: %d ms.\n" - + " - Diffing time: %d ms. Avg: %.2f. Median: %.2f ms. Max: %d ms.\n" - + " - FinishTransaction (Diffing + JNI serialization): %d ms. Avg: %.2f. Median: %.2f ms. Max: %d ms.\n" - + " - Mounting: %d ms. Avg: %.2f. Median: %.2f ms. Max: %d ms.\n", - commitPoint.getCommitNumber(), - commitDuration, - DevToolsReactPerfLogger.mStreamingCommitStats.getAverage(), - DevToolsReactPerfLogger.mStreamingCommitStats.getMedian(), - DevToolsReactPerfLogger.mStreamingCommitStats.getMax(), - layoutDuration, - DevToolsReactPerfLogger.mStreamingLayoutStats.getAverage(), - DevToolsReactPerfLogger.mStreamingLayoutStats.getMedian(), - DevToolsReactPerfLogger.mStreamingLayoutStats.getMax(), - diffDuration, - DevToolsReactPerfLogger.mStreamingDiffStats.getAverage(), - DevToolsReactPerfLogger.mStreamingDiffStats.getMedian(), - DevToolsReactPerfLogger.mStreamingDiffStats.getMax(), - transactionEndDuration, - DevToolsReactPerfLogger.mStreamingTransactionEndStats.getAverage(), - DevToolsReactPerfLogger.mStreamingTransactionEndStats.getMedian(), - DevToolsReactPerfLogger.mStreamingTransactionEndStats.getMax(), - batchExecutionDuration, - DevToolsReactPerfLogger.mStreamingBatchExecutionStats.getAverage(), - DevToolsReactPerfLogger.mStreamingBatchExecutionStats.getMedian(), - DevToolsReactPerfLogger.mStreamingBatchExecutionStats.getMax()); - } + commitPoint -> { + long commitDuration = commitPoint.getCommitDuration(); + long layoutDuration = commitPoint.getLayoutDuration(); + long diffDuration = commitPoint.getDiffDuration(); + long transactionEndDuration = commitPoint.getTransactionEndDuration(); + long batchExecutionDuration = commitPoint.getBatchExecutionDuration(); + + DevToolsReactPerfLogger.mStreamingCommitStats.add(commitDuration); + DevToolsReactPerfLogger.mStreamingLayoutStats.add(layoutDuration); + DevToolsReactPerfLogger.mStreamingDiffStats.add(diffDuration); + DevToolsReactPerfLogger.mStreamingTransactionEndStats.add(transactionEndDuration); + DevToolsReactPerfLogger.mStreamingBatchExecutionStats.add(batchExecutionDuration); + + FLog.i( + TAG, + "Statistics of Fabric commit #%d:\n" + + " - Total commit time: %d ms. Avg: %.2f. Median: %.2f ms. Max: %d ms.\n" + + " - Layout time: %d ms. Avg: %.2f. Median: %.2f ms. Max: %d ms.\n" + + " - Diffing time: %d ms. Avg: %.2f. Median: %.2f ms. Max: %d ms.\n" + + " - FinishTransaction (Diffing + JNI serialization): %d ms. Avg: %.2f. Median: %.2f ms. Max: %d ms.\n" + + " - Mounting: %d ms. Avg: %.2f. Median: %.2f ms. Max: %d ms.\n", + commitPoint.getCommitNumber(), + commitDuration, + DevToolsReactPerfLogger.mStreamingCommitStats.getAverage(), + DevToolsReactPerfLogger.mStreamingCommitStats.getMedian(), + DevToolsReactPerfLogger.mStreamingCommitStats.getMax(), + layoutDuration, + DevToolsReactPerfLogger.mStreamingLayoutStats.getAverage(), + DevToolsReactPerfLogger.mStreamingLayoutStats.getMedian(), + DevToolsReactPerfLogger.mStreamingLayoutStats.getMax(), + diffDuration, + DevToolsReactPerfLogger.mStreamingDiffStats.getAverage(), + DevToolsReactPerfLogger.mStreamingDiffStats.getMedian(), + DevToolsReactPerfLogger.mStreamingDiffStats.getMax(), + transactionEndDuration, + DevToolsReactPerfLogger.mStreamingTransactionEndStats.getAverage(), + DevToolsReactPerfLogger.mStreamingTransactionEndStats.getMedian(), + DevToolsReactPerfLogger.mStreamingTransactionEndStats.getMax(), + batchExecutionDuration, + DevToolsReactPerfLogger.mStreamingBatchExecutionStats.getAverage(), + DevToolsReactPerfLogger.mStreamingBatchExecutionStats.getMedian(), + DevToolsReactPerfLogger.mStreamingBatchExecutionStats.getMax()); }; static { @@ -191,7 +190,7 @@ public void onFabricCommitEnd(DevToolsReactPerfLogger.FabricCommitPoint commitPo // from C++ to exceed 9,999 and it should be obvious what's going on when analyzing performance. private int mCurrentSynchronousCommitNumber = 10000; - private MountingManager.MountItemExecutor mMountItemExecutor = + private final MountingManager.MountItemExecutor mMountItemExecutor = new MountingManager.MountItemExecutor() { @Override public void executeItems(Queue items) { @@ -202,9 +201,9 @@ public void executeItems(Queue items) { }; public FabricUIManager( - ReactApplicationContext reactContext, - ViewManagerRegistry viewManagerRegistry, - EventBeatManager eventBeatManager) { + @NonNull ReactApplicationContext reactContext, + @NonNull ViewManagerRegistry viewManagerRegistry, + @NonNull EventBeatManager eventBeatManager) { mDispatchUIFrameCallback = new DispatchUIFrameCallback(reactContext); mReactApplicationContext = reactContext; mMountingManager = new MountingManager(viewManagerRegistry, mMountItemExecutor); @@ -386,6 +385,11 @@ public void initialize() { ReactMarker.addFabricListener(mDevToolsReactPerfLogger); } + if (ReactFeatureFlags.unstable_useFabricInterop) { + InteropEventEmitter interopEventEmitter = new InteropEventEmitter(mReactApplicationContext); + mReactApplicationContext.internal_registerInteropModule( + RCTEventEmitter.class, interopEventEmitter); + } } // This is called on the JS thread (see CatalystInstanceImpl). @@ -1079,7 +1083,7 @@ public void setJSResponder( mMountItemDispatcher.addMountItem( new MountItem() { @Override - public void execute(MountingManager mountingManager) { + public void execute(@NonNull MountingManager mountingManager) { SurfaceMountingManager surfaceMountingManager = mountingManager.getSurfaceManager(surfaceId); if (surfaceMountingManager != null) { @@ -1096,6 +1100,8 @@ public int getSurfaceId() { return surfaceId; } + @NonNull + @SuppressLint("DefaultLocale") @Override public String toString() { return String.format("SET_JS_RESPONDER [%d] [surface:%d]", reactTag, surfaceId); @@ -1111,7 +1117,7 @@ public void clearJSResponder() { mMountItemDispatcher.addMountItem( new MountItem() { @Override - public void execute(MountingManager mountingManager) { + public void execute(@NonNull MountingManager mountingManager) { mountingManager.clearJSResponder(); } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/events/EventBeatManager.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/events/EventBeatManager.java index f67dd8716715cb..4c4703d0ae7910 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/events/EventBeatManager.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/events/EventBeatManager.java @@ -19,22 +19,25 @@ * Class that acts as a proxy between the list of EventBeats registered in C++ and the Android side. */ @SuppressLint("MissingNativeLoadLibrary") -public class EventBeatManager implements BatchEventDispatchedListener { +public final class EventBeatManager implements BatchEventDispatchedListener { static { FabricSoLoader.staticInit(); } @DoNotStrip private final HybridData mHybridData; - private final ReactApplicationContext mReactApplicationContext; private static native HybridData initHybrid(); private native void tick(); + @Deprecated(forRemoval = true, since = "Deprecated on v0.72.0 Use EventBeatManager() instead") public EventBeatManager(@NonNull ReactApplicationContext reactApplicationContext) { + this(); + } + + public EventBeatManager() { mHybridData = initHybrid(); - mReactApplicationContext = reactApplicationContext; } @Override diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/interop/InteropEvent.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/interop/InteropEvent.java new file mode 100644 index 00000000000000..881edbdf6fa4e1 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/interop/InteropEvent.java @@ -0,0 +1,41 @@ +/* + * 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. + */ + +package com.facebook.react.fabric.interop; + +import androidx.annotation.Nullable; +import com.facebook.react.bridge.WritableMap; +import com.facebook.react.common.annotations.VisibleForTesting; +import com.facebook.react.uimanager.events.Event; + +/** + * An {@link Event} class used by the {@link InteropEventEmitter}. This class is just holding the + * event name and the data which is received by the `receiveEvent` method and will be passed over + * the the {@link com.facebook.react.uimanager.events.EventDispatcher} + */ +class InteropEvent extends Event { + + private final String mName; + private final WritableMap mEventData; + + InteropEvent(String name, @Nullable WritableMap eventData, int surfaceId, int viewTag) { + super(surfaceId, viewTag); + mName = name; + mEventData = eventData; + } + + @Override + public String getEventName() { + return mName; + } + + @Override + @VisibleForTesting + public WritableMap getEventData() { + return mEventData; + } +} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/interop/InteropEventEmitter.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/interop/InteropEventEmitter.java new file mode 100644 index 00000000000000..aef10bffdfbdcf --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/interop/InteropEventEmitter.java @@ -0,0 +1,65 @@ +/* + * 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. + */ + +package com.facebook.react.fabric.interop; + +import androidx.annotation.Nullable; +import com.facebook.react.bridge.ReactContext; +import com.facebook.react.bridge.WritableArray; +import com.facebook.react.bridge.WritableMap; +import com.facebook.react.common.annotations.VisibleForTesting; +import com.facebook.react.uimanager.UIManagerHelper; +import com.facebook.react.uimanager.events.EventDispatcher; +import com.facebook.react.uimanager.events.RCTEventEmitter; + +/** + * A reimplementation of {@link RCTEventEmitter} which is using a {@link EventDispatcher} under the + * hood. + * + *

On Fabric, you're supposed to use {@link EventDispatcher} to dispatch events. However, we + * provide an interop layer for non-Fabric migrated components. + * + *

This instance will be returned if the user is invoking `context.getJsModule(RCTEventEmitter) + * and is providing support for the `receiveEvent` method, so that non-Fabric ViewManagers can + * continue to deliver events also when Fabric is turned on. + */ +public class InteropEventEmitter implements RCTEventEmitter { + + private final ReactContext mReactContext; + + private @Nullable EventDispatcher mEventDispatcherOverride; + + public InteropEventEmitter(ReactContext reactContext) { + mReactContext = reactContext; + } + + @Override + public void receiveEvent(int targetReactTag, String eventName, @Nullable WritableMap eventData) { + EventDispatcher dispatcher; + if (mEventDispatcherOverride != null) { + dispatcher = mEventDispatcherOverride; + } else { + dispatcher = UIManagerHelper.getEventDispatcherForReactTag(mReactContext, targetReactTag); + } + int surfaceId = UIManagerHelper.getSurfaceId(mReactContext); + if (dispatcher != null) { + dispatcher.dispatchEvent(new InteropEvent(eventName, eventData, surfaceId, targetReactTag)); + } + } + + @Override + public void receiveTouches( + String eventName, WritableArray touches, WritableArray changedIndices) { + throw new UnsupportedOperationException( + "EventEmitter#receiveTouches is not supported by the Fabric Interop Layer"); + } + + @VisibleForTesting + void overrideEventDispatcher(EventDispatcher eventDispatcherOverride) { + mEventDispatcherOverride = eventDispatcherOverride; + } +} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/SurfaceMountingManager.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/SurfaceMountingManager.java index 8863d0edca1bbb..f3fb5e0a0024bf 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/SurfaceMountingManager.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/SurfaceMountingManager.java @@ -103,7 +103,6 @@ public SurfaceMountingManager( @NonNull MountItemExecutor mountItemExecutor, @NonNull ThemedReactContext reactContext) { mSurfaceId = surfaceId; - mJSResponderHandler = jsResponderHandler; mViewManagerRegistry = viewManagerRegistry; mRootViewManager = rootViewManager; @@ -196,42 +195,39 @@ private void addRootView(@NonNull final View rootView) { true)); Runnable runnable = - new Runnable() { - @Override - public void run() { - // The CPU has ticked since `addRootView` was called, so the surface could technically - // have already stopped here. - if (isStopped()) { - return; - } - - if (rootView.getId() == mSurfaceId) { - ReactSoftExceptionLogger.logSoftException( - TAG, - new IllegalViewOperationException( - "Race condition in addRootView detected. Trying to set an id of [" - + mSurfaceId - + "] on the RootView, but that id has already been set. ")); - } else if (rootView.getId() != View.NO_ID) { - FLog.e( - TAG, - "Trying to add RootTag to RootView that already has a tag: existing tag: [%d] new tag: [%d]", - rootView.getId(), - mSurfaceId); - throw new IllegalViewOperationException( - "Trying to add a root view with an explicit id already set. React Native uses " - + "the id field to track react tags and will overwrite this field. If that is fine, " - + "explicitly overwrite the id field to View.NO_ID before calling addRootView."); - } - rootView.setId(mSurfaceId); + () -> { + // The CPU has ticked since `addRootView` was called, so the surface could technically + // have already stopped here. + if (isStopped()) { + return; + } - if (rootView instanceof ReactRoot) { - ((ReactRoot) rootView).setRootViewTag(mSurfaceId); - } - mRootViewAttached = true; + if (rootView.getId() == mSurfaceId) { + ReactSoftExceptionLogger.logSoftException( + TAG, + new IllegalViewOperationException( + "Race condition in addRootView detected. Trying to set an id of [" + + mSurfaceId + + "] on the RootView, but that id has already been set. ")); + } else if (rootView.getId() != View.NO_ID) { + FLog.e( + TAG, + "Trying to add RootTag to RootView that already has a tag: existing tag: [%d] new tag: [%d]", + rootView.getId(), + mSurfaceId); + throw new IllegalViewOperationException( + "Trying to add a root view with an explicit id already set. React Native uses " + + "the id field to track react tags and will overwrite this field. If that is fine, " + + "explicitly overwrite the id field to View.NO_ID before calling addRootView."); + } + rootView.setId(mSurfaceId); - executeViewAttachMountItems(); + if (rootView instanceof ReactRoot) { + ((ReactRoot) rootView).setRootViewTag(mSurfaceId); } + mRootViewAttached = true; + + executeViewAttachMountItems(); }; if (UiThreadUtil.isOnUiThread()) { @@ -1105,21 +1101,26 @@ public void updateEventEmitter(int reactTag, @NonNull EventEmitterWrapper eventE previousEventEmitterWrapper.destroy(); } - if (viewState.mPendingEventQueue != null) { + Queue pendingEventQueue = viewState.mPendingEventQueue; + if (pendingEventQueue != null) { // Invoke pending event queued to the view state - for (ViewEvent viewEvent : viewState.mPendingEventQueue) { - if (viewEvent.canCoalesceEvent()) { - eventEmitter.dispatchUnique( - viewEvent.getEventName(), viewEvent.getParams(), viewEvent.getCustomCoalesceKey()); - } else { - eventEmitter.dispatch( - viewEvent.getEventName(), viewEvent.getParams(), viewEvent.getEventCategory()); - } + for (ViewEvent viewEvent : pendingEventQueue) { + dispatchEvent(eventEmitter, viewEvent); } viewState.mPendingEventQueue = null; } } + private void dispatchEvent(EventEmitterWrapper eventEmitter, ViewEvent viewEvent) { + if (viewEvent.canCoalesceEvent()) { + eventEmitter.dispatchUnique( + viewEvent.getEventName(), viewEvent.getParams(), viewEvent.getCustomCoalesceKey()); + } else { + eventEmitter.dispatch( + viewEvent.getEventName(), viewEvent.getParams(), viewEvent.getEventCategory()); + } + } + @UiThread public synchronized void setJSResponder( int reactTag, int initialReactTag, boolean blockNativeResponder) { @@ -1301,9 +1302,18 @@ public void enqueuePendingEvent(int reactTag, ViewEvent viewEvent) { // Cannot queue event without view state. Do nothing here. return; } - Assertions.assertCondition( - viewState.mEventEmitter == null, - "Only queue pending events when event emitter is null for the given view state"); + EventEmitterWrapper eventEmitter = viewState.mEventEmitter; + if (eventEmitter != null) { + // TODO T152630743: Verify threading for mEventEmitter + FLog.i( + TAG, + "Queue pending events when event emitter is null for the given view state, this should be dispatched instead - surfaceId: " + + mSurfaceId + + " reactTag: " + + reactTag); + dispatchEvent(eventEmitter, viewEvent); + return; + } if (viewState.mPendingEventQueue == null) { viewState.mPendingEventQueue = new LinkedList<>(); @@ -1342,6 +1352,7 @@ private ViewState( mViewManager = viewManager; } + @NonNull @Override public String toString() { boolean isLayoutOnly = mViewManager == null; diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/common/ModuleDataCleaner.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/common/ModuleDataCleaner.java index fabc71170f32a2..ed1b526ad1710d 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/common/ModuleDataCleaner.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/common/ModuleDataCleaner.java @@ -43,6 +43,7 @@ public interface Cleanable { * * @deprecated */ + @Deprecated public static void cleanDataFromModules(CatalystInstance catalystInstance) { for (NativeModule nativeModule : catalystInstance.getNativeModules()) { if (nativeModule instanceof Cleanable) { diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/fabric/ReactFabric.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/fabric/ReactFabric.java deleted file mode 100644 index 46bd31ba032dd7..00000000000000 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/fabric/ReactFabric.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -package com.facebook.react.modules.fabric; - -import com.facebook.react.bridge.JavaScriptModule; - -/** - * JS module used to execute Fabric specific methods. Note: This is a temporary class that will be - * replaced when Fabric is fully integrated with the rest of the modules. - */ -public interface ReactFabric extends JavaScriptModule { - - /** - * JS method used to unmount Fabric surfaces. - * - * @param rootTag {@link int} react tag of Root {@link - * com.facebook.react.uimanager.ReactShadowNode} - */ - void unmountComponentAtNode(int rootTag); -} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/permissions/PermissionsModule.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/permissions/PermissionsModule.java index 1ff5fa5a5995e1..af6d28b396a7a7 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/permissions/PermissionsModule.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/permissions/PermissionsModule.java @@ -13,6 +13,7 @@ import android.os.Build; import android.os.Process; import android.util.SparseArray; +import com.facebook.common.logging.FLog; import com.facebook.fbreact.specs.NativePermissionsAndroidSpec; import com.facebook.react.bridge.Callback; import com.facebook.react.bridge.Promise; @@ -198,9 +199,17 @@ public void invoke(Object... args) { @Override public boolean onRequestPermissionsResult( int requestCode, String[] permissions, int[] grantResults) { - mCallbacks.get(requestCode).invoke(grantResults, getPermissionAwareActivity()); - mCallbacks.remove(requestCode); - return mCallbacks.size() == 0; + try { + mCallbacks.get(requestCode).invoke(grantResults, getPermissionAwareActivity()); + mCallbacks.remove(requestCode); + return mCallbacks.size() == 0; + } catch (IllegalStateException e) { + FLog.e( + "PermissionsModule", + e, + "Unexpected invocation of `onRequestPermissionsResult` with invalid current activity"); + return false; + } } private PermissionAwareActivity getPermissionAwareActivity() { diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/TurboModuleManager.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/TurboModuleManager.java index ecb5203c39dff3..c17a99bfef88db 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/TurboModuleManager.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/TurboModuleManager.java @@ -10,12 +10,15 @@ import androidx.annotation.GuardedBy; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import com.facebook.common.logging.FLog; import com.facebook.infer.annotation.Assertions; import com.facebook.jni.HybridData; import com.facebook.proguard.annotations.DoNotStrip; import com.facebook.react.bridge.CxxModuleWrapper; import com.facebook.react.bridge.JSIModule; import com.facebook.react.bridge.NativeModule; +import com.facebook.react.bridge.ReactNoCrashSoftException; +import com.facebook.react.bridge.ReactSoftExceptionLogger; import com.facebook.react.bridge.RuntimeExecutor; import com.facebook.react.config.ReactFeatureFlags; import com.facebook.react.turbomodule.core.interfaces.CallInvokerHolder; @@ -36,8 +39,9 @@ public class TurboModuleManager implements JSIModule, TurboModuleRegistry { private static volatile boolean sIsSoLibraryLoaded; private final List mEagerInitModuleNames; - private final ModuleProvider mModuleProvider; - private final ModuleProvider mLegacyModuleProvider; + private final ModuleProvider mTurboModuleProvider; + private final ModuleProvider mLegacyModuleProvider; + private final TurboModuleManagerDelegate mDelegate; // Prevents the creation of new TurboModules once cleanup as been initiated. private final Object mModuleCleanupLock = new Object(); @@ -59,6 +63,7 @@ public TurboModuleManager( CallInvokerHolder jsCallInvokerHolder, CallInvokerHolder nativeCallInvokerHolder) { maybeLoadSoLibrary(); + mDelegate = delegate; mHybridData = initHybrid( runtimeExecutor, @@ -68,47 +73,37 @@ public TurboModuleManager( installJSIBindings(shouldCreateLegacyModules()); mEagerInitModuleNames = - delegate == null ? new ArrayList() : delegate.getEagerInitModuleNames(); - - mModuleProvider = - moduleName -> { - if (delegate == null || shouldRouteTurboModulesThroughInteropLayer()) { - return null; - } - - TurboModule module = delegate.getModule(moduleName); - if (module == null) { - CxxModuleWrapper legacyCxxModule = delegate.getLegacyCxxModule(moduleName); - - if (legacyCxxModule != null) { - // TurboModuleManagerDelegate.getLegacyCxxModule() must always return TurboModules - Assertions.assertCondition( - legacyCxxModule instanceof TurboModule, - "CxxModuleWrapper \"" + moduleName + "\" is not a TurboModule"); - module = (TurboModule) legacyCxxModule; - } - } - return module; - }; + delegate == null ? new ArrayList<>() : delegate.getEagerInitModuleNames(); + + ModuleProvider nullProvider = moduleName -> null; + + mTurboModuleProvider = + delegate == null + ? nullProvider + : moduleName -> (NativeModule) delegate.getModule(moduleName); mLegacyModuleProvider = - moduleName -> { - if (delegate == null || !shouldCreateLegacyModules()) { - return null; - } - - NativeModule nativeModule = delegate.getLegacyModule(moduleName); - if (nativeModule != null) { - if (!shouldRouteTurboModulesThroughInteropLayer()) { - // TurboModuleManagerDelegate.getLegacyModule must never return a TurboModule - Assertions.assertCondition( - !(nativeModule instanceof TurboModule), - "NativeModule \"" + moduleName + "\" is a TurboModule"); - } - return nativeModule; - } - return nativeModule; - }; + delegate == null || !shouldCreateLegacyModules() + ? nullProvider + : moduleName -> { + NativeModule nativeModule = delegate.getLegacyModule(moduleName); + if (nativeModule != null) { + // TurboModuleManagerDelegate.getLegacyModule must never return a TurboModule + Assertions.assertCondition( + !(nativeModule instanceof TurboModule), + "NativeModule \"" + moduleName + "\" is a TurboModule"); + return nativeModule; + } + return null; + }; + } + + private boolean isTurboModule(String moduleName) { + return mDelegate != null && mDelegate.unstable_isModuleRegistered(moduleName); + } + + private boolean isLegacyModule(String moduleName) { + return mDelegate != null && mDelegate.unstable_isLegacyModuleRegistered(moduleName); } private static boolean shouldCreateLegacyModules() { @@ -135,9 +130,21 @@ private static List getMethodDescripto @DoNotStrip @Nullable private NativeModule getLegacyJavaModule(String moduleName) { - final NativeModule module = getNativeModule(moduleName); - return !(module instanceof CxxModuleWrapper) - && (shouldRouteTurboModulesThroughInteropLayer() || !(module instanceof TurboModule)) + if (shouldRouteTurboModulesThroughInteropLayer()) { + final NativeModule module = getModule(moduleName); + return !(module instanceof CxxModuleWrapper) ? module : null; + } + + /* + * This API is invoked from global.nativeModuleProxy. + * Only call getModule if the native module is a legacy module. + */ + if (!isLegacyModule(moduleName)) { + return null; + } + + final NativeModule module = getModule(moduleName); + return !(module instanceof CxxModuleWrapper) && !(module instanceof TurboModule) ? module : null; } @@ -146,9 +153,21 @@ private NativeModule getLegacyJavaModule(String moduleName) { @DoNotStrip @Nullable private CxxModuleWrapper getLegacyCxxModule(String moduleName) { - final NativeModule module = getNativeModule(moduleName); - return module instanceof CxxModuleWrapper - && (shouldRouteTurboModulesThroughInteropLayer() || !(module instanceof TurboModule)) + if (shouldRouteTurboModulesThroughInteropLayer()) { + final NativeModule module = getModule(moduleName); + return module instanceof CxxModuleWrapper ? (CxxModuleWrapper) module : null; + } + + /* + * This API is invoked from global.nativeModuleProxy. + * Only call getModule if the native module is a legacy module. + */ + if (!isLegacyModule(moduleName)) { + return null; + } + + final NativeModule module = getModule(moduleName); + return module instanceof CxxModuleWrapper && !(module instanceof TurboModule) ? (CxxModuleWrapper) module : null; } @@ -160,7 +179,16 @@ private CxxModuleWrapper getTurboLegacyCxxModule(String moduleName) { if (shouldRouteTurboModulesThroughInteropLayer()) { return null; } - final NativeModule module = getNativeModule(moduleName); + + /* + * This API is invoked from global.__turboModuleProxy. + * Only call getModule if the native module is a turbo module. + */ + if (!isTurboModule(moduleName)) { + return null; + } + + final NativeModule module = getModule(moduleName); return module instanceof CxxModuleWrapper && module instanceof TurboModule ? (CxxModuleWrapper) module : null; @@ -172,18 +200,21 @@ private TurboModule getTurboJavaModule(String moduleName) { if (shouldRouteTurboModulesThroughInteropLayer()) { return null; } - final NativeModule module = getNativeModule(moduleName); + + /* + * This API is invoked from global.__turboModuleProxy. + * Only call getModule if the native module is a turbo module. + */ + if (!isTurboModule(moduleName)) { + return null; + } + + final NativeModule module = getModule(moduleName); return !(module instanceof CxxModuleWrapper) && module instanceof TurboModule ? (TurboModule) module : null; } - @Deprecated - public TurboModule getModule(String moduleName) { - NativeModule module = getNativeModule(moduleName); - return module instanceof TurboModule ? (TurboModule) module : null; - } - /** * Return the NativeModule instance that corresponds to the provided moduleName. * @@ -191,7 +222,7 @@ public TurboModule getModule(String moduleName) { * null after TurboModuleManager has been torn down. */ @Nullable - public NativeModule getNativeModule(String moduleName) { + public NativeModule getModule(String moduleName) { ModuleHolder moduleHolder; synchronized (mModuleCleanupLock) { @@ -199,6 +230,14 @@ public NativeModule getNativeModule(String moduleName) { /* * Always return null after cleanup has started, so that getNativeModule(moduleName) returns null. */ + logError( + "getModule(): Tried to get module \"" + + moduleName + + "\", but TurboModuleManager was tearing down. Returning null. Was legacy: " + + isLegacyModule(moduleName) + + ". Was turbo: " + + isTurboModule(moduleName) + + "."); return null; } @@ -214,7 +253,7 @@ public NativeModule getNativeModule(String moduleName) { } TurboModulePerfLogger.moduleCreateStart(moduleName, moduleHolder.getModuleId()); - NativeModule module = getOrCreateNativeModule(moduleName, moduleHolder, true); + NativeModule module = getOrCreateModule(moduleName, moduleHolder, true); if (module != null) { TurboModulePerfLogger.moduleCreateEnd(moduleName, moduleHolder.getModuleId()); @@ -232,7 +271,7 @@ public NativeModule getNativeModule(String moduleName) { * first thread creates x. All n - 1 other threads wait until the x is created and initialized. */ @Nullable - private NativeModule getOrCreateNativeModule( + private NativeModule getOrCreateModule( String moduleName, @NonNull ModuleHolder moduleHolder, boolean shouldPerfLog) { boolean shouldCreateModule = false; @@ -254,7 +293,7 @@ private NativeModule getOrCreateNativeModule( if (shouldCreateModule) { TurboModulePerfLogger.moduleCreateConstructStart(moduleName, moduleHolder.getModuleId()); - NativeModule nativeModule = (NativeModule) mModuleProvider.getModule(moduleName); + NativeModule nativeModule = mTurboModuleProvider.getModule(moduleName); if (nativeModule == null) { nativeModule = mLegacyModuleProvider.getModule(moduleName); @@ -274,6 +313,15 @@ private NativeModule getOrCreateNativeModule( * Therefore, we should initialize on the TurboModule now. */ nativeModule.initialize(); + } else { + logError( + "getOrCreateModule(): Unable to create module \"" + + moduleName + + "\". Was legacy: " + + isLegacyModule(moduleName) + + ". Was turbo: " + + isTurboModule(moduleName) + + "."); } TurboModulePerfLogger.moduleCreateSetUpEnd(moduleName, moduleHolder.getModuleId()); @@ -309,21 +357,8 @@ private NativeModule getOrCreateNativeModule( } } - @Deprecated - public Collection getModules() { - final Collection modules = new ArrayList<>(); - - for (final NativeModule module : getNativeModules()) { - if (module instanceof TurboModule) { - modules.add((TurboModule) module); - } - } - - return modules; - } - /** Which NativeModules have been created? */ - public Collection getNativeModules() { + public Collection getModules() { final List moduleHolders = new ArrayList<>(); synchronized (mModuleCleanupLock) { moduleHolders.addAll(mModuleHolders.values()); @@ -342,7 +377,6 @@ public Collection getNativeModules() { return modules; } - @Deprecated public boolean hasModule(String moduleName) { ModuleHolder moduleHolder; synchronized (mModuleCleanupLock) { @@ -351,7 +385,7 @@ public boolean hasModule(String moduleName) { if (moduleHolder != null) { synchronized (moduleHolder) { - if (moduleHolder.getModule() instanceof TurboModule) { + if (moduleHolder.getModule() != null) { return true; } } @@ -360,21 +394,12 @@ public boolean hasModule(String moduleName) { return false; } - public boolean hasNativeModule(String moduleName) { - ModuleHolder moduleHolder; - synchronized (mModuleCleanupLock) { - moduleHolder = mModuleHolders.get(moduleName); - } - - if (moduleHolder != null) { - synchronized (moduleHolder) { - if (moduleHolder.getModule() != null) { - return true; - } - } + public static void logError(String message) { + FLog.e("TurboModuleManager", message); + if (shouldRouteTurboModulesThroughInteropLayer()) { + ReactSoftExceptionLogger.logSoftException( + "TurboModuleManager", new ReactNoCrashSoftException(message)); } - - return false; } private native HybridData initHybrid( @@ -412,7 +437,7 @@ public void onCatalystInstanceDestroy() { * initialized. In this case, we should wait for initialization to complete, before destroying * the TurboModule. */ - final NativeModule nativeModule = getOrCreateNativeModule(moduleName, moduleHolder, false); + final NativeModule nativeModule = getOrCreateModule(moduleName, moduleHolder, false); if (nativeModule != null) { nativeModule.invalidate(); @@ -476,8 +501,8 @@ boolean isCreatingModule() { } } - private interface ModuleProvider { + private interface ModuleProvider { @Nullable - T getModule(String name); + NativeModule getModule(String name); } } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/TurboModuleManagerDelegate.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/TurboModuleManagerDelegate.java index 0a55f1faf9ee70..4c187079eb3a25 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/TurboModuleManagerDelegate.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/TurboModuleManagerDelegate.java @@ -10,7 +10,6 @@ import androidx.annotation.Nullable; import com.facebook.jni.HybridData; import com.facebook.proguard.annotations.DoNotStrip; -import com.facebook.react.bridge.CxxModuleWrapper; import com.facebook.react.bridge.NativeModule; import com.facebook.react.turbomodule.core.interfaces.TurboModule; import com.facebook.soloader.SoLoader; @@ -39,15 +38,7 @@ protected TurboModuleManagerDelegate() { @Nullable public abstract TurboModule getModule(String moduleName); - /** - * Create and return a CxxModuleWrapper NativeModule with name `moduleName`. If `moduleName` isn't - * a CxxModule, return null. CxxModuleWrapper must implement TurboModule. - * - *

Deprecated. Please just return your CxxModuleWrappers from getModule. - */ - @Deprecated - @Nullable - public abstract CxxModuleWrapper getLegacyCxxModule(String moduleName); + public abstract boolean unstable_isModuleRegistered(String moduleName); /** * Create an return a legacy NativeModule with name `moduleName`. If `moduleName` is a @@ -58,6 +49,10 @@ public NativeModule getLegacyModule(String moduleName) { return null; } + public boolean unstable_isLegacyModuleRegistered(String moduleName) { + return false; + }; + public List getEagerInitModuleNames() { return new ArrayList<>(); } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/interfaces/TurboModuleRegistry.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/interfaces/TurboModuleRegistry.java index b7fc5a944191f9..a255d1a4140531 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/interfaces/TurboModuleRegistry.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/interfaces/TurboModuleRegistry.java @@ -19,36 +19,19 @@ * deleted, we should rename this interface accordingly. */ public interface TurboModuleRegistry { - /** - * Return the TurboModule instance that has that name `moduleName`. If the `moduleName` - * TurboModule hasn't been instantiated, instantiate it. If no TurboModule is registered under - * `moduleName`, return null. - */ - @Deprecated - @Nullable - TurboModule getModule(String moduleName); - - /** Get all instantiated TurboModules. */ - @Deprecated - Collection getModules(); - - /** Has the TurboModule with name `moduleName` been instantiated? */ - @Deprecated - boolean hasModule(String moduleName); - /** * Return the NativeModule instance that has that name `moduleName`. If the `moduleName` - * NativeModule hasn't been instantiated, instantiate it. If no NativeModule is registered under + * TurboModule hasn't been instantiated, instantiate it. If no TurboModule is registered under * `moduleName`, return null. */ @Nullable - NativeModule getNativeModule(String moduleName); + NativeModule getModule(String moduleName); - /** Get all instantiated NativeModule. */ - Collection getNativeModules(); + /** Get all instantiated NativeModules. */ + Collection getModules(); /** Has the NativeModule with name `moduleName` been instantiated? */ - boolean hasNativeModule(String moduleName); + boolean hasModule(String moduleName); /** * Return the names of all the NativeModules that are supposed to be eagerly initialized. By diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/JSPointerDispatcher.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/JSPointerDispatcher.java index c2125fa3eed78a..bc904f755f9941 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/JSPointerDispatcher.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/JSPointerDispatcher.java @@ -7,6 +7,7 @@ package com.facebook.react.uimanager; +import android.graphics.Rect; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; @@ -63,10 +64,24 @@ public void onChildStartedNativeGesture( return; } - dispatchCancelEvent(motionEvent, eventDispatcher); + MotionEvent motionInRoot = convertMotionToRootFrame(childView, motionEvent); + + dispatchCancelEventForTarget(childView, motionInRoot, eventDispatcher); mChildHandlingNativeGesture = childView.getId(); } + private MotionEvent convertMotionToRootFrame(View childView, MotionEvent childMotion) { + MotionEvent motionInRoot = MotionEvent.obtain(childMotion); + final int cX = (int) childMotion.getX(); + final int cY = (int) childMotion.getY(); + Rect childCoords = new Rect(cX, cY, cX + 1, cY + 1); + // note: should be safe since we're only looking at descendants of the root + mRootViewGroup.offsetDescendantRectToMyCoords(childView, childCoords); + motionInRoot.setLocation(childCoords.left, childCoords.top); + + return motionInRoot; + } + public void onChildEndedNativeGesture() { // There should be only one child gesture at any given time. We can safely turn off the flag. mChildHandlingNativeGesture = -1; @@ -228,6 +243,7 @@ public void handleMotionEvent( // 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; + View activeTargetView; List activeHitPath; if (isExitFromRoot) { @@ -238,7 +254,9 @@ public void handleMotionEvent( if (lastHitPath == null || lastHitPath.isEmpty()) { return; } - activeTargetTag = lastHitPath.get(lastHitPath.size() - 1).getViewId(); + ViewTarget activeTarget = lastHitPath.get(lastHitPath.size() - 1); + activeTargetTag = activeTarget.getViewId(); + activeTargetView = activeTarget.getView(); // Explicitly make the hit path for this cursor empty activeHitPath = new ArrayList<>(); @@ -248,7 +266,9 @@ public void handleMotionEvent( if (activeHitPath == null || activeHitPath.isEmpty()) { return; } - activeTargetTag = activeHitPath.get(0).getViewId(); + ViewTarget activeTarget = activeHitPath.get(0); + activeTargetTag = activeTarget.getViewId(); + activeTargetView = activeTarget.getView(); } handleHitStateDivergence(activeTargetTag, eventState, motionEvent, eventDispatcher); @@ -284,7 +304,7 @@ public void handleMotionEvent( onUp(activeTargetTag, eventState, motionEvent, eventDispatcher); break; case MotionEvent.ACTION_CANCEL: - dispatchCancelEvent(eventState, motionEvent, eventDispatcher); + dispatchCancelEventForTarget(activeTargetView, eventState, motionEvent, eventDispatcher); break; case MotionEvent.ACTION_HOVER_ENTER: // Ignore these events as enters will be calculated from HOVER_MOVE @@ -504,7 +524,8 @@ private void onMove( } } - private void dispatchCancelEvent(MotionEvent motionEvent, EventDispatcher eventDispatcher) { + private void dispatchCancelEventForTarget( + View targetView, MotionEvent motionEvent, EventDispatcher eventDispatcher) { Assertions.assertCondition( mChildHandlingNativeGesture == -1, "Expected to not have already sent a cancel for this gesture"); @@ -512,11 +533,14 @@ private void dispatchCancelEvent(MotionEvent motionEvent, EventDispatcher eventD int activeIndex = motionEvent.getActionIndex(); int activePointerId = motionEvent.getPointerId(activeIndex); PointerEventState eventState = createEventState(activePointerId, motionEvent); - dispatchCancelEvent(eventState, motionEvent, eventDispatcher); + dispatchCancelEventForTarget(targetView, eventState, motionEvent, eventDispatcher); } - private void dispatchCancelEvent( - PointerEventState eventState, MotionEvent motionEvent, EventDispatcher eventDispatcher) { + private void dispatchCancelEventForTarget( + View targetView, + PointerEventState eventState, + MotionEvent motionEvent, + EventDispatcher eventDispatcher) { // This means the gesture has already ended, via some other CANCEL or UP event. This is not // expected to happen very often as it would mean some child View has decided to intercept the // touch stream and start a native gesture only upon receiving the UP/CANCEL event. @@ -532,18 +556,31 @@ private void dispatchCancelEvent( isAnyoneListeningForBubblingEvent(activeHitPath, EVENT.CANCEL, EVENT.CANCEL_CAPTURE); if (listeningForCancel) { int targetTag = activeHitPath.get(0).getViewId(); + + // cancel events need to report client coordinates of (0, 0) and offset coordinates relative + // to the root view + int[] childOffset = getChildOffsetRelativeToRoot(targetView); + PointerEventState normalizedEventState = + normalizeToRoot(eventState, childOffset[0], childOffset[1]); Assertions.assertNotNull(eventDispatcher) .dispatchEvent( PointerEvent.obtain( - PointerEventHelper.POINTER_CANCEL, targetTag, eventState, motionEvent)); + PointerEventHelper.POINTER_CANCEL, + targetTag, + normalizedEventState, + motionEvent)); } - // TODO(luwe) - Need to fire pointer out here as well: + // Need to fire pointer out + pointer leave here as well: // https://w3c.github.io/pointerevents/#dfn-suppress-a-pointer-event-stream + List outViewTargets = + filterByShouldDispatch(activeHitPath, EVENT.OUT, EVENT.OUT_CAPTURE, false); List leaveViewTargets = filterByShouldDispatch(activeHitPath, EVENT.LEAVE, EVENT.LEAVE_CAPTURE, false); // dispatch from target -> root + dispatchEventForViewTargets( + PointerEventHelper.POINTER_OUT, eventState, motionEvent, outViewTargets, eventDispatcher); dispatchEventForViewTargets( PointerEventHelper.POINTER_LEAVE, eventState, @@ -558,6 +595,44 @@ private void dispatchCancelEvent( } } + // returns child (0, 0) relative to root coordinate system + private int[] getChildOffsetRelativeToRoot(View childView) { + Rect childCoords = new Rect(0, 0, 1, 1); + mRootViewGroup.offsetDescendantRectToMyCoords(childView, childCoords); + return new int[] {childCoords.top, childCoords.left}; + } + + // Returns a copy of `original` with coordinates zeroed relative to the provided root coordinates. + // In particular, + // - the event (client) coordinates will all be set to 0 + // - the offset coordinates will be set to the root coordinates + private PointerEventState normalizeToRoot(PointerEventState original, float rootX, float rootY) { + Map newOffsets = new HashMap<>(original.getOffsetByPointerId()); + Map newEventCoords = new HashMap<>(original.getEventCoordinatesByPointerId()); + + for (Map.Entry offsetEntry : newOffsets.entrySet()) { + float[] offsetValue = offsetEntry.getValue(); + offsetValue[0] = rootX; + offsetValue[1] = rootY; + } + + for (Map.Entry eventCoordsEntry : newEventCoords.entrySet()) { + float[] eventCoordsValue = eventCoordsEntry.getValue(); + eventCoordsValue[0] = 0; + eventCoordsValue[1] = 0; + } + + return new PointerEventState( + original.getPrimaryPointerId(), + original.getActivePointerId(), + original.getLastButtonState(), + original.getSurfaceId(), + newOffsets, + new HashMap<>(original.getHitPathByPointerId()), + newEventCoords, + new HashSet<>(original.getHoveringPointerIds())); + } + private static void debugPrintHitPath(List hitPath) { StringBuilder builder = new StringBuilder("hitPath: "); for (ViewTarget viewTarget : hitPath) { diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java index c2e3023d026955..9dca8b0a37361f 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java @@ -860,12 +860,7 @@ public synchronized void dispatchCommand( + commandId); } ViewManager viewManager = resolveViewManager(reactTag); - ViewManagerDelegate delegate = viewManager.getDelegate(); - if (delegate != null) { - delegate.receiveCommand(view, commandId, args); - } else { - viewManager.receiveCommand(view, commandId, args); - } + viewManager.receiveCommand(view, commandId, args); } /** diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactYogaConfigProvider.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactYogaConfigProvider.java index a9da826a4c8059..16fbb71ae118b5 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactYogaConfigProvider.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactYogaConfigProvider.java @@ -9,6 +9,7 @@ import com.facebook.yoga.YogaConfig; import com.facebook.yoga.YogaConfigFactory; +import com.facebook.yoga.YogaErrata; public class ReactYogaConfigProvider { @@ -18,7 +19,7 @@ public static YogaConfig get() { if (YOGA_CONFIG == null) { YOGA_CONFIG = YogaConfigFactory.create(); YOGA_CONFIG.setPointScaleFactor(0f); - YOGA_CONFIG.setUseLegacyStretchBehaviour(true); + YOGA_CONFIG.setErrata(YogaErrata.ALL); } return YOGA_CONFIG; } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/RootView.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/RootView.java index ca8fa5f65849ee..4e0e1723368e05 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/RootView.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/RootView.java @@ -20,6 +20,7 @@ public interface RootView { void onChildStartedNativeGesture(View childView, MotionEvent ev); /** @deprecated */ + @Deprecated void onChildStartedNativeGesture(MotionEvent ev); /** diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/ThemedReactContext.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/ThemedReactContext.java index 28cd1855473d35..b10d2d9b3c0681 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/ThemedReactContext.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/ThemedReactContext.java @@ -50,6 +50,7 @@ public ThemedReactContext( if (reactApplicationContext.hasCatalystInstance()) { initializeWithInstance(reactApplicationContext.getCatalystInstance()); } + initializeInteropModules(reactApplicationContext); mReactApplicationContext = reactApplicationContext; mModuleName = moduleName; mSurfaceId = surfaceId; diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModuleConstantsHelper.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModuleConstantsHelper.java index a4d8facc08d9ec..cd10e3a76d0698 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModuleConstantsHelper.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModuleConstantsHelper.java @@ -10,11 +10,16 @@ import static com.facebook.systrace.Systrace.TRACE_TAG_REACT_JAVA_BRIDGE; import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; import com.facebook.react.common.MapBuilder; +import com.facebook.react.config.ReactFeatureFlags; import com.facebook.systrace.SystraceMessage; import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; /** * Helps generate constants map for {@link UIManagerModule} by collecting and merging constants from @@ -113,6 +118,13 @@ Map viewManagerBubblingEvents = viewManager.getExportedCustomBubblingEventTypeConstants(); if (viewManagerBubblingEvents != null) { + + if (ReactFeatureFlags.enableFabricRenderer && ReactFeatureFlags.unstable_useFabricInterop) { + // For Fabric, events needs to be fired with a "top" prefix. + // For the sake of Fabric Interop, here we normalize events adding "top" in their + // name if the user hasn't provided it. + normalizeEventTypes(viewManagerBubblingEvents); + } recursiveMerge(cumulativeBubblingEventTypes, viewManagerBubblingEvents); recursiveMerge(viewManagerBubblingEvents, defaultBubblingEvents); viewManagerConstants.put(BUBBLING_EVENTS_KEY, viewManagerBubblingEvents); @@ -145,6 +157,27 @@ return viewManagerConstants; } + @VisibleForTesting + /* package */ static void normalizeEventTypes(Map events) { + if (events == null) { + return; + } + Set keysToNormalize = new HashSet<>(); + for (Object key : events.keySet()) { + if (key instanceof String) { + String keyString = (String) key; + if (!keyString.startsWith("top")) { + keysToNormalize.add(keyString); + } + } + } + for (String oldKey : keysToNormalize) { + Object value = events.get(oldKey); + String newKey = "top" + oldKey.substring(0, 1).toUpperCase() + oldKey.substring(1); + events.put(newKey, value); + } + } + /** Merges {@param source} map into {@param dest} map recursively */ private static void recursiveMerge(@Nullable Map dest, @Nullable Map source) { if (dest == null || source == null || source.isEmpty()) { @@ -155,6 +188,11 @@ private static void recursiveMerge(@Nullable Map dest, @Nullable Map source) { Object sourceValue = source.get(key); Object destValue = dest.get(key); if (destValue != null && (sourceValue instanceof Map) && (destValue instanceof Map)) { + // Since event maps are client based Map interface, it could be immutable + if (!(destValue instanceof HashMap)) { + destValue = new HashMap((Map) destValue); + dest.replace(key, (Map) destValue); + } recursiveMerge((Map) destValue, (Map) sourceValue); } else { dest.put(key, sourceValue); diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManager.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManager.java index 1e16571963be50..3c1e668cef72e7 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManager.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManager.java @@ -285,7 +285,12 @@ public void receiveCommand(@NonNull T root, int commandId, @Nullable ReadableArr * @param commandId code of the command * @param args optional arguments for the command */ - public void receiveCommand(@NonNull T root, String commandId, @Nullable ReadableArray args) {} + public void receiveCommand(@NonNull T root, String commandId, @Nullable ReadableArray args) { + final ViewManagerDelegate delegate = getDelegate(); + if (delegate != null) { + delegate.receiveCommand(root, commandId, args); + } + } /** * Subclasses of {@link ViewManager} that expect to receive commands through {@link diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/PointerEvent.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/PointerEvent.java index bdcab7b048a6e7..9b5bc00a973376 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/PointerEvent.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/PointerEvent.java @@ -356,6 +356,10 @@ public boolean supportsHover(int pointerId) { return mHoveringPointerIds.contains(pointerId); } + public Set getHoveringPointerIds() { + return mHoveringPointerIds; + } + public final Map getOffsetByPointerId() { return mOffsetByPointerId; } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/drawer/ReactDrawerLayoutManager.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/drawer/ReactDrawerLayoutManager.java index 68a941f16ed717..7e24f0d7345574 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/drawer/ReactDrawerLayoutManager.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/drawer/ReactDrawerLayoutManager.java @@ -58,7 +58,8 @@ public ReactDrawerLayoutManager() { } @Override - protected void addEventEmitters(ThemedReactContext reactContext, ReactDrawerLayout view) { + protected void addEventEmitters( + @NonNull ThemedReactContext reactContext, ReactDrawerLayout view) { EventDispatcher eventDispatcher = UIManagerHelper.getEventDispatcherForReactTag(reactContext, view.getId()); if (eventDispatcher == null) { @@ -188,7 +189,8 @@ public boolean needsCustomLayoutForChildren() { } @Override - public void receiveCommand(ReactDrawerLayout root, int commandId, @Nullable ReadableArray args) { + public void receiveCommand( + @NonNull ReactDrawerLayout root, int commandId, @Nullable ReadableArray args) { switch (commandId) { case OPEN_DRAWER: root.openDrawer(); @@ -213,13 +215,13 @@ public void receiveCommand( } @Override - public @Nullable Map getExportedViewConstants() { + public @Nullable Map getExportedViewConstants() { return MapBuilder.of( "DrawerPosition", MapBuilder.of("Left", Gravity.START, "Right", Gravity.END)); } @Override - public @Nullable Map getExportedCustomDirectEventTypeConstants() { + public @Nullable Map getExportedCustomDirectEventTypeConstants() { @Nullable Map baseEventTypeConstants = super.getExportedCustomDirectEventTypeConstants(); Map eventTypeConstants = diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewAccessibilityDelegate.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewAccessibilityDelegate.java index 6cf22db90c04e1..bc122f2ee3f112 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewAccessibilityDelegate.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewAccessibilityDelegate.java @@ -105,7 +105,7 @@ private void onInitializeAccessibilityEventInternal(View view, AccessibilityEven } } - if (isVisible == true && accessibilityCollectionItem != null) { + if (isVisible && accessibilityCollectionItem != null) { if (firstVisibleIndex == null) { firstVisibleIndex = accessibilityCollectionItem.getInt("itemIndex"); } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ContentSizeWatcher.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ContentSizeWatcher.java index 73da55e7e30bc9..16df4fff108564 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ContentSizeWatcher.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ContentSizeWatcher.java @@ -8,5 +8,5 @@ package com.facebook.react.views.textinput; public interface ContentSizeWatcher { - public void onLayout(); + void onLayout(); } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManagerWrapper.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManagerWrapper.kt index 0a349409f760f9..69518a1524ba56 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManagerWrapper.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManagerWrapper.kt @@ -16,6 +16,9 @@ import com.facebook.react.uimanager.StateWrapper import com.facebook.react.uimanager.ThemedReactContext import com.facebook.react.uimanager.ViewManager +/** Temporary to help trace the cause of T151032868 */ +class ReactViewReturnTypeException(message: String, e: Throwable) : Exception(message, e) + interface ReactViewManagerWrapper { fun createView( reactTag: Int, @@ -51,9 +54,17 @@ interface ReactViewManagerWrapper { props: Any?, stateWrapper: StateWrapper?, jsResponderHandler: JSResponderHandler - ): View = - viewManager.createView( + ): View { + try { + return viewManager.createView( reactTag, reactContext, props as? ReactStylesDiffMap, stateWrapper, jsResponderHandler) + } catch (e: NullPointerException) { + // Throwing to try capture information about the cause of T151032868, remove after. + throw ReactViewReturnTypeException( + "DefaultViewManagerWrapper::createView(${viewManager.getName()}, ${viewManager::class.java}) can't return null", + e) + } + } override fun updateProperties(viewToUpdate: View, props: Any?) { viewManager.updateProperties(viewToUpdate, props as? ReactStylesDiffMap) diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaConfig.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaConfig.java index ec96a9636d9290..931313594b113f 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaConfig.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaConfig.java @@ -22,9 +22,19 @@ public abstract class YogaConfig { * Yoga previously had an error where containers would take the maximum space possible instead of the minimum * like they are supposed to. In practice this resulted in implicit behaviour similar to align-self: stretch; * Because this was such a long-standing bug we must allow legacy users to switch back to this behaviour. + * + * @deprecated "setUseLegacyStretchBehaviour" will be removed in the next release. Usage should be replaced with + * "setErrata(YogaErrata.ALL)" to opt out of all future breaking conformance fixes, or + * "setErrata(YogaErrata.STRETCH_FLEX_BASIS)" to opt out of the specific conformance fix previously disabled by + * "UseLegacyStretchBehaviour". */ + @Deprecated public abstract void setUseLegacyStretchBehaviour(boolean useLegacyStretchBehaviour); + public abstract void setErrata(YogaErrata errata); + + public abstract YogaErrata getErrata(); + public abstract void setLogger(YogaLogger logger); public abstract YogaLogger getLogger(); diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaConfigJNIBase.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaConfigJNIBase.java index 62a740ef6a8cdb..bbe526d7004971 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaConfigJNIBase.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaConfigJNIBase.java @@ -52,6 +52,14 @@ public void setUseLegacyStretchBehaviour(boolean useLegacyStretchBehaviour) { YogaNative.jni_YGConfigSetUseLegacyStretchBehaviourJNI(mNativePointer, useLegacyStretchBehaviour); } + public void setErrata(YogaErrata errata) { + YogaNative.jni_YGConfigSetErrataJNI(mNativePointer, errata.intValue()); + } + + public YogaErrata getErrata() { + return YogaErrata.fromInt(YogaNative.jni_YGConfigGetErrataJNI(mNativePointer)); + } + public void setLogger(YogaLogger logger) { mLogger = logger; YogaNative.jni_YGConfigSetLoggerJNI(mNativePointer, logger); diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaErrata.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaErrata.java new file mode 100644 index 00000000000000..6ae5ac0e7cbf08 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaErrata.java @@ -0,0 +1,37 @@ +/* + * 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. + */ + +// @generated by enums.py + +package com.facebook.yoga; + +public enum YogaErrata { + NONE(0), + STRETCH_FLEX_BASIS(1), + ALL(2147483647), + CLASSIC(2147483646); + + private final int mIntValue; + + YogaErrata(int intValue) { + mIntValue = intValue; + } + + public int intValue() { + return mIntValue; + } + + public static YogaErrata fromInt(int value) { + switch (value) { + case 0: return NONE; + case 1: return STRETCH_FLEX_BASIS; + case 2147483647: return ALL; + case 2147483646: return CLASSIC; + default: throw new IllegalArgumentException("Unknown enum value: " + value); + } + } +} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaNative.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaNative.java index 934602d840afd8..74f4a98cb473d6 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaNative.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaNative.java @@ -25,18 +25,20 @@ public class YogaNative { static native void jni_YGConfigSetPrintTreeFlagJNI(long nativePointer, boolean enable); static native void jni_YGConfigSetPointScaleFactorJNI(long nativePointer, float pixelsInPoint); static native void jni_YGConfigSetUseLegacyStretchBehaviourJNI(long nativePointer, boolean useLegacyStretchBehaviour); + static native void jni_YGConfigSetErrataJNI(long nativePointer, int errata); + static native int jni_YGConfigGetErrataJNI(long nativePointer); static native void jni_YGConfigSetLoggerJNI(long nativePointer, YogaLogger logger); // YGNode related static native long jni_YGNodeNewJNI(); static native long jni_YGNodeNewWithConfigJNI(long configPointer); - static native void jni_YGNodeFreeJNI(long nativePointer); + static native void jni_YGNodeDeallocateJNI(long nativePointer); static native void jni_YGNodeResetJNI(long nativePointer); static native void jni_YGNodeInsertChildJNI(long nativePointer, long childPointer, int index); static native void jni_YGNodeSwapChildJNI(long nativePointer, long childPointer, int index); static native void jni_YGNodeSetIsReferenceBaselineJNI(long nativePointer, boolean isReferenceBaseline); static native boolean jni_YGNodeIsReferenceBaselineJNI(long nativePointer); - static native void jni_YGNodeClearChildrenJNI(long nativePointer); + static native void jni_YGNodeRemoveAllChildrenJNI(long nativePointer); static native void jni_YGNodeRemoveChildJNI(long nativePointer, long childPointer); static native void jni_YGNodeCalculateLayoutJNI(long nativePointer, float width, float height, long[] nativePointers, YogaNodeJNIBase[] nodes); static native void jni_YGNodeMarkDirtyJNI(long nativePointer); diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaNodeJNIBase.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaNodeJNIBase.java index 2420d999181b36..9100e64c817b44 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaNodeJNIBase.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaNodeJNIBase.java @@ -155,7 +155,7 @@ public YogaNodeJNIBase cloneWithoutChildren() { private void clearChildren() { mChildren = null; - YogaNative.jni_YGNodeClearChildrenJNI(mNativePointer); + YogaNative.jni_YGNodeRemoveAllChildrenJNI(mNativePointer); } public YogaNodeJNIBase removeChildAt(int i) { diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaNodeJNIFinalizer.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaNodeJNIFinalizer.java index 424006e978d8d3..ab617c7f16ff6c 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaNodeJNIFinalizer.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaNodeJNIFinalizer.java @@ -29,7 +29,7 @@ public void freeNatives() { if (mNativePointer != 0) { long nativePointer = mNativePointer; mNativePointer = 0; - YogaNative.jni_YGNodeFreeJNI(nativePointer); + YogaNative.jni_YGNodeDeallocateJNI(nativePointer); } } } diff --git a/packages/react-native/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJNI.h b/packages/react-native/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJNI.h index 69f11392d3fd4c..13950445a7b0ca 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJNI.h +++ b/packages/react-native/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJNI.h @@ -5,6 +5,8 @@ * LICENSE file in the root directory of this source tree. */ +#include + const short int LAYOUT_EDGE_SET_FLAG_INDEX = 0; const short int LAYOUT_WIDTH_INDEX = 1; const short int LAYOUT_HEIGHT_INDEX = 2; @@ -36,14 +38,14 @@ class YGNodeEdges { YGNodeEdges(YGNodeRef node) { auto context = YGNodeContext{}; - context.asVoidPtr = node->getContext(); + context.asVoidPtr = YGNodeGetContext(node); edges_ = context.edgesSet; } void setOn(YGNodeRef node) { auto context = YGNodeContext{}; context.edgesSet = edges_; - node->setContext(context.asVoidPtr); + YGNodeSetContext(node, context.asVoidPtr); } bool has(Edge edge) { return (edges_ & edge) == edge; } diff --git a/packages/react-native/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJNIVanilla.cpp b/packages/react-native/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJNIVanilla.cpp index b6ef83be909934..0a95d991976a8b 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJNIVanilla.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJNIVanilla.cpp @@ -7,18 +7,19 @@ #include "jni.h" #include "YGJNIVanilla.h" -#include #include #include "YGJNI.h" #include "common.h" #include "YGJTypesVanilla.h" -#include #include #include #include "YogaJniException.h" +// TODO: Reconcile missing layoutContext functionality from callbacks in the C +// API and use that +#include + using namespace facebook::yoga::vanillajni; -using facebook::yoga::detail::Log; static inline ScopedLocalRef YGNodeJobject( YGNodeRef node, @@ -34,11 +35,14 @@ static inline YGConfigRef _jlong2YGConfigRef(jlong addr) { return reinterpret_cast(static_cast(addr)); } -static jlong jni_YGConfigNewJNI(JNIEnv* env, jobject obj) { +static jlong jni_YGConfigNewJNI(JNIEnv* /*env*/, jobject /*obj*/) { return reinterpret_cast(YGConfigNew()); } -static void jni_YGConfigFreeJNI(JNIEnv* env, jobject obj, jlong nativePointer) { +static void jni_YGConfigFreeJNI( + JNIEnv* /*env*/, + jobject /*obj*/, + jlong nativePointer) { const YGConfigRef config = _jlong2YGConfigRef(nativePointer); // unique_ptr will destruct the underlying global_ref, if present. auto context = std::unique_ptr>{ @@ -47,8 +51,8 @@ static void jni_YGConfigFreeJNI(JNIEnv* env, jobject obj, jlong nativePointer) { } static void jni_YGConfigSetExperimentalFeatureEnabledJNI( - JNIEnv* env, - jobject obj, + JNIEnv* /*env*/, + jobject /*obj*/, jlong nativePointer, jint feature, jboolean enabled) { @@ -58,8 +62,8 @@ static void jni_YGConfigSetExperimentalFeatureEnabledJNI( } static void jni_YGConfigSetUseWebDefaultsJNI( - JNIEnv* env, - jobject obj, + JNIEnv* /*env*/, + jobject /*obj*/, jlong nativePointer, jboolean useWebDefaults) { const YGConfigRef config = _jlong2YGConfigRef(nativePointer); @@ -67,8 +71,8 @@ static void jni_YGConfigSetUseWebDefaultsJNI( } static void jni_YGConfigSetPrintTreeFlagJNI( - JNIEnv* env, - jobject obj, + JNIEnv* /*env*/, + jobject /*obj*/, jlong nativePointer, jboolean enable) { const YGConfigRef config = _jlong2YGConfigRef(nativePointer); @@ -76,56 +80,63 @@ static void jni_YGConfigSetPrintTreeFlagJNI( } static void jni_YGConfigSetPointScaleFactorJNI( - JNIEnv* env, - jobject obj, + JNIEnv* /*env*/, + jobject /*obj*/, jlong nativePointer, jfloat pixelsInPoint) { const YGConfigRef config = _jlong2YGConfigRef(nativePointer); YGConfigSetPointScaleFactor(config, pixelsInPoint); } -static void YGPrint(YGNodeRef node, void* layoutContext) { - if (auto obj = YGNodeJobject(node, layoutContext)) { - // TODO cout << obj.get()->toString() << endl; - } else { - Log::log( - node, - YGLogLevelError, - nullptr, - "Java YGNode was GCed during layout calculation\n"); - } -} - static void jni_YGConfigSetUseLegacyStretchBehaviourJNI( - JNIEnv* env, - jobject obj, + JNIEnv* /*env*/, + jobject /*obj*/, jlong nativePointer, jboolean useLegacyStretchBehaviour) { const YGConfigRef config = _jlong2YGConfigRef(nativePointer); +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated" YGConfigSetUseLegacyStretchBehaviour(config, useLegacyStretchBehaviour); +#pragma clang diagnostic pop +} + +static void jni_YGConfigSetErrataJNI( + JNIEnv* /*env*/, + jobject /*obj*/, + jlong nativePointer, + jint errata) { + const YGConfigRef config = _jlong2YGConfigRef(nativePointer); + YGConfigSetErrata(config, static_cast(errata)); +} + +static jint jni_YGConfigGetErrataJNI( + JNIEnv* /*env*/, + jobject /*obj*/, + jlong nativePointer) { + const YGConfigRef config = _jlong2YGConfigRef(nativePointer); + return static_cast(YGConfigGetErrata(config)); } -static jlong jni_YGNodeNewJNI(JNIEnv* env, jobject obj) { +static jlong jni_YGNodeNewJNI(JNIEnv* /*env*/, jobject /*obj*/) { const YGNodeRef node = YGNodeNew(); - node->setContext(YGNodeContext{}.asVoidPtr); - node->setPrintFunc(YGPrint); + YGNodeSetContext(node, YGNodeContext{}.asVoidPtr); return reinterpret_cast(node); } static jlong jni_YGNodeNewWithConfigJNI( - JNIEnv* env, - jobject obj, + JNIEnv* /*env*/, + jobject /*obj*/, jlong configPointer) { const YGNodeRef node = YGNodeNewWithConfig(_jlong2YGConfigRef(configPointer)); - node->setContext(YGNodeContext{}.asVoidPtr); + YGNodeSetContext(node, YGNodeContext{}.asVoidPtr); return reinterpret_cast(node); } static int YGJNILogFunc( const YGConfigRef config, - const YGNodeRef node, + const YGNodeRef /*node*/, YGLogLevel level, - void* layoutContext, + void* /*layoutContext*/, const char* format, va_list args) { int result = vsnprintf(NULL, 0, format, args); @@ -167,7 +178,7 @@ static int YGJNILogFunc( static void jni_YGConfigSetLoggerJNI( JNIEnv* env, - jobject obj, + jobject /*obj*/, jlong nativePointer, jobject logger) { const YGConfigRef config = _jlong2YGConfigRef(nativePointer); @@ -191,24 +202,30 @@ static void jni_YGConfigSetLoggerJNI( } } -static void jni_YGNodeFreeJNI(JNIEnv* env, jobject obj, jlong nativePointer) { +static void jni_YGNodeDeallocateJNI( + JNIEnv* /*env*/, + jobject /*obj*/, + jlong nativePointer) { if (nativePointer == 0) { return; } const YGNodeRef node = _jlong2YGNodeRef(nativePointer); - YGNodeFree(node); + YGNodeDeallocate(node); } -static void jni_YGNodeResetJNI(JNIEnv* env, jobject obj, jlong nativePointer) { +static void jni_YGNodeResetJNI( + JNIEnv* /*env*/, + jobject /*obj*/, + jlong nativePointer) { const YGNodeRef node = _jlong2YGNodeRef(nativePointer); - void* context = node->getContext(); + void* context = YGNodeGetContext(node); YGNodeReset(node); - node->setContext(context); + YGNodeSetContext(node, context); } static void jni_YGNodeInsertChildJNI( - JNIEnv* env, - jobject obj, + JNIEnv* /*env*/, + jobject /*obj*/, jlong nativePointer, jlong childPointer, jint index) { @@ -217,8 +234,8 @@ static void jni_YGNodeInsertChildJNI( } static void jni_YGNodeSwapChildJNI( - JNIEnv* env, - jobject obj, + JNIEnv* /*env*/, + jobject /*obj*/, jlong nativePointer, jlong childPointer, jint index) { @@ -227,8 +244,8 @@ static void jni_YGNodeSwapChildJNI( } static void jni_YGNodeSetIsReferenceBaselineJNI( - JNIEnv* env, - jobject obj, + JNIEnv* /*env*/, + jobject /*obj*/, jlong nativePointer, jboolean isReferenceBaseline) { YGNodeSetIsReferenceBaseline( @@ -236,23 +253,23 @@ static void jni_YGNodeSetIsReferenceBaselineJNI( } static jboolean jni_YGNodeIsReferenceBaselineJNI( - JNIEnv* env, - jobject obj, + JNIEnv* /*env*/, + jobject /*obj*/, jlong nativePointer) { return YGNodeIsReferenceBaseline(_jlong2YGNodeRef(nativePointer)); } -static void jni_YGNodeClearChildrenJNI( - JNIEnv* env, - jobject obj, +static void jni_YGNodeRemoveAllChildrenJNI( + JNIEnv* /*env*/, + jobject /*obj*/, jlong nativePointer) { const YGNodeRef node = _jlong2YGNodeRef(nativePointer); - node->clearChildren(); + YGNodeRemoveAllChildren(node); } static void jni_YGNodeRemoveChildJNI( - JNIEnv* env, - jobject obj, + JNIEnv* /*env*/, + jobject /*obj*/, jlong nativePointer, jlong childPointer) { YGNodeRemoveChild( @@ -264,16 +281,11 @@ static void YGTransferLayoutOutputsRecursive( jobject thiz, YGNodeRef root, void* layoutContext) { - if (!root->getHasNewLayout()) { + if (!YGNodeGetHasNewLayout(root)) { return; } auto obj = YGNodeJobject(root, layoutContext); if (!obj) { - Log::log( - root, - YGLogLevelError, - nullptr, - "Java YGNode was GCed during layout calculation\n"); return; } @@ -334,7 +346,7 @@ static void YGTransferLayoutOutputsRecursive( env->SetFloatArrayRegion(arrFinal.get(), 0, arrSize, arr); env->SetObjectField(obj.get(), arrField, arrFinal.get()); - root->setHasNewLayout(false); + YGNodeSetHasNewLayout(root, false); for (uint32_t i = 0; i < YGNodeGetChildCount(root); i++) { YGTransferLayoutOutputsRecursive( @@ -383,102 +395,102 @@ static void jni_YGNodeCalculateLayoutJNI( } static void jni_YGNodeMarkDirtyJNI( - JNIEnv* env, - jobject obj, + JNIEnv* /*env*/, + jobject /*obj*/, jlong nativePointer) { YGNodeMarkDirty(_jlong2YGNodeRef(nativePointer)); } static void jni_YGNodeMarkDirtyAndPropagateToDescendantsJNI( - JNIEnv* env, - jobject obj, + JNIEnv* /*env*/, + jobject /*obj*/, jlong nativePointer) { YGNodeMarkDirtyAndPropagateToDescendants(_jlong2YGNodeRef(nativePointer)); } static jboolean jni_YGNodeIsDirtyJNI( - JNIEnv* env, - jobject obj, + JNIEnv* /*env*/, + jobject /*obj*/, jlong nativePointer) { - return (jboolean) _jlong2YGNodeRef(nativePointer)->isDirty(); + return (jboolean) YGNodeIsDirty(_jlong2YGNodeRef(nativePointer)); } static void jni_YGNodeCopyStyleJNI( - JNIEnv* env, - jobject obj, + JNIEnv* /*env*/, + jobject /*obj*/, jlong dstNativePointer, jlong srcNativePointer) { YGNodeCopyStyle( _jlong2YGNodeRef(dstNativePointer), _jlong2YGNodeRef(srcNativePointer)); } -#define YG_NODE_JNI_STYLE_PROP(javatype, type, name) \ - static javatype jni_YGNodeStyleGet##name##JNI( \ - JNIEnv* env, jobject obj, jlong nativePointer) { \ - return (javatype) YGNodeStyleGet##name(_jlong2YGNodeRef(nativePointer)); \ +#define YG_NODE_JNI_STYLE_PROP(javatype, type, name) \ + static javatype jni_YGNodeStyleGet##name##JNI( \ + JNIEnv* /*env*/, jobject /*obj*/, jlong nativePointer) { \ + return (javatype) YGNodeStyleGet##name(_jlong2YGNodeRef(nativePointer)); \ + } \ + \ + static void jni_YGNodeStyleSet##name##JNI( \ + JNIEnv* /*env*/, jobject /*obj*/, jlong nativePointer, javatype value) { \ + YGNodeStyleSet##name( \ + _jlong2YGNodeRef(nativePointer), static_cast(value)); \ + } + +#define YG_NODE_JNI_STYLE_UNIT_PROP(name) \ + static jlong jni_YGNodeStyleGet##name##JNI( \ + JNIEnv* /*env*/, jobject /*obj*/, jlong nativePointer) { \ + return YogaValue::asJavaLong( \ + YGNodeStyleGet##name(_jlong2YGNodeRef(nativePointer))); \ } \ \ static void jni_YGNodeStyleSet##name##JNI( \ - JNIEnv* env, jobject obj, jlong nativePointer, javatype value) { \ + JNIEnv* /*env*/, jobject /*obj*/, jlong nativePointer, jfloat value) { \ YGNodeStyleSet##name( \ - _jlong2YGNodeRef(nativePointer), static_cast(value)); \ - } - -#define YG_NODE_JNI_STYLE_UNIT_PROP(name) \ - static jlong jni_YGNodeStyleGet##name##JNI( \ - JNIEnv* env, jobject obj, jlong nativePointer) { \ - return YogaValue::asJavaLong( \ - YGNodeStyleGet##name(_jlong2YGNodeRef(nativePointer))); \ - } \ - \ - static void jni_YGNodeStyleSet##name##JNI( \ - JNIEnv* env, jobject obj, jlong nativePointer, jfloat value) { \ - YGNodeStyleSet##name( \ - _jlong2YGNodeRef(nativePointer), static_cast(value)); \ - } \ - \ - static void jni_YGNodeStyleSet##name##PercentJNI( \ - JNIEnv* env, jobject obj, jlong nativePointer, jfloat value) { \ - YGNodeStyleSet##name##Percent( \ - _jlong2YGNodeRef(nativePointer), static_cast(value)); \ + _jlong2YGNodeRef(nativePointer), static_cast(value)); \ + } \ + \ + static void jni_YGNodeStyleSet##name##PercentJNI( \ + JNIEnv* /*env*/, jobject /*obj*/, jlong nativePointer, jfloat value) { \ + YGNodeStyleSet##name##Percent( \ + _jlong2YGNodeRef(nativePointer), static_cast(value)); \ } #define YG_NODE_JNI_STYLE_UNIT_PROP_AUTO(name) \ YG_NODE_JNI_STYLE_UNIT_PROP(name) \ static void jni_YGNodeStyleSet##name##AutoJNI( \ - JNIEnv* env, jobject obj, jlong nativePointer) { \ + JNIEnv* /*env*/, jobject /*obj*/, jlong nativePointer) { \ YGNodeStyleSet##name##Auto(_jlong2YGNodeRef(nativePointer)); \ } -#define YG_NODE_JNI_STYLE_EDGE_UNIT_PROP(name) \ - static jlong jni_YGNodeStyleGet##name##JNI( \ - JNIEnv* env, jobject obj, jlong nativePointer, jint edge) { \ - return YogaValue::asJavaLong(YGNodeStyleGet##name( \ - _jlong2YGNodeRef(nativePointer), static_cast(edge))); \ - } \ - \ - static void jni_YGNodeStyleSet##name##JNI( \ - JNIEnv* env, \ - jobject obj, \ - jlong nativePointer, \ - jint edge, \ - jfloat value) { \ - YGNodeStyleSet##name( \ - _jlong2YGNodeRef(nativePointer), \ - static_cast(edge), \ - static_cast(value)); \ - } \ - \ - static void jni_YGNodeStyleSet##name##PercentJNI( \ - JNIEnv* env, \ - jobject obj, \ - jlong nativePointer, \ - jint edge, \ - jfloat value) { \ - YGNodeStyleSet##name##Percent( \ - _jlong2YGNodeRef(nativePointer), \ - static_cast(edge), \ - static_cast(value)); \ +#define YG_NODE_JNI_STYLE_EDGE_UNIT_PROP(name) \ + static jlong jni_YGNodeStyleGet##name##JNI( \ + JNIEnv* /*env*/, jobject /*obj*/, jlong nativePointer, jint edge) { \ + return YogaValue::asJavaLong(YGNodeStyleGet##name( \ + _jlong2YGNodeRef(nativePointer), static_cast(edge))); \ + } \ + \ + static void jni_YGNodeStyleSet##name##JNI( \ + JNIEnv* /*env*/, \ + jobject /*obj*/, \ + jlong nativePointer, \ + jint edge, \ + jfloat value) { \ + YGNodeStyleSet##name( \ + _jlong2YGNodeRef(nativePointer), \ + static_cast(edge), \ + static_cast(value)); \ + } \ + \ + static void jni_YGNodeStyleSet##name##PercentJNI( \ + JNIEnv* /*env*/, \ + jobject /*obj*/, \ + jlong nativePointer, \ + jint edge, \ + jfloat value) { \ + YGNodeStyleSet##name##Percent( \ + _jlong2YGNodeRef(nativePointer), \ + static_cast(edge), \ + static_cast(value)); \ } YG_NODE_JNI_STYLE_PROP(jint, YGDirection, Direction); @@ -506,8 +518,8 @@ YG_NODE_JNI_STYLE_UNIT_PROP(MaxHeight); YG_NODE_JNI_STYLE_EDGE_UNIT_PROP(Position); static jlong jni_YGNodeStyleGetMarginJNI( - JNIEnv* env, - jobject obj, + JNIEnv* /*env*/, + jobject /*obj*/, jlong nativePointer, jint edge) { YGNodeRef yogaNodeRef = _jlong2YGNodeRef(nativePointer); @@ -519,8 +531,8 @@ static jlong jni_YGNodeStyleGetMarginJNI( } static void jni_YGNodeStyleSetMarginJNI( - JNIEnv* env, - jobject obj, + JNIEnv* /*env*/, + jobject /*obj*/, jlong nativePointer, jint edge, jfloat margin) { @@ -531,8 +543,8 @@ static void jni_YGNodeStyleSetMarginJNI( } static void jni_YGNodeStyleSetMarginPercentJNI( - JNIEnv* env, - jobject obj, + JNIEnv* /*env*/, + jobject /*obj*/, jlong nativePointer, jint edge, jfloat percent) { @@ -543,8 +555,8 @@ static void jni_YGNodeStyleSetMarginPercentJNI( } static void jni_YGNodeStyleSetMarginAutoJNI( - JNIEnv* env, - jobject obj, + JNIEnv* /*env*/, + jobject /*obj*/, jlong nativePointer, jint edge) { YGNodeRef yogaNodeRef = _jlong2YGNodeRef(nativePointer); @@ -553,8 +565,8 @@ static void jni_YGNodeStyleSetMarginAutoJNI( } static jlong jni_YGNodeStyleGetPaddingJNI( - JNIEnv* env, - jobject obj, + JNIEnv* /*env*/, + jobject /*obj*/, jlong nativePointer, jint edge) { YGNodeRef yogaNodeRef = _jlong2YGNodeRef(nativePointer); @@ -566,8 +578,8 @@ static jlong jni_YGNodeStyleGetPaddingJNI( } static void jni_YGNodeStyleSetPaddingJNI( - JNIEnv* env, - jobject obj, + JNIEnv* /*env*/, + jobject /*obj*/, jlong nativePointer, jint edge, jfloat padding) { @@ -578,8 +590,8 @@ static void jni_YGNodeStyleSetPaddingJNI( } static void jni_YGNodeStyleSetPaddingPercentJNI( - JNIEnv* env, - jobject obj, + JNIEnv* /*env*/, + jobject /*obj*/, jlong nativePointer, jint edge, jfloat percent) { @@ -590,8 +602,8 @@ static void jni_YGNodeStyleSetPaddingPercentJNI( } static jfloat jni_YGNodeStyleGetBorderJNI( - JNIEnv* env, - jobject obj, + JNIEnv* /*env*/, + jobject /*obj*/, jlong nativePointer, jint edge) { YGNodeRef yogaNodeRef = _jlong2YGNodeRef(nativePointer); @@ -602,8 +614,8 @@ static jfloat jni_YGNodeStyleGetBorderJNI( } static void jni_YGNodeStyleSetBorderJNI( - JNIEnv* env, - jobject obj, + JNIEnv* /*env*/, + jobject /*obj*/, jlong nativePointer, jint edge, jfloat border) { @@ -657,11 +669,6 @@ static YGSize YGJNIMeasureFunc( return YGSize{*measuredWidth, *measuredHeight}; } else { - Log::log( - node, - YGLogLevelError, - nullptr, - "Java YGNode was GCed during layout calculation\n"); return YGSize{ widthMode == YGMeasureModeUndefined ? 0 : width, heightMode == YGMeasureModeUndefined ? 0 : height, @@ -670,8 +677,8 @@ static YGSize YGJNIMeasureFunc( } static void jni_YGNodeSetHasMeasureFuncJNI( - JNIEnv* env, - jobject obj, + JNIEnv* /*env*/, + jobject /*obj*/, jlong nativePointer, jboolean hasMeasureFunc) { _jlong2YGNodeRef(nativePointer) @@ -697,34 +704,42 @@ static float YGJNIBaselineFunc( } static void jni_YGNodeSetHasBaselineFuncJNI( - JNIEnv* env, - jobject obj, + JNIEnv* /*env*/, + jobject /*obj*/, jlong nativePointer, jboolean hasBaselineFunc) { _jlong2YGNodeRef(nativePointer) ->setBaselineFunc(hasBaselineFunc ? YGJNIBaselineFunc : nullptr); } -static void jni_YGNodePrintJNI(JNIEnv* env, jobject obj, jlong nativePointer) { +static void jni_YGNodePrintJNI( + JNIEnv* /*env*/, + jobject /*obj*/, + jlong nativePointer) { #ifdef DEBUG const YGNodeRef node = _jlong2YGNodeRef(nativePointer); YGNodePrint( node, (YGPrintOptions) (YGPrintOptionsStyle | YGPrintOptionsLayout | YGPrintOptionsChildren)); +#else + (void) nativePointer; #endif } -static jlong jni_YGNodeCloneJNI(JNIEnv* env, jobject obj, jlong nativePointer) { +static jlong jni_YGNodeCloneJNI( + JNIEnv* /*env*/, + jobject /*obj*/, + jlong nativePointer) { auto node = _jlong2YGNodeRef(nativePointer); const YGNodeRef clonedYogaNode = YGNodeClone(node); - clonedYogaNode->setContext(node->getContext()); + YGNodeSetContext(clonedYogaNode, YGNodeGetContext(node)); return reinterpret_cast(clonedYogaNode); } static jfloat jni_YGNodeStyleGetGapJNI( - JNIEnv* env, - jobject obj, + JNIEnv* /*env*/, + jobject /*obj*/, jlong nativePointer, jint gutter) { return (jfloat) YGNodeStyleGetGap( @@ -732,8 +747,8 @@ static jfloat jni_YGNodeStyleGetGapJNI( } static void jni_YGNodeStyleSetGapJNI( - JNIEnv* env, - jobject obj, + JNIEnv* /*env*/, + jobject /*obj*/, jlong nativePointer, jint gutter, jfloat gapLength) { @@ -764,12 +779,14 @@ static JNINativeMethod methods[] = { {"jni_YGConfigSetUseLegacyStretchBehaviourJNI", "(JZ)V", (void*) jni_YGConfigSetUseLegacyStretchBehaviourJNI}, + {"jni_YGConfigSetErrataJNI", "(JI)V", (void*) jni_YGConfigSetErrataJNI}, + {"jni_YGConfigGetErrataJNI", "(J)I", (void*) jni_YGConfigGetErrataJNI}, {"jni_YGConfigSetLoggerJNI", "(JLcom/facebook/yoga/YogaLogger;)V", (void*) jni_YGConfigSetLoggerJNI}, {"jni_YGNodeNewJNI", "()J", (void*) jni_YGNodeNewJNI}, {"jni_YGNodeNewWithConfigJNI", "(J)J", (void*) jni_YGNodeNewWithConfigJNI}, - {"jni_YGNodeFreeJNI", "(J)V", (void*) jni_YGNodeFreeJNI}, + {"jni_YGNodeDeallocateJNI", "(J)V", (void*) jni_YGNodeDeallocateJNI}, {"jni_YGNodeResetJNI", "(J)V", (void*) jni_YGNodeResetJNI}, {"jni_YGNodeInsertChildJNI", "(JJI)V", (void*) jni_YGNodeInsertChildJNI}, {"jni_YGNodeSwapChildJNI", "(JJI)V", (void*) jni_YGNodeSwapChildJNI}, @@ -779,7 +796,9 @@ static JNINativeMethod methods[] = { {"jni_YGNodeIsReferenceBaselineJNI", "(J)Z", (void*) jni_YGNodeIsReferenceBaselineJNI}, - {"jni_YGNodeClearChildrenJNI", "(J)V", (void*) jni_YGNodeClearChildrenJNI}, + {"jni_YGNodeRemoveAllChildrenJNI", + "(J)V", + (void*) jni_YGNodeRemoveAllChildrenJNI}, {"jni_YGNodeRemoveChildJNI", "(JJ)V", (void*) jni_YGNodeRemoveChildJNI}, {"jni_YGNodeCalculateLayoutJNI", "(JFF[J[Lcom/facebook/yoga/YogaNodeJNIBase;)V", diff --git a/packages/react-native/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJTypesVanilla.h b/packages/react-native/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJTypesVanilla.h index 1b4d62dfae49fc..506c304909a37c 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJTypesVanilla.h +++ b/packages/react-native/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJTypesVanilla.h @@ -5,11 +5,13 @@ * LICENSE file in the root directory of this source tree. */ -#include "jni.h" -#include -#include #include +#include + +#include + #include "common.h" +#include "jni.h" class PtrJNodeMapVanilla { std::map ptrsToIdxs_; diff --git a/packages/react-native/ReactAndroid/src/main/jni/first-party/yogajni/jni/corefunctions.cpp b/packages/react-native/ReactAndroid/src/main/jni/first-party/yogajni/jni/corefunctions.cpp index 1f8c3f75c66ed0..bbdcebd323df77 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/first-party/yogajni/jni/corefunctions.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/first-party/yogajni/jni/corefunctions.cpp @@ -56,6 +56,7 @@ JNIEXPORT JNIEnv* getCurrentEnv() { } void logErrorMessageAndDie(const char* message) { + (void) message; VANILLAJNI_LOG_ERROR( "VanillaJni", "Aborting due to error detected in native code: %s", diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/hermes/jni/JHermesInstance.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/hermes/jni/JHermesInstance.cpp index e60ef0f74c3fae..4c04821a75e5c6 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/hermes/jni/JHermesInstance.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/hermes/jni/JHermesInstance.cpp @@ -9,8 +9,7 @@ #include -namespace facebook { -namespace react { +namespace facebook::react { jni::local_ref JHermesInstance::initHybrid( jni::alias_ref) { @@ -28,5 +27,4 @@ std::unique_ptr JHermesInstance::createJSRuntime() noexcept { return HermesInstance::createJSRuntime(); } -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/hermes/jni/JHermesInstance.h b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/hermes/jni/JHermesInstance.h index 13a427057bce82..117556998971d0 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/hermes/jni/JHermesInstance.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/hermes/jni/JHermesInstance.h @@ -17,8 +17,7 @@ #include #include "../../jni/JJSEngineInstance.h" -namespace facebook { -namespace react { +namespace facebook::react { class JHermesInstance : public jni::HybridClass { @@ -38,5 +37,4 @@ class JHermesInstance friend HybridBase; }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JJSEngineInstance.h b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JJSEngineInstance.h index ee166fb6b17e35..ba4d66cfea0c99 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JJSEngineInstance.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JJSEngineInstance.h @@ -11,9 +11,7 @@ #include #include -namespace facebook { - -namespace react { +namespace facebook::react { class JJSEngineInstance : public jni::HybridClass, public JSEngineInstance { @@ -25,5 +23,4 @@ class JJSEngineInstance : public jni::HybridClass, friend HybridBase; }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JJSTimerExecutor.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JJSTimerExecutor.cpp index 60a1ad64462ec9..ebd93d2d49b9fe 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JJSTimerExecutor.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JJSTimerExecutor.cpp @@ -10,8 +10,7 @@ #include #include -namespace facebook { -namespace react { +namespace facebook::react { void JJSTimerExecutor::setTimerManager( std::weak_ptr timerManager) { @@ -33,5 +32,4 @@ void JJSTimerExecutor::registerNatives() { }); } -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JJSTimerExecutor.h b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JJSTimerExecutor.h index d5a9904c9fe1b8..3da6a77b1f8217 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JJSTimerExecutor.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JJSTimerExecutor.h @@ -13,8 +13,7 @@ #include #include -namespace facebook { -namespace react { +namespace facebook::react { class JJSTimerExecutor : public jni::HybridClass { public: @@ -35,5 +34,4 @@ class JJSTimerExecutor : public jni::HybridClass { std::weak_ptr timerManager_; }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JJavaTimerManager.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JJavaTimerManager.cpp index 36276e5d2a9380..638f664cc782ce 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JJavaTimerManager.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JJavaTimerManager.cpp @@ -10,8 +10,7 @@ #include #include -namespace facebook { -namespace react { +namespace facebook::react { void JJavaTimerManager::createTimer( uint32_t timerID, @@ -28,5 +27,4 @@ void JJavaTimerManager::deleteTimer(uint32_t timerID) { method(self(), timerID); } -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JJavaTimerManager.h b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JJavaTimerManager.h index 3e39f04879a46a..d44cec367fc795 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JJavaTimerManager.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JJavaTimerManager.h @@ -12,8 +12,7 @@ #include #include -namespace facebook { -namespace react { +namespace facebook::react { struct JJavaTimerManager : jni::JavaClass { static auto constexpr kJavaDescriptor = @@ -24,5 +23,4 @@ struct JJavaTimerManager : jni::JavaClass { void deleteTimer(uint32_t timerID); }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JReactExceptionManager.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JReactExceptionManager.cpp index 2a8cbde9d12141..a8968d77bcc1aa 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JReactExceptionManager.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JReactExceptionManager.cpp @@ -11,8 +11,7 @@ #include #include -namespace facebook { -namespace react { +namespace facebook::react { void JReactExceptionManager::reportJsException( const JReadableMapBuffer::javaobject errorMapBuffer) { @@ -24,5 +23,4 @@ void JReactExceptionManager::reportJsException( } } -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JReactExceptionManager.h b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JReactExceptionManager.h index 7f16ec9ca7e30f..23b4ea46b900a4 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JReactExceptionManager.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JReactExceptionManager.h @@ -11,8 +11,7 @@ #include #include -namespace facebook { -namespace react { +namespace facebook::react { class JReactExceptionManager : public facebook::jni::JavaClass { @@ -23,5 +22,4 @@ class JReactExceptionManager void reportJsException(const JReadableMapBuffer::javaobject errorMapBuffer); }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JReactInstance.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JReactInstance.cpp index 2d1837ac9df550..d5ce7517657ac5 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JReactInstance.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JReactInstance.cpp @@ -26,8 +26,7 @@ #include #include "JavaTimerRegistry.h" -namespace facebook { -namespace react { +namespace facebook::react { JReactInstance::JReactInstance( jni::alias_ref jsEngineInstance, @@ -232,5 +231,4 @@ void JReactInstance::registerNatives() { }); } -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JReactInstance.h b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JReactInstance.h index 6604af59955b3b..61dfa4debee201 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JReactInstance.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JReactInstance.h @@ -27,8 +27,7 @@ #include "JJavaTimerManager.h" #include "JReactExceptionManager.h" -namespace facebook { -namespace react { +namespace facebook::react { class JReactInstance : public jni::HybridClass { public: @@ -105,5 +104,4 @@ class JReactInstance : public jni::HybridClass { jni::global_ref jBindingsInstaller_; }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JavaTimerRegistry.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JavaTimerRegistry.cpp index 3cbff64a6e9a49..842cade5af292f 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JavaTimerRegistry.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JavaTimerRegistry.cpp @@ -7,8 +7,7 @@ #include "JavaTimerRegistry.h" -namespace facebook { -namespace react { +namespace facebook::react { JavaTimerRegistry::JavaTimerRegistry( jni::global_ref javaTimerManager) @@ -26,5 +25,4 @@ void JavaTimerRegistry::deleteTimer(uint32_t timerID) { javaTimerManager_->deleteTimer(timerID); } -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JavaTimerRegistry.h b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JavaTimerRegistry.h index dbfd43bde72372..ae89a5296f8b5f 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JavaTimerRegistry.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JavaTimerRegistry.h @@ -14,8 +14,7 @@ #include "JJavaTimerManager.h" -namespace facebook { -namespace react { +namespace facebook::react { /** * Call into JavaTimerManager.java to schedule and delete timers @@ -36,5 +35,4 @@ class JavaTimerRegistry : public PlatformTimerRegistry { jni::global_ref javaTimerManager_; }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/Binding.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/Binding.cpp index 1a9743187a31cd..e8139b5380fe01 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/Binding.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/Binding.cpp @@ -37,8 +37,7 @@ #include #include -namespace facebook { -namespace react { +namespace facebook::react { jni::local_ref Binding::initHybrid( jni::alias_ref) { @@ -422,8 +421,6 @@ void Binding::installFabricUIManager( "CalculateTransformedFramesEnabled", getFeatureFlagValue("calculateTransformedFramesEnabled")); - CoreFeatures::cacheLastTextMeasurement = - getFeatureFlagValue("enableTextMeasureCachePerShadowNode"); CoreFeatures::enablePropIteratorSetter = getFeatureFlagValue("enableCppPropsIteratorSetter"); CoreFeatures::useNativeState = getFeatureFlagValue("useNativeState"); @@ -486,7 +483,12 @@ void Binding::schedulerDidFinishTransaction( if (!mountingManager) { return; } - mountingManager->executeMount(mountingCoordinator); + + auto mountingTransaction = mountingCoordinator->pullTransaction(); + if (!mountingTransaction.has_value()) { + return; + } + mountingManager->executeMount(*mountingTransaction); } void Binding::schedulerDidRequestPreliminaryViewAllocation( @@ -586,5 +588,4 @@ void Binding::registerNatives() { }); } -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/Binding.h b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/Binding.h index d3ba4dd4dd7f70..a1f443b1bcaa5b 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/Binding.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/Binding.h @@ -22,8 +22,7 @@ #include "EventEmitterWrapper.h" #include "JFabricUIManager.h" -namespace facebook { -namespace react { +namespace facebook::react { class ComponentFactory; class EventBeatManager; @@ -151,5 +150,4 @@ class Binding : public jni::HybridClass, bool enableFabricLogs_{false}; }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/ComponentFactory.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/ComponentFactory.cpp index 77425a03549f70..e7ecc79aba21a1 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/ComponentFactory.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/ComponentFactory.cpp @@ -13,8 +13,7 @@ using namespace facebook::jsi; -namespace facebook { -namespace react { +namespace facebook::react { jni::local_ref ComponentFactory::initHybrid( jni::alias_ref) { @@ -27,5 +26,4 @@ void ComponentFactory::registerNatives() { }); } -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/ComponentFactory.h b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/ComponentFactory.h index ffbb3f7ba3aac7..b7ae67dd0e1d2a 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/ComponentFactory.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/ComponentFactory.h @@ -11,8 +11,7 @@ #include #include -namespace facebook { -namespace react { +namespace facebook::react { class Instance; @@ -29,5 +28,4 @@ class ComponentFactory : public jni::HybridClass { static jni::local_ref initHybrid(jni::alias_ref); }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/CoreComponentsRegistry.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/CoreComponentsRegistry.cpp index 933e9fed2a596e..b82a561a074c05 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/CoreComponentsRegistry.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/CoreComponentsRegistry.cpp @@ -24,8 +24,7 @@ #include #include -namespace facebook { -namespace react { +namespace facebook::react { CoreComponentsRegistry::CoreComponentsRegistry(ComponentFactory *delegate) : delegate_(delegate) {} @@ -109,5 +108,4 @@ void CoreComponentsRegistry::registerNatives() { }); } -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/CoreComponentsRegistry.h b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/CoreComponentsRegistry.h index 4821ee29f7339b..a9f24c9c003b32 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/CoreComponentsRegistry.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/CoreComponentsRegistry.h @@ -12,8 +12,7 @@ #include #include "ComponentFactory.h" -namespace facebook { -namespace react { +namespace facebook::react { class CoreComponentsRegistry : public facebook::jni::HybridClass { @@ -38,5 +37,4 @@ class CoreComponentsRegistry ComponentFactory *delegate); }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/EventBeatManager.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/EventBeatManager.cpp index 9e9e383792e809..eeafad82499da4 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/EventBeatManager.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/EventBeatManager.cpp @@ -9,8 +9,7 @@ #include using namespace facebook::jni; -namespace facebook { -namespace react { +namespace facebook::react { EventBeatManager::EventBeatManager( jni::alias_ref jhybridobject) @@ -48,5 +47,4 @@ void EventBeatManager::registerNatives() { }); } -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/EventBeatManager.h b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/EventBeatManager.h index 39b2607770886d..228e4e9bbba129 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/EventBeatManager.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/EventBeatManager.h @@ -14,8 +14,7 @@ #include #include -namespace facebook { -namespace react { +namespace facebook::react { class EventBeatManagerObserver { public: @@ -63,5 +62,4 @@ class EventBeatManager : public jni::HybridClass { jni::alias_ref jhybridobject); }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/EventEmitterWrapper.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/EventEmitterWrapper.cpp index 638cf9e2d92832..88e9f66d4be178 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/EventEmitterWrapper.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/EventEmitterWrapper.cpp @@ -10,8 +10,7 @@ using namespace facebook::jni; -namespace facebook { -namespace react { +namespace facebook::react { void EventEmitterWrapper::dispatchEvent( std::string eventName, @@ -51,5 +50,4 @@ void EventEmitterWrapper::registerNatives() { }); } -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/EventEmitterWrapper.h b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/EventEmitterWrapper.h index a3834ad9357bc0..977fd13bca8439 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/EventEmitterWrapper.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/EventEmitterWrapper.h @@ -11,8 +11,7 @@ #include #include -namespace facebook { -namespace react { +namespace facebook::react { class Instance; @@ -35,5 +34,4 @@ class EventEmitterWrapper : public jni::HybridClass { int customCoalesceKey); }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricMountingManager.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricMountingManager.cpp index dcf8106c140839..cde2d633044c45 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricMountingManager.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricMountingManager.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -26,8 +27,7 @@ #include #include -namespace facebook { -namespace react { +namespace facebook::react { constexpr static auto kReactFeatureFlagsJavaDescriptor = "com/facebook/react/config/ReactFeatureFlags"; @@ -118,8 +118,7 @@ static inline void computeBufferSizes( std::vector &cppUpdatePaddingMountItems, std::vector &cppUpdateLayoutMountItems, std::vector &cppUpdateOverflowInsetMountItems, - std::vector &cppUpdateEventEmitterMountItems, - ShadowViewMutationList &cppViewMutations) { + std::vector &cppUpdateEventEmitterMountItems) { CppMountItem::Type lastType = CppMountItem::Type::Undefined; int numSameType = 0; for (auto const &mountItem : cppCommonMountItems) { @@ -178,11 +177,6 @@ static inline void computeBufferSizes( cppDeleteMountItems.size(), batchMountItemIntsSize, batchMountItemObjectsSize); - - if (cppViewMutations.size() > 0) { - batchMountItemIntsSize++; - batchMountItemObjectsSize++; - } } static inline void writeIntBufferTypePreamble( @@ -258,24 +252,15 @@ jni::local_ref FabricMountingManager::getProps( } void FabricMountingManager::executeMount( - const MountingCoordinator::Shared &mountingCoordinator) { + const MountingTransaction &transaction) { std::lock_guard lock(commitMutex_); - - SystraceSection s( - "FabricUIManagerBinding::schedulerDidFinishTransactionIntBuffer"); auto finishTransactionStartTime = telemetryTimePointNow(); - auto mountingTransaction = mountingCoordinator->pullTransaction(); - - if (!mountingTransaction.has_value()) { - return; - } - auto env = jni::Environment::current(); - auto telemetry = mountingTransaction->getTelemetry(); - auto surfaceId = mountingTransaction->getSurfaceId(); - auto &mutations = mountingTransaction->getMutations(); + auto telemetry = transaction.getTelemetry(); + auto surfaceId = transaction.getSurfaceId(); + auto &mutations = transaction.getMutations(); auto revisionNumber = telemetry.getRevisionNumber(); @@ -287,7 +272,7 @@ void FabricMountingManager::executeMount( std::vector cppUpdateLayoutMountItems; std::vector cppUpdateOverflowInsetMountItems; std::vector cppUpdateEventEmitterMountItems; - auto cppViewMutations = ShadowViewMutationList(); + { std::lock_guard allocatedViewsLock(allocatedViewsMutex_); @@ -506,8 +491,7 @@ void FabricMountingManager::executeMount( cppUpdatePaddingMountItems, cppUpdateLayoutMountItems, cppUpdateOverflowInsetMountItems, - cppUpdateEventEmitterMountItems, - cppViewMutations); + cppUpdateEventEmitterMountItems); static auto createMountItemsIntBufferBatchContainer = JFabricUIManager::javaClassStatic() @@ -959,5 +943,4 @@ void FabricMountingManager::onAllAnimationsComplete() { allAnimationsCompleteJNI(javaUIManager_); } -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricMountingManager.h b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricMountingManager.h index 01248be957cbd1..a4386d3432e5b5 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricMountingManager.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricMountingManager.h @@ -12,12 +12,11 @@ #include #include #include -#include #include -namespace facebook { -namespace react { +namespace facebook::react { +class MountingTransaction; class ReactNativeConfig; struct ShadowView; @@ -33,7 +32,7 @@ class FabricMountingManager final { void preallocateShadowView(SurfaceId surfaceId, ShadowView const &shadowView); - void executeMount(const MountingCoordinator::Shared &mountingCoordinator); + void executeMount(const MountingTransaction &transaction); void dispatchCommand( ShadowView const &shadowView, @@ -68,5 +67,4 @@ class FabricMountingManager final { ShadowView const &newShadowView); }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/JBackgroundExecutor.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/JBackgroundExecutor.cpp index e6d4f641f5e1c4..43bb9ce15882b8 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/JBackgroundExecutor.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/JBackgroundExecutor.cpp @@ -10,8 +10,7 @@ #include #include -namespace facebook { -namespace react { +namespace facebook::react { using namespace facebook::jni; @@ -26,5 +25,4 @@ BackgroundExecutor JBackgroundExecutor::create(const std::string &name) { }; } -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/JBackgroundExecutor.h b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/JBackgroundExecutor.h index 50e37dacd18a85..337f9615c6e119 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/JBackgroundExecutor.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/JBackgroundExecutor.h @@ -10,8 +10,7 @@ #include #include -namespace facebook { -namespace react { +namespace facebook::react { class JBackgroundExecutor : public jni::JavaClass { public: @@ -21,5 +20,4 @@ class JBackgroundExecutor : public jni::JavaClass { static BackgroundExecutor create(const std::string &name); }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/MountItem.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/MountItem.cpp index 7e53343220f954..79046a0220a0b6 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/MountItem.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/MountItem.cpp @@ -7,8 +7,7 @@ #include "MountItem.h" -namespace facebook { -namespace react { +namespace facebook::react { CppMountItem CppMountItem::CreateMountItem(ShadowView const &shadowView) { return {CppMountItem::Type::Create, {}, {}, shadowView, -1}; @@ -62,5 +61,4 @@ CppMountItem CppMountItem::UpdateOverflowInsetMountItem( return {CppMountItem::Type::UpdateOverflowInset, {}, {}, shadowView, -1}; } -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/MountItem.h b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/MountItem.h index f2e82f7a23e892..893eefdf2966ef 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/MountItem.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/MountItem.h @@ -10,8 +10,7 @@ #include #include -namespace facebook { -namespace react { +namespace facebook::react { struct JMountItem : public jni::JavaClass { static constexpr auto kJavaDescriptor = @@ -84,5 +83,4 @@ struct CppMountItem final { int index = {}; }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/ReactNativeConfigHolder.h b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/ReactNativeConfigHolder.h index faf602a2f00581..d6a7903cc0500e 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/ReactNativeConfigHolder.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/ReactNativeConfigHolder.h @@ -12,8 +12,7 @@ #include #include -namespace facebook { -namespace react { +namespace facebook::react { /** * Implementation of ReactNativeConfig that wraps a FabricMobileConfig Java @@ -33,5 +32,4 @@ class ReactNativeConfigHolder : public ReactNativeConfig { jni::global_ref reactNativeConfig_; }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/StateWrapperImpl.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/StateWrapperImpl.cpp index e79d25f55dfa17..f7301907b5b3d5 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/StateWrapperImpl.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/StateWrapperImpl.cpp @@ -13,8 +13,7 @@ using namespace facebook::jni; -namespace facebook { -namespace react { +namespace facebook::react { /** * Called from Java constructor through the JNI. @@ -64,5 +63,4 @@ void StateWrapperImpl::registerNatives() { }); } -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/StateWrapperImpl.h b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/StateWrapperImpl.h index 92ec87e9bb2493..691a80d0642792 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/StateWrapperImpl.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/StateWrapperImpl.h @@ -12,8 +12,7 @@ #include #include -namespace facebook { -namespace react { +namespace facebook::react { class Instance; @@ -38,5 +37,4 @@ class StateWrapperImpl : public jni::HybridClass { static jni::local_ref initHybrid(jni::alias_ref); }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/SurfaceHandlerBinding.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/SurfaceHandlerBinding.cpp index 63559fe3bb929a..688db9052bf214 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/SurfaceHandlerBinding.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/SurfaceHandlerBinding.cpp @@ -8,8 +8,7 @@ #include "SurfaceHandlerBinding.h" #include -namespace facebook { -namespace react { +namespace facebook::react { SurfaceHandlerBinding::SurfaceHandlerBinding( SurfaceId surfaceId, @@ -113,5 +112,4 @@ void SurfaceHandlerBinding::registerNatives() { }); } -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/SurfaceHandlerBinding.h b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/SurfaceHandlerBinding.h index e067810a31a4c6..2fd2c812d9ef4d 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/SurfaceHandlerBinding.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/SurfaceHandlerBinding.h @@ -13,8 +13,7 @@ #include #include -namespace facebook { -namespace react { +namespace facebook::react { class SurfaceHandlerBinding : public jni::HybridClass { public: @@ -63,5 +62,4 @@ class SurfaceHandlerBinding : public jni::HybridClass { jni::alias_ref moduleName); }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/viewPropConversions.h b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/viewPropConversions.h index 1c05d7973fb8ec..19381f8d585a79 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/viewPropConversions.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/viewPropConversions.h @@ -16,8 +16,7 @@ #include -namespace facebook { -namespace react { +namespace facebook::react { namespace { static MapBuffer convertAccessibilityActions( @@ -219,5 +218,4 @@ MapBuffer convertTransform(Transform const &transform) { } } // namespace -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/hermes/reactexecutor/OnLoad.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/hermes/reactexecutor/OnLoad.cpp index d3182e95305f58..795a2ac7b9022e 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/hermes/reactexecutor/OnLoad.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/hermes/reactexecutor/OnLoad.cpp @@ -19,8 +19,7 @@ #include -namespace facebook { -namespace react { +namespace facebook::react { static void hermesFatalHandler(const std::string &reason) { LOG(ERROR) << "Hermes Fatal: " << reason << "\n"; @@ -110,8 +109,7 @@ class HermesExecutorHolder using HybridBase::HybridBase; }; -} // namespace react -} // namespace facebook +} // namespace facebook::react JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) { return facebook::jni::initialize( diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.cpp index e3345f038be28b..043d5afcfaeb84 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.cpp @@ -43,8 +43,7 @@ using namespace facebook::jni; -namespace facebook { -namespace react { +namespace facebook::react { namespace { @@ -418,5 +417,4 @@ CatalystInstanceImpl::getRuntimeScheduler() { return runtimeScheduler_; } -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.h b/packages/react-native/ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.h index cd242903faba8d..bc07691e331a68 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.h @@ -20,8 +20,7 @@ #include "JavaModuleWrapper.h" #include "ModuleRegistryBuilder.h" -namespace facebook { -namespace react { +namespace facebook::react { class Instance; class JavaScriptExecutorHolder; @@ -117,5 +116,4 @@ class CatalystInstanceImpl : public jni::HybridClass { jni::global_ref runtimeScheduler_; }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/jni/CxxModuleWrapper.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/jni/CxxModuleWrapper.cpp index f712545de7d316..aab1371be692a9 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/jni/CxxModuleWrapper.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/jni/CxxModuleWrapper.cpp @@ -16,8 +16,7 @@ using namespace facebook::jni; using namespace facebook::xplat::module; -namespace facebook { -namespace react { +namespace facebook::react { jni::local_ref CxxModuleWrapper::makeDsoNative( jni::alias_ref, @@ -55,5 +54,4 @@ jni::local_ref CxxModuleWrapper::makeDsoNative( std::unique_ptr((*factory)())); } -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/jni/CxxModuleWrapper.h b/packages/react-native/ReactAndroid/src/main/jni/react/jni/CxxModuleWrapper.h index 656fd8ef0a6e37..1534b51e29e19a 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/jni/CxxModuleWrapper.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/jni/CxxModuleWrapper.h @@ -9,8 +9,7 @@ #include "CxxModuleWrapperBase.h" -namespace facebook { -namespace react { +namespace facebook::react { class CxxModuleWrapper : public jni::HybridClass { @@ -46,5 +45,4 @@ class CxxModuleWrapper std::unique_ptr module_; }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/jni/CxxModuleWrapperBase.h b/packages/react-native/ReactAndroid/src/main/jni/react/jni/CxxModuleWrapperBase.h index 3b561522409b45..edb353ac586dcd 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/jni/CxxModuleWrapperBase.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/jni/CxxModuleWrapperBase.h @@ -13,8 +13,7 @@ #include #include -namespace facebook { -namespace react { +namespace facebook::react { struct JNativeModule : jni::JavaClass { constexpr static const char *const kJavaDescriptor = @@ -43,5 +42,4 @@ class CxxModuleWrapperBase virtual std::unique_ptr getModule() = 0; }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/jni/CxxSharedModuleWrapper.h b/packages/react-native/ReactAndroid/src/main/jni/react/jni/CxxSharedModuleWrapper.h index 1a06300c2e6dbb..8d6dd71f8c0928 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/jni/CxxSharedModuleWrapper.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/jni/CxxSharedModuleWrapper.h @@ -11,8 +11,7 @@ #include "CxxModuleWrapperBase.h" -namespace facebook { -namespace react { +namespace facebook::react { class CxxSharedModuleWrapper : public CxxModuleWrapperBase { public: @@ -35,5 +34,4 @@ class CxxSharedModuleWrapper : public CxxModuleWrapperBase { std::shared_ptr shared_; }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/jni/JCallback.h b/packages/react-native/ReactAndroid/src/main/jni/react/jni/JCallback.h index da480384d9e897..56f0a4109a8ea3 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/jni/JCallback.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/jni/JCallback.h @@ -14,8 +14,7 @@ #include "NativeArray.h" -namespace facebook { -namespace react { +namespace facebook::react { class Instance; @@ -55,5 +54,4 @@ class JCxxCallbackImpl : public jni::HybridClass { Callback callback_; }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/jni/JInspector.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/jni/JInspector.cpp index 27eca48da219ed..a96bd26ab1bd8c 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/jni/JInspector.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/jni/JInspector.cpp @@ -11,8 +11,7 @@ #ifdef WITH_INSPECTOR -namespace facebook { -namespace react { +namespace facebook::react { namespace { @@ -108,7 +107,6 @@ void JInspector::registerNatives() { }); } -} // namespace react -} // namespace facebook +} // namespace facebook::react #endif diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/jni/JInspector.h b/packages/react-native/ReactAndroid/src/main/jni/react/jni/JInspector.h index 4016365e589ade..b18d8ef58ee291 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/jni/JInspector.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/jni/JInspector.h @@ -15,8 +15,7 @@ #include -namespace facebook { -namespace react { +namespace facebook::react { class JPage : public jni::JavaClass { public: @@ -75,7 +74,6 @@ class JInspector : public jni::HybridClass { IInspector *inspector_; }; -} // namespace react -} // namespace facebook +} // namespace facebook::react #endif diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/jni/JMessageQueueThread.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/jni/JMessageQueueThread.cpp index d95c28ea66b0b2..206844ec749050 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/jni/JMessageQueueThread.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/jni/JMessageQueueThread.cpp @@ -15,8 +15,7 @@ #include #include -namespace facebook { -namespace react { +namespace facebook::react { using namespace jni; @@ -109,5 +108,4 @@ void JMessageQueueThread::quitSynchronous() { method(m_jobj); } -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/jni/JReactCxxErrorHandler.h b/packages/react-native/ReactAndroid/src/main/jni/react/jni/JReactCxxErrorHandler.h index 45b2799f77fdf0..0bbf90351db629 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/jni/JReactCxxErrorHandler.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/jni/JReactCxxErrorHandler.h @@ -10,8 +10,7 @@ #include #include -namespace facebook { -namespace react { +namespace facebook::react { class JReactCxxErrorHandler : public jni::JavaClass { public: @@ -21,5 +20,4 @@ class JReactCxxErrorHandler : public jni::JavaClass { static void handleError(std::string message); }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/jni/JReactMarker.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/jni/JReactMarker.cpp index 6708d0d1ba8770..c3be1ad2b55a3f 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/jni/JReactMarker.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/jni/JReactMarker.cpp @@ -11,8 +11,7 @@ #include #include -namespace facebook { -namespace react { +namespace facebook::react { void JReactMarker::setLogPerfMarkerIfNeeded() { static std::once_flag flag{}; @@ -110,5 +109,4 @@ double JReactMarker::getAppStartTime() { return meth(cls); } -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/jni/JReactMarker.h b/packages/react-native/ReactAndroid/src/main/jni/react/jni/JReactMarker.h index b945d5555a9631..a857ae4f3f72e1 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/jni/JReactMarker.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/jni/JReactMarker.h @@ -12,8 +12,7 @@ #include -namespace facebook { -namespace react { +namespace facebook::react { class JReactMarker : public facebook::jni::JavaClass { public: @@ -41,5 +40,4 @@ class JReactMarker : public facebook::jni::JavaClass { static double getAppStartTime(); }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/jni/JReactSoftExceptionLogger.h b/packages/react-native/ReactAndroid/src/main/jni/react/jni/JReactSoftExceptionLogger.h index fda4b85e3ebd62..e412d668585d5d 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/jni/JReactSoftExceptionLogger.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/jni/JReactSoftExceptionLogger.h @@ -10,8 +10,7 @@ #include #include -namespace facebook { -namespace react { +namespace facebook::react { class JReactSoftExceptionLogger : public jni::JavaClass { @@ -24,5 +23,4 @@ class JReactSoftExceptionLogger std::string message); }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/jni/JRuntimeExecutor.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/jni/JRuntimeExecutor.cpp index 70bda09416ccba..433e6ed143d127 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/jni/JRuntimeExecutor.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/jni/JRuntimeExecutor.cpp @@ -7,8 +7,7 @@ #include "JRuntimeExecutor.h" -namespace facebook { -namespace react { +namespace facebook::react { JRuntimeExecutor::JRuntimeExecutor(RuntimeExecutor runtimeExecutor) : runtimeExecutor_(runtimeExecutor) {} @@ -17,5 +16,4 @@ RuntimeExecutor JRuntimeExecutor::get() { return runtimeExecutor_; } -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/jni/JRuntimeExecutor.h b/packages/react-native/ReactAndroid/src/main/jni/react/jni/JRuntimeExecutor.h index 03df73d1a446a5..b614ad1a1fecc3 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/jni/JRuntimeExecutor.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/jni/JRuntimeExecutor.h @@ -10,8 +10,7 @@ #include #include -namespace facebook { -namespace react { +namespace facebook::react { class JRuntimeExecutor : public jni::HybridClass { public: @@ -26,5 +25,4 @@ class JRuntimeExecutor : public jni::HybridClass { RuntimeExecutor runtimeExecutor_; }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/jni/JRuntimeScheduler.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/jni/JRuntimeScheduler.cpp index 7a9b3f8efaf9c2..587c32419752bc 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/jni/JRuntimeScheduler.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/jni/JRuntimeScheduler.cpp @@ -7,8 +7,7 @@ #include "JRuntimeScheduler.h" -namespace facebook { -namespace react { +namespace facebook::react { JRuntimeScheduler::JRuntimeScheduler( std::weak_ptr runtimeScheduler) @@ -18,5 +17,4 @@ std::weak_ptr JRuntimeScheduler::get() { return runtimeScheduler_; } -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/jni/JRuntimeScheduler.h b/packages/react-native/ReactAndroid/src/main/jni/react/jni/JRuntimeScheduler.h index 8bc42bf9d024c3..6220ccedda3437 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/jni/JRuntimeScheduler.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/jni/JRuntimeScheduler.h @@ -10,8 +10,7 @@ #include #include -namespace facebook { -namespace react { +namespace facebook::react { class JRuntimeScheduler : public jni::HybridClass { public: @@ -26,5 +25,4 @@ class JRuntimeScheduler : public jni::HybridClass { std::weak_ptr runtimeScheduler_; }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/jni/JSLoader.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/jni/JSLoader.cpp index dc87d09bac8ff2..f37f1ce6ca02e2 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/jni/JSLoader.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/jni/JSLoader.cpp @@ -20,8 +20,7 @@ using fbsystrace::FbSystraceSection; using namespace facebook::jni; -namespace facebook { -namespace react { +namespace facebook::react { class AssetManagerString : public JSBigString { public: @@ -95,5 +94,4 @@ loadScriptFromAssets(AAssetManager *manager, const std::string &assetName) { "' is packaged correctly for release.")); } -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/jni/JSLoader.h b/packages/react-native/ReactAndroid/src/main/jni/react/jni/JSLoader.h index d16f2990276c25..2c04656d85033f 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/jni/JSLoader.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/jni/JSLoader.h @@ -13,8 +13,7 @@ #include #include -namespace facebook { -namespace react { +namespace facebook::react { struct JAssetManager : jni::JavaClass { static constexpr auto kJavaDescriptor = "Landroid/content/res/AssetManager;"; @@ -30,5 +29,4 @@ std::unique_ptr loadScriptFromAssets( AAssetManager *assetManager, const std::string &assetName); -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/jni/JSLogging.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/jni/JSLogging.cpp index cf0a293688abc9..be29b28aa10867 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/jni/JSLogging.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/jni/JSLogging.cpp @@ -9,8 +9,7 @@ #include -namespace facebook { -namespace react { +namespace facebook::react { void reactAndroidLoggingHook( const std::string &message, @@ -25,5 +24,4 @@ void reactAndroidLoggingHook( message, static_cast(logLevel + ANDROID_LOG_DEBUG)); } -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/jni/JSLogging.h b/packages/react-native/ReactAndroid/src/main/jni/react/jni/JSLogging.h index 0fd115bafa3ca3..36a246782fe78b 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/jni/JSLogging.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/jni/JSLogging.h @@ -10,13 +10,11 @@ #include #include -namespace facebook { -namespace react { +namespace facebook::react { void reactAndroidLoggingHook( const std::string &message, android_LogPriority logLevel); void reactAndroidLoggingHook(const std::string &message, unsigned int logLevel); -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/jni/JavaModuleWrapper.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/jni/JavaModuleWrapper.cpp index 5cfdf7f5943c8c..c4e32b11cd67e2 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/jni/JavaModuleWrapper.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/jni/JavaModuleWrapper.cpp @@ -26,8 +26,7 @@ using facebook::xplat::module::CxxModule; -namespace facebook { -namespace react { +namespace facebook::react { std::string JMethodDescriptor::getSignature() const { static auto signature = javaClassStatic()->getField("signature"); @@ -159,5 +158,4 @@ jni::local_ref JMethodDescriptor::getMethod() return getFieldValue(method); } -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/jni/JavaModuleWrapper.h b/packages/react-native/ReactAndroid/src/main/jni/react/jni/JavaModuleWrapper.h index f5bf7dcdf84590..40031cb0639f74 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/jni/JavaModuleWrapper.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/jni/JavaModuleWrapper.h @@ -13,8 +13,7 @@ #include "MethodInvoker.h" -namespace facebook { -namespace react { +namespace facebook::react { class Instance; class MessageQueueThread; @@ -85,5 +84,4 @@ class JavaNativeModule : public NativeModule { std::vector> syncMethods_; }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/jni/JavaScriptExecutorHolder.h b/packages/react-native/ReactAndroid/src/main/jni/react/jni/JavaScriptExecutorHolder.h index 1a4fa1435c10a8..55cbc3eb545927 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/jni/JavaScriptExecutorHolder.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/jni/JavaScriptExecutorHolder.h @@ -10,8 +10,7 @@ #include #include -namespace facebook { -namespace react { +namespace facebook::react { class JavaScriptExecutorHolder : public jni::HybridClass { @@ -31,5 +30,4 @@ class JavaScriptExecutorHolder std::shared_ptr mExecutorFactory; }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/jni/JniJSModulesUnbundle.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/jni/JniJSModulesUnbundle.cpp index 40aab053c681ba..b9bb2b56c020f0 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/jni/JniJSModulesUnbundle.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/jni/JniJSModulesUnbundle.cpp @@ -19,8 +19,7 @@ using magic_number_t = uint32_t; const magic_number_t MAGIC_FILE_HEADER = 0xFB0BD1E5; const char *MAGIC_FILE_NAME = "UNBUNDLE"; -namespace facebook { -namespace react { +namespace facebook::react { using asset_ptr = std::unique_ptr>; @@ -94,5 +93,4 @@ JSModulesUnbundle::Module JniJSModulesUnbundle::getModule( return {sourceUrl, std::string(buffer, AAsset_getLength(asset.get()))}; } -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/jni/JniJSModulesUnbundle.h b/packages/react-native/ReactAndroid/src/main/jni/react/jni/JniJSModulesUnbundle.h index 71187fd99aec11..100cbe4b00f00e 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/jni/JniJSModulesUnbundle.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/jni/JniJSModulesUnbundle.h @@ -12,8 +12,7 @@ #include #include -namespace facebook { -namespace react { +namespace facebook::react { class JniJSModulesUnbundle : public JSModulesUnbundle { /** @@ -41,5 +40,4 @@ class JniJSModulesUnbundle : public JSModulesUnbundle { std::string m_moduleDirectory; }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/jni/MethodInvoker.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/jni/MethodInvoker.cpp index 4223a449980999..6a944e6b9a33ac 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/jni/MethodInvoker.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/jni/MethodInvoker.cpp @@ -24,8 +24,7 @@ using namespace facebook::jni; -namespace facebook { -namespace react { +namespace facebook::react { namespace { @@ -311,5 +310,4 @@ MethodCallResult MethodInvoker::invoke( } } -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/jni/MethodInvoker.h b/packages/react-native/ReactAndroid/src/main/jni/react/jni/MethodInvoker.h index f0ab0a16814434..da7cdd4ecd35bf 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/jni/MethodInvoker.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/jni/MethodInvoker.h @@ -13,8 +13,7 @@ #include #include -namespace facebook { -namespace react { +namespace facebook::react { class Instance; @@ -62,5 +61,4 @@ class MethodInvoker { bool isSync_; }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/jni/ModuleRegistryBuilder.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/jni/ModuleRegistryBuilder.cpp index eeb248504aaed0..2d00a652e582bc 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/jni/ModuleRegistryBuilder.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/jni/ModuleRegistryBuilder.cpp @@ -13,8 +13,7 @@ #include -namespace facebook { -namespace react { +namespace facebook::react { std::string ModuleHolder::getName() const { static auto method = getClass()->getMethod("getName"); @@ -68,5 +67,4 @@ std::vector> buildNativeModuleList( return modules; } -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/jni/ModuleRegistryBuilder.h b/packages/react-native/ReactAndroid/src/main/jni/react/jni/ModuleRegistryBuilder.h index 6f837b8f3bb194..2902dd1da19420 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/jni/ModuleRegistryBuilder.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/jni/ModuleRegistryBuilder.h @@ -14,8 +14,7 @@ #include "CxxModuleWrapper.h" #include "JavaModuleWrapper.h" -namespace facebook { -namespace react { +namespace facebook::react { class MessageQueueThread; @@ -36,5 +35,4 @@ std::vector> buildNativeModuleList( jni::alias_ref::javaobject> cxxModules, std::shared_ptr moduleMessageQueue); -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/jni/NativeArray.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/jni/NativeArray.cpp index 6d4337877e0e7b..179cd0ab82fb6f 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/jni/NativeArray.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/jni/NativeArray.cpp @@ -11,8 +11,7 @@ using namespace facebook::jni; -namespace facebook { -namespace react { +namespace facebook::react { void NativeArray::assertInternalType() { if (!array_.isArray()) { @@ -44,5 +43,4 @@ void NativeArray::throwIfConsumed() { exceptions::throwIfObjectAlreadyConsumed(this, "Array already consumed"); } -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/jni/NativeArray.h b/packages/react-native/ReactAndroid/src/main/jni/react/jni/NativeArray.h index 1e48e742c6bfe8..08816872d641e7 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/jni/NativeArray.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/jni/NativeArray.h @@ -12,8 +12,7 @@ #include "NativeCommon.h" -namespace facebook { -namespace react { +namespace facebook::react { class NativeArray : public jni::HybridClass { public: @@ -48,5 +47,4 @@ class NativeArray : public jni::HybridClass { NativeArray &operator=(const NativeArray &) = delete; }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/jni/NativeCommon.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/jni/NativeCommon.cpp index 3b604bd06e7240..b7134f7276ff72 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/jni/NativeCommon.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/jni/NativeCommon.cpp @@ -9,8 +9,7 @@ using namespace facebook::jni; -namespace facebook { -namespace react { +namespace facebook::react { namespace exceptions { const char *gUnexpectedNativeTypeExceptionClass = @@ -61,5 +60,4 @@ local_ref ReadableType::getType(folly::dynamic::Type type) { } } -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/jni/NativeCommon.h b/packages/react-native/ReactAndroid/src/main/jni/react/jni/NativeCommon.h index d04c3b7bd46004..cc27b94b150bc1 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/jni/NativeCommon.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/jni/NativeCommon.h @@ -14,8 +14,7 @@ #define RN_EXPORT __attribute__((visibility("default"))) #endif -namespace facebook { -namespace react { +namespace facebook::react { struct ReadableType : public jni::JavaClass { static auto constexpr kJavaDescriptor = @@ -38,5 +37,4 @@ void throwIfObjectAlreadyConsumed(const T &t, const char *msg) { } // namespace exceptions -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/jni/NativeMap.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/jni/NativeMap.cpp index ee581634e6d53c..31a01a1348884a 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/jni/NativeMap.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/jni/NativeMap.cpp @@ -11,8 +11,7 @@ using namespace facebook::jni; -namespace facebook { -namespace react { +namespace facebook::react { local_ref NativeMap::toString() { throwIfConsumed(); @@ -35,5 +34,4 @@ void NativeMap::throwIfConsumed() { exceptions::throwIfObjectAlreadyConsumed(this, "Map already consumed"); } -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/jni/NativeMap.h b/packages/react-native/ReactAndroid/src/main/jni/react/jni/NativeMap.h index 39a42b236270d5..b61e22760e54b0 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/jni/NativeMap.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/jni/NativeMap.h @@ -12,8 +12,7 @@ #include "NativeCommon.h" -namespace facebook { -namespace react { +namespace facebook::react { class NativeMap : public jni::HybridClass { public: @@ -45,5 +44,4 @@ class NativeMap : public jni::HybridClass { NativeMap &operator=(const NativeMap &) = delete; }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp index 5dd3d1860981ab..58bd589c43d7ab 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp @@ -31,8 +31,7 @@ using namespace facebook::jni; -namespace facebook { -namespace react { +namespace facebook::react { namespace { @@ -93,5 +92,4 @@ extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) { }); } -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/jni/OnLoad.h b/packages/react-native/ReactAndroid/src/main/jni/react/jni/OnLoad.h index b68b71bd204874..54c83cb1faae4b 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/jni/OnLoad.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/jni/OnLoad.h @@ -9,10 +9,8 @@ #include -namespace facebook { -namespace react { +namespace facebook::react { jmethodID getLogMarkerMethod(); -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.cpp index 45217f71ecfb5e..bd9e98fee5821a 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.cpp @@ -18,8 +18,7 @@ #include -namespace facebook { -namespace react { +namespace facebook::react { const auto EXECUTOR_BASECLASS = "com/facebook/react/bridge/JavaJSExecutor"; @@ -140,5 +139,4 @@ std::string ProxyExecutor::getDescription() { return "Chrome"; } -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.h b/packages/react-native/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.h index 79d36e50f07462..4f05c0a9a2809e 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.h @@ -13,8 +13,7 @@ #include #include "OnLoad.h" -namespace facebook { -namespace react { +namespace facebook::react { /** * This executor factory can only create a single executor instance because it @@ -63,5 +62,4 @@ class ProxyExecutor : public JSExecutor { std::shared_ptr m_delegate; }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/jni/ReadableNativeArray.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/jni/ReadableNativeArray.cpp index 397108b9642f81..833db513e2f849 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/jni/ReadableNativeArray.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/jni/ReadableNativeArray.cpp @@ -11,8 +11,7 @@ using namespace facebook::jni; -namespace facebook { -namespace react { +namespace facebook::react { // TODO T112842309: Remove after fbjni upgraded in OSS void ReadableNativeArray::mapException(const std::exception &ex) { @@ -56,5 +55,4 @@ void ReadableNativeArray::registerNatives() { }); } -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/jni/ReadableNativeArray.h b/packages/react-native/ReactAndroid/src/main/jni/react/jni/ReadableNativeArray.h index 0242a4907be9ba..52ab38f0bafa9d 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/jni/ReadableNativeArray.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/jni/ReadableNativeArray.h @@ -12,8 +12,7 @@ #include "NativeCommon.h" #include "NativeMap.h" -namespace facebook { -namespace react { +namespace facebook::react { struct ReadableArray : jni::JavaClass { static auto constexpr kJavaDescriptor = @@ -41,5 +40,4 @@ class ReadableNativeArray jni::local_ref> importTypeArray(); }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/jni/ReadableNativeMap.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/jni/ReadableNativeMap.cpp index f55a92dffb928e..6a9d554b9ac4a7 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/jni/ReadableNativeMap.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/jni/ReadableNativeMap.cpp @@ -9,8 +9,7 @@ using namespace facebook::jni; -namespace facebook { -namespace react { +namespace facebook::react { // TODO T112842309: Remove after fbjni upgraded in OSS void ReadableNativeMap::mapException(const std::exception &ex) { @@ -134,5 +133,4 @@ void ReadableNativeMap::registerNatives() { }); } -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/jni/ReadableNativeMap.h b/packages/react-native/ReactAndroid/src/main/jni/react/jni/ReadableNativeMap.h index bf6a44245abfb8..2513a8a6028c27 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/jni/ReadableNativeMap.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/jni/ReadableNativeMap.h @@ -16,8 +16,7 @@ #include "NativeMap.h" #include "ReadableNativeArray.h" -namespace facebook { -namespace react { +namespace facebook::react { struct WritableNativeMap; @@ -50,5 +49,4 @@ struct ReadableNativeMap : jni::HybridClass { friend struct WritableNativeMap; }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/jni/WritableNativeArray.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/jni/WritableNativeArray.cpp index 14746a38f62e15..46f34f08d9ee76 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/jni/WritableNativeArray.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/jni/WritableNativeArray.cpp @@ -11,8 +11,7 @@ using namespace facebook::jni; -namespace facebook { -namespace react { +namespace facebook::react { WritableNativeArray::WritableNativeArray() : HybridBase(folly::dynamic::array()) {} @@ -89,5 +88,4 @@ void WritableNativeArray::registerNatives() { }); } -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/jni/WritableNativeArray.h b/packages/react-native/ReactAndroid/src/main/jni/react/jni/WritableNativeArray.h index fe5d8ad2e4e493..0b1224b6fc5b53 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/jni/WritableNativeArray.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/jni/WritableNativeArray.h @@ -13,8 +13,7 @@ #include "ReadableNativeArray.h" -namespace facebook { -namespace react { +namespace facebook::react { struct ReadableNativeMap; @@ -44,5 +43,4 @@ struct WritableNativeArray static void registerNatives(); }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/jni/WritableNativeMap.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/jni/WritableNativeMap.cpp index ddb0a83343731a..a787d9c6e279ea 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/jni/WritableNativeMap.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/jni/WritableNativeMap.cpp @@ -9,8 +9,7 @@ using namespace facebook::jni; -namespace facebook { -namespace react { +namespace facebook::react { WritableNativeMap::WritableNativeMap() : HybridBase(folly::dynamic::object()) {} @@ -100,5 +99,4 @@ void WritableNativeMap::registerNatives() { }); } -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/jni/WritableNativeMap.h b/packages/react-native/ReactAndroid/src/main/jni/react/jni/WritableNativeMap.h index 093759658cb4a2..61d153f3cf9feb 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/jni/WritableNativeMap.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/jni/WritableNativeMap.h @@ -14,8 +14,7 @@ #include "ReadableNativeArray.h" #include "ReadableNativeMap.h" -namespace facebook { -namespace react { +namespace facebook::react { struct WritableMap : jni::JavaClass { static auto constexpr kJavaDescriptor = @@ -46,5 +45,4 @@ struct WritableNativeMap friend HybridBase; }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/jscexecutor/OnLoad.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/jscexecutor/OnLoad.cpp index d61e0706d7b216..fa9a1d2697e4fd 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/jscexecutor/OnLoad.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/jscexecutor/OnLoad.cpp @@ -15,8 +15,7 @@ #include -namespace facebook { -namespace react { +namespace facebook::react { namespace { @@ -72,8 +71,7 @@ class JSCExecutorHolder using HybridBase::HybridBase; }; -} // namespace react -} // namespace facebook +} // namespace facebook::react JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) { return facebook::jni::initialize( diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/mapbuffer/react/common/mapbuffer/JReadableMapBuffer.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/mapbuffer/react/common/mapbuffer/JReadableMapBuffer.cpp index dd5d24cfef9de8..21bf6305cecca6 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/mapbuffer/react/common/mapbuffer/JReadableMapBuffer.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/mapbuffer/react/common/mapbuffer/JReadableMapBuffer.cpp @@ -7,8 +7,7 @@ #include "JReadableMapBuffer.h" -namespace facebook { -namespace react { +namespace facebook::react { void JReadableMapBuffer::registerNatives() { registerHybrid({ @@ -39,5 +38,4 @@ JReadableMapBuffer::JReadableMapBuffer(MapBuffer &&map) (serializedData_.size() != 0) && "Error no content in map"); } -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/mapbuffer/react/common/mapbuffer/JReadableMapBuffer.h b/packages/react-native/ReactAndroid/src/main/jni/react/mapbuffer/react/common/mapbuffer/JReadableMapBuffer.h index 4aae5f03e8f1a3..3db58d3bbe35bf 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/mapbuffer/react/common/mapbuffer/JReadableMapBuffer.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/mapbuffer/react/common/mapbuffer/JReadableMapBuffer.h @@ -13,8 +13,7 @@ #include -namespace facebook { -namespace react { +namespace facebook::react { class JReadableMapBuffer : public jni::HybridClass { public: @@ -36,5 +35,4 @@ class JReadableMapBuffer : public jni::HybridClass { std::vector serializedData_; }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/newarchdefaults/DefaultComponentsRegistry.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/newarchdefaults/DefaultComponentsRegistry.cpp index 00e2cfc15ec515..8273e31777adc7 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/newarchdefaults/DefaultComponentsRegistry.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/newarchdefaults/DefaultComponentsRegistry.cpp @@ -12,8 +12,7 @@ #include #include -namespace facebook { -namespace react { +namespace facebook::react { std::function)> DefaultComponentsRegistry::registerComponentDescriptorsFromEntryPoint{}; @@ -66,5 +65,4 @@ void DefaultComponentsRegistry::registerNatives() { }); } -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/newarchdefaults/DefaultComponentsRegistry.h b/packages/react-native/ReactAndroid/src/main/jni/react/newarchdefaults/DefaultComponentsRegistry.h index 921101b6aaface..748e6aeec82dd0 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/newarchdefaults/DefaultComponentsRegistry.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/newarchdefaults/DefaultComponentsRegistry.h @@ -13,8 +13,7 @@ #include #include -namespace facebook { -namespace react { +namespace facebook::react { class DefaultComponentsRegistry : public facebook::jni::HybridClass { @@ -43,5 +42,4 @@ class DefaultComponentsRegistry ComponentFactory *delegate); }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/newarchdefaults/DefaultTurboModuleManagerDelegate.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/newarchdefaults/DefaultTurboModuleManagerDelegate.cpp index 78af98677af624..182582251bfd9f 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/newarchdefaults/DefaultTurboModuleManagerDelegate.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/newarchdefaults/DefaultTurboModuleManagerDelegate.cpp @@ -9,8 +9,7 @@ #include -namespace facebook { -namespace react { +namespace facebook::react { std::function( const std::string &, @@ -56,5 +55,4 @@ std::shared_ptr DefaultTurboModuleManagerDelegate::getTurboModule( return rncore_ModuleProvider(name, params); } -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/newarchdefaults/DefaultTurboModuleManagerDelegate.h b/packages/react-native/ReactAndroid/src/main/jni/react/newarchdefaults/DefaultTurboModuleManagerDelegate.h index c6d37782d9b25f..bbfa17c44dcd2d 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/newarchdefaults/DefaultTurboModuleManagerDelegate.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/newarchdefaults/DefaultTurboModuleManagerDelegate.h @@ -13,8 +13,7 @@ #include #include -namespace facebook { -namespace react { +namespace facebook::react { class DefaultTurboModuleManagerDelegate : public jni::HybridClass< DefaultTurboModuleManagerDelegate, @@ -49,5 +48,4 @@ class DefaultTurboModuleManagerDelegate : public jni::HybridClass< using HybridBase::HybridBase; }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/perftests/OnLoad.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/perftests/OnLoad.cpp index 06b828439d2bb5..35965eb017cb2a 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/perftests/OnLoad.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/perftests/OnLoad.cpp @@ -13,8 +13,7 @@ #include #include -namespace facebook { -namespace react { +namespace facebook::react { using facebook::jni::alias_ref; @@ -207,8 +206,7 @@ static void startWatchingForLogMessage( } // namespace logwatcher } // namespace -} // namespace react -} // namespace facebook +} // namespace facebook::react using namespace facebook::react; diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/reactnativeblob/BlobCollector.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/reactnativeblob/BlobCollector.cpp index fd5e106631ca8f..7a9285653e5ca0 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/reactnativeblob/BlobCollector.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/reactnativeblob/BlobCollector.cpp @@ -13,8 +13,7 @@ using namespace facebook; -namespace facebook { -namespace react { +namespace facebook::react { static constexpr auto kBlobModuleJavaDescriptor = "com/facebook/react/modules/blob/BlobModule"; @@ -63,5 +62,4 @@ void BlobCollector::registerNatives() { {makeNativeMethod("nativeInstall", BlobCollector::nativeInstall)}); } -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/reactnativeblob/BlobCollector.h b/packages/react-native/ReactAndroid/src/main/jni/react/reactnativeblob/BlobCollector.h index 6f0943801c35f0..d327e44a288650 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/reactnativeblob/BlobCollector.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/reactnativeblob/BlobCollector.h @@ -10,8 +10,7 @@ #include #include -namespace facebook { -namespace react { +namespace facebook::react { class BlobCollector : public jni::HybridClass, public jsi::HostObject { @@ -38,5 +37,4 @@ class BlobCollector : public jni::HybridClass, const std::string blobId_; }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/reactperflogger/reactperflogger/JNativeModulePerfLogger.h b/packages/react-native/ReactAndroid/src/main/jni/react/reactperflogger/reactperflogger/JNativeModulePerfLogger.h index 362246c7945ac7..0ae39b952a8430 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/reactperflogger/reactperflogger/JNativeModulePerfLogger.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/reactperflogger/reactperflogger/JNativeModulePerfLogger.h @@ -11,8 +11,7 @@ #include #include -namespace facebook { -namespace react { +namespace facebook::react { class JNativeModulePerfLogger : public jni::HybridClass { @@ -26,5 +25,4 @@ class JNativeModulePerfLogger friend HybridBase; }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/turbomodule/ReactCommon/CallInvokerHolder.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/turbomodule/ReactCommon/CallInvokerHolder.cpp index f2d610b5e0bd8e..9b44821755b9e9 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/turbomodule/ReactCommon/CallInvokerHolder.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/turbomodule/ReactCommon/CallInvokerHolder.cpp @@ -7,8 +7,7 @@ #include "CallInvokerHolder.h" -namespace facebook { -namespace react { +namespace facebook::react { CallInvokerHolder::CallInvokerHolder(std::shared_ptr callInvoker) : _callInvoker(callInvoker) {} @@ -19,5 +18,4 @@ std::shared_ptr CallInvokerHolder::getCallInvoker() { void CallInvokerHolder::registerNatives() {} -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/turbomodule/ReactCommon/CallInvokerHolder.h b/packages/react-native/ReactAndroid/src/main/jni/react/turbomodule/ReactCommon/CallInvokerHolder.h index 5e64012dba8ae1..3e4b4f8f2a2767 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/turbomodule/ReactCommon/CallInvokerHolder.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/turbomodule/ReactCommon/CallInvokerHolder.h @@ -11,8 +11,7 @@ #include #include -namespace facebook { -namespace react { +namespace facebook::react { class CallInvokerHolder : public jni::HybridClass { public: @@ -28,5 +27,4 @@ class CallInvokerHolder : public jni::HybridClass { std::shared_ptr _callInvoker; }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/turbomodule/ReactCommon/CompositeTurboModuleManagerDelegate.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/turbomodule/ReactCommon/CompositeTurboModuleManagerDelegate.cpp index dedcff8592ad62..4796310bca7277 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/turbomodule/ReactCommon/CompositeTurboModuleManagerDelegate.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/turbomodule/ReactCommon/CompositeTurboModuleManagerDelegate.cpp @@ -7,8 +7,7 @@ #include "CompositeTurboModuleManagerDelegate.h" -namespace facebook { -namespace react { +namespace facebook::react { jni::local_ref CompositeTurboModuleManagerDelegate::initHybrid(jni::alias_ref) { @@ -55,5 +54,4 @@ void CompositeTurboModuleManagerDelegate::addTurboModuleManagerDelegate( mDelegates_.insert(turboModuleManagerDelegate->cthis()); } -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/turbomodule/ReactCommon/CompositeTurboModuleManagerDelegate.h b/packages/react-native/ReactAndroid/src/main/jni/react/turbomodule/ReactCommon/CompositeTurboModuleManagerDelegate.h index 257d87b53b921d..46aece570b1a6d 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/turbomodule/ReactCommon/CompositeTurboModuleManagerDelegate.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/turbomodule/ReactCommon/CompositeTurboModuleManagerDelegate.h @@ -13,8 +13,7 @@ #include #include -namespace facebook { -namespace react { +namespace facebook::react { class CompositeTurboModuleManagerDelegate : public jni::HybridClass< @@ -45,5 +44,4 @@ class CompositeTurboModuleManagerDelegate turboModuleManagerDelegate); }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/turbomodule/ReactCommon/TurboModuleManager.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/turbomodule/ReactCommon/TurboModuleManager.cpp index 9d57caf91a4f0d..8b8f2c64611ff8 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/turbomodule/ReactCommon/TurboModuleManager.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/turbomodule/ReactCommon/TurboModuleManager.cpp @@ -19,8 +19,7 @@ #include "TurboModuleManager.h" -namespace facebook { -namespace react { +namespace facebook::react { namespace { @@ -114,7 +113,8 @@ TurboModuleManager::TurboModuleManager( jsCallInvoker_(jsCallInvoker), nativeCallInvoker_(nativeCallInvoker), delegate_(jni::make_global(delegate)), - turboModuleCache_(std::make_shared()) {} + turboModuleCache_(std::make_shared()), + legacyModuleCache_(std::make_shared()) {} jni::local_ref TurboModuleManager::initHybrid( jni::alias_ref jThis, @@ -140,88 +140,7 @@ void TurboModuleManager::registerNatives() { TurboModuleProviderFunctionType TurboModuleManager::createTurboModuleProvider() { - return - [turboModuleCache_ = std::weak_ptr(turboModuleCache_), - jsCallInvoker_ = std::weak_ptr(jsCallInvoker_), - nativeCallInvoker_ = std::weak_ptr(nativeCallInvoker_), - delegate_ = jni::make_weak(delegate_), - javaPart_ = jni::make_weak(javaPart_)]( - const std::string &name) -> std::shared_ptr { - auto turboModuleCache = turboModuleCache_.lock(); - auto jsCallInvoker = jsCallInvoker_.lock(); - auto nativeCallInvoker = nativeCallInvoker_.lock(); - auto delegate = delegate_.lockLocal(); - auto javaPart = javaPart_.lockLocal(); - - if (!turboModuleCache || !jsCallInvoker || !nativeCallInvoker || - !delegate || !javaPart) { - return nullptr; - } - - const char *moduleName = name.c_str(); - - TurboModulePerfLogger::moduleJSRequireBeginningStart(moduleName); - - auto turboModuleLookup = turboModuleCache->find(name); - if (turboModuleLookup != turboModuleCache->end()) { - TurboModulePerfLogger::moduleJSRequireBeginningCacheHit(moduleName); - TurboModulePerfLogger::moduleJSRequireBeginningEnd(moduleName); - return turboModuleLookup->second; - } - - TurboModulePerfLogger::moduleJSRequireBeginningEnd(moduleName); - - auto cxxModule = delegate->cthis()->getTurboModule(name, jsCallInvoker); - if (cxxModule) { - turboModuleCache->insert({name, cxxModule}); - return cxxModule; - } - - static auto getTurboLegacyCxxModule = - javaPart->getClass() - ->getMethod( - const std::string &)>("getTurboLegacyCxxModule"); - auto legacyCxxModule = getTurboLegacyCxxModule(javaPart.get(), name); - - if (legacyCxxModule) { - TurboModulePerfLogger::moduleJSRequireEndingStart(moduleName); - - auto turboModule = std::make_shared( - legacyCxxModule->cthis()->getModule(), jsCallInvoker); - turboModuleCache->insert({name, turboModule}); - - TurboModulePerfLogger::moduleJSRequireEndingEnd(moduleName); - return turboModule; - } - - static auto getTurboJavaModule = - javaPart->getClass() - ->getMethod(const std::string &)>( - "getTurboJavaModule"); - auto moduleInstance = getTurboJavaModule(javaPart.get(), name); - - if (moduleInstance) { - TurboModulePerfLogger::moduleJSRequireEndingStart(moduleName); - JavaTurboModule::InitParams params = { - .moduleName = name, - .instance = moduleInstance, - .jsInvoker = jsCallInvoker, - .nativeInvoker = nativeCallInvoker}; - - auto turboModule = delegate->cthis()->getTurboModule(name, params); - turboModuleCache->insert({name, turboModule}); - TurboModulePerfLogger::moduleJSRequireEndingEnd(moduleName); - return turboModule; - } - - return nullptr; - }; -} - -TurboModuleProviderFunctionType -TurboModuleManager::createLegacyModuleProvider() { - return [turboModuleCache_ = - std::weak_ptr(turboModuleCache_), + return [turboModuleCache_ = std::weak_ptr(turboModuleCache_), jsCallInvoker_ = std::weak_ptr(jsCallInvoker_), nativeCallInvoker_ = std::weak_ptr(nativeCallInvoker_), delegate_ = jni::make_weak(delegate_), @@ -251,6 +170,85 @@ TurboModuleManager::createLegacyModuleProvider() { TurboModulePerfLogger::moduleJSRequireBeginningEnd(moduleName); + auto cxxModule = delegate->cthis()->getTurboModule(name, jsCallInvoker); + if (cxxModule) { + turboModuleCache->insert({name, cxxModule}); + return cxxModule; + } + + static auto getTurboLegacyCxxModule = + javaPart->getClass() + ->getMethod( + const std::string &)>("getTurboLegacyCxxModule"); + auto legacyCxxModule = getTurboLegacyCxxModule(javaPart.get(), name); + + if (legacyCxxModule) { + TurboModulePerfLogger::moduleJSRequireEndingStart(moduleName); + + auto turboModule = std::make_shared( + legacyCxxModule->cthis()->getModule(), jsCallInvoker); + turboModuleCache->insert({name, turboModule}); + + TurboModulePerfLogger::moduleJSRequireEndingEnd(moduleName); + return turboModule; + } + + static auto getTurboJavaModule = + javaPart->getClass() + ->getMethod(const std::string &)>( + "getTurboJavaModule"); + auto moduleInstance = getTurboJavaModule(javaPart.get(), name); + + if (moduleInstance) { + TurboModulePerfLogger::moduleJSRequireEndingStart(moduleName); + JavaTurboModule::InitParams params = { + .moduleName = name, + .instance = moduleInstance, + .jsInvoker = jsCallInvoker, + .nativeInvoker = nativeCallInvoker}; + + auto turboModule = delegate->cthis()->getTurboModule(name, params); + turboModuleCache->insert({name, turboModule}); + TurboModulePerfLogger::moduleJSRequireEndingEnd(moduleName); + return turboModule; + } + + return nullptr; + }; +} + +TurboModuleProviderFunctionType +TurboModuleManager::createLegacyModuleProvider() { + return [legacyModuleCache_ = std::weak_ptr(legacyModuleCache_), + jsCallInvoker_ = std::weak_ptr(jsCallInvoker_), + nativeCallInvoker_ = std::weak_ptr(nativeCallInvoker_), + delegate_ = jni::make_weak(delegate_), + javaPart_ = jni::make_weak(javaPart_)]( + const std::string &name) -> std::shared_ptr { + auto legacyModuleCache = legacyModuleCache_.lock(); + auto jsCallInvoker = jsCallInvoker_.lock(); + auto nativeCallInvoker = nativeCallInvoker_.lock(); + auto delegate = delegate_.lockLocal(); + auto javaPart = javaPart_.lockLocal(); + + if (!legacyModuleCache || !jsCallInvoker || !nativeCallInvoker || + !delegate || !javaPart) { + return nullptr; + } + + const char *moduleName = name.c_str(); + + TurboModulePerfLogger::moduleJSRequireBeginningStart(moduleName); + + auto legacyModuleLookup = legacyModuleCache->find(name); + if (legacyModuleLookup != legacyModuleCache->end()) { + TurboModulePerfLogger::moduleJSRequireBeginningCacheHit(moduleName); + TurboModulePerfLogger::moduleJSRequireBeginningEnd(moduleName); + return legacyModuleLookup->second; + } + + TurboModulePerfLogger::moduleJSRequireBeginningEnd(moduleName); + static auto getLegacyCxxModule = javaPart->getClass() ->getMethod( @@ -262,7 +260,7 @@ TurboModuleManager::createLegacyModuleProvider() { auto turboModule = std::make_shared( legacyCxxModule->cthis()->getModule(), jsCallInvoker); - turboModuleCache->insert({name, turboModule}); + legacyModuleCache->insert({name, turboModule}); TurboModulePerfLogger::moduleJSRequireEndingEnd(moduleName); return turboModule; @@ -301,7 +299,7 @@ TurboModuleManager::createLegacyModuleProvider() { auto turboModule = std::make_shared(params, methodDescriptors); - turboModuleCache->insert({name, turboModule}); + legacyModuleCache->insert({name, turboModule}); TurboModulePerfLogger::moduleJSRequireEndingEnd(moduleName); return turboModule; } @@ -335,5 +333,4 @@ void TurboModuleManager::installJSIBindings(bool shouldCreateLegacyModules) { }); } -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/turbomodule/ReactCommon/TurboModuleManager.h b/packages/react-native/ReactAndroid/src/main/jni/react/turbomodule/ReactCommon/TurboModuleManager.h index 22deddb577f412..03a0ad387009a6 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/turbomodule/ReactCommon/TurboModuleManager.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/turbomodule/ReactCommon/TurboModuleManager.h @@ -20,8 +20,7 @@ #include #include -namespace facebook { -namespace react { +namespace facebook::react { class TurboModuleManager : public jni::HybridClass { public: @@ -43,7 +42,7 @@ class TurboModuleManager : public jni::HybridClass { std::shared_ptr nativeCallInvoker_; jni::global_ref delegate_; - using TurboModuleCache = + using ModuleCache = std::unordered_map>; /** @@ -52,7 +51,8 @@ class TurboModuleManager : public jni::HybridClass { * We need to come up with a mechanism to allow modules to specify whether * they want to be long-lived or short-lived. */ - std::shared_ptr turboModuleCache_; + std::shared_ptr turboModuleCache_; + std::shared_ptr legacyModuleCache_; void installJSIBindings(bool shouldCreateLegacyModules); explicit TurboModuleManager( @@ -66,5 +66,4 @@ class TurboModuleManager : public jni::HybridClass { TurboModuleProviderFunctionType createLegacyModuleProvider(); }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/turbomodule/ReactCommon/TurboModuleManagerDelegate.h b/packages/react-native/ReactAndroid/src/main/jni/react/turbomodule/ReactCommon/TurboModuleManagerDelegate.h index 8e9dcb0a8e3947..e97575cf1a4a5a 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/turbomodule/ReactCommon/TurboModuleManagerDelegate.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/turbomodule/ReactCommon/TurboModuleManagerDelegate.h @@ -13,8 +13,7 @@ #include #include -namespace facebook { -namespace react { +namespace facebook::react { class TurboModuleManagerDelegate : public jni::HybridClass { @@ -33,5 +32,4 @@ class TurboModuleManagerDelegate friend HybridBase; }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/uimanager/ComponentNameResolverManager.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/uimanager/ComponentNameResolverManager.cpp index ec528b53e4ba3c..909b1d8c720b38 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/uimanager/ComponentNameResolverManager.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/uimanager/ComponentNameResolverManager.cpp @@ -14,8 +14,7 @@ #include -namespace facebook { -namespace react { +namespace facebook::react { using namespace facebook::jni; @@ -68,10 +67,8 @@ void ComponentNameResolverManager::installJSIBindings() { return thizz->componentNames_.find(name) != thizz->componentNames_.end(); }; - react::NativeComponentRegistryBinding::install( - runtime, std::move(viewManagerProvider)); + bindHasComponentProvider(runtime, std::move(viewManagerProvider)); }); } -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/uimanager/ComponentNameResolverManager.h b/packages/react-native/ReactAndroid/src/main/jni/react/uimanager/ComponentNameResolverManager.h index 33a667e961399e..db2a8fffc56187 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/uimanager/ComponentNameResolverManager.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/uimanager/ComponentNameResolverManager.h @@ -13,8 +13,7 @@ #include #include -namespace facebook { -namespace react { +namespace facebook::react { class ComponentNameResolverManager : public facebook::jni::HybridClass { @@ -50,5 +49,4 @@ class ComponentNameResolverManager facebook::jni::alias_ref componentNameResolver); }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-af/strings.xml b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-af/strings.xml index 24e1b69fe6b4ef..be441f6e6398ad 100644 --- a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-af/strings.xml +++ b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-af/strings.xml @@ -3,4 +3,6 @@ + Toestelspesifieke ontwikkelaarkieslys vir reaksies (%1$s) + Wys %1$s diff --git a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-ar/strings.xml b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-ar/strings.xml index 9ee5b1218296dd..39018d371fe9f6 100644 --- a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-ar/strings.xml +++ b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-ar/strings.xml @@ -3,4 +3,6 @@ + التفاعل مع قائمة التطوير الأصلي (%1$s) + تشغيل %1$s diff --git a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-bg/strings.xml b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-bg/strings.xml index 09b7b31c671dab..88472622ff9dfa 100644 --- a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-bg/strings.xml +++ b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-bg/strings.xml @@ -3,4 +3,5 @@ + Управление на %1$s diff --git a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-bn/strings.xml b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-bn/strings.xml index b5d516623ef92f..0f2812a24ef0f7 100644 --- a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-bn/strings.xml +++ b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-bn/strings.xml @@ -3,4 +3,6 @@ + রিয়েকশন নেটিভ ডেভেলপার মেনু (%1$s) + %1$s চলছে diff --git a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-cs/strings.xml b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-cs/strings.xml index b556b85f3bc390..ca0aeddeb5cbdf 100644 --- a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-cs/strings.xml +++ b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-cs/strings.xml @@ -3,4 +3,6 @@ + Nabídka React Native Dev (%1$s) + Spuštěno: %1$s diff --git a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-da/strings.xml b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-da/strings.xml index 1fd6723b3bae1f..0656358b2b90bd 100644 --- a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-da/strings.xml +++ b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-da/strings.xml @@ -3,4 +3,5 @@ + Kører %1$s diff --git a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-el/strings.xml b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-el/strings.xml index 0604fa12ac1e99..e619a3f967bf8c 100644 --- a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-el/strings.xml +++ b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-el/strings.xml @@ -3,4 +3,5 @@ + Προβάλλεται: %1$s diff --git a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-en-rGB/strings.xml b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-en-rGB/strings.xml index 49147780ee63b5..63bb3b42ae9d72 100644 --- a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-en-rGB/strings.xml +++ b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-en-rGB/strings.xml @@ -3,4 +3,5 @@ + React native dev menu (%1$s) diff --git a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-es-rES/strings.xml b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-es-rES/strings.xml index 025a080a25a9f8..4aba889d969b0e 100644 --- a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-es-rES/strings.xml +++ b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-es-rES/strings.xml @@ -3,4 +3,6 @@ + Menú del desarrollador de React Native (%1$s) + Se está ejecutando %1$s diff --git a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-es/strings.xml b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-es/strings.xml index bfb1514177a8c5..084c9b7f192c3c 100644 --- a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-es/strings.xml +++ b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-es/strings.xml @@ -3,4 +3,6 @@ + Menú de desarrollador nativo de reacción (%1$s) + Se está ejecutando %1$s diff --git a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-et/strings.xml b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-et/strings.xml index e17476d14d8823..ef1ea85b10f17c 100644 --- a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-et/strings.xml +++ b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-et/strings.xml @@ -3,4 +3,6 @@ + React Native’i arendaja menüü (%1$s) + Töötab %1$s diff --git a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-fa/strings.xml b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-fa/strings.xml index 72270d97102a7c..9717fb6ab20f78 100644 --- a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-fa/strings.xml +++ b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-fa/strings.xml @@ -3,4 +3,5 @@ + اجرای %1$s diff --git a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-fb-rLS/strings.xml b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-fb-rLS/strings.xml index d531cc7909261f..448b9c7e8f40e2 100644 --- a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-fb-rLS/strings.xml +++ b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-fb-rLS/strings.xml @@ -3,4 +3,6 @@ + React Native Dev Menu (%1$s)\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@ + Running %1$s\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@ diff --git a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-fb/strings.xml b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-fb/strings.xml index aee984ff543edb..05438a4eb22e30 100644 --- a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-fb/strings.xml +++ b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-fb/strings.xml @@ -3,4 +3,6 @@ + [React Native Dev Menu (%1$s)#f560753940a8856cdc2de8717c0295df:1] + [Running %1$s#c566f94d6bbe163799a3235b4b55f9d1:1] diff --git a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-fi/strings.xml b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-fi/strings.xml index 7c49d51816ed44..9fdab18be3958c 100644 --- a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-fi/strings.xml +++ b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-fi/strings.xml @@ -3,4 +3,6 @@ + Reagointien natiivikehittäjävalikko (%1$s) + Näytetään %1$s diff --git a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-fr-rCA/strings.xml b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-fr-rCA/strings.xml index d5fe3fb4a959d0..12dae28ef0c509 100644 --- a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-fr-rCA/strings.xml +++ b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-fr-rCA/strings.xml @@ -3,4 +3,5 @@ + %1$s en cours diff --git a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-fr/strings.xml b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-fr/strings.xml index 64b98fc6a925f6..f81cf0999513b5 100644 --- a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-fr/strings.xml +++ b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-fr/strings.xml @@ -3,4 +3,5 @@ + En cours %1$s diff --git a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-gu/strings.xml b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-gu/strings.xml index 2a2946b617eb63..139d0c2fe58a07 100644 --- a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-gu/strings.xml +++ b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-gu/strings.xml @@ -3,4 +3,6 @@ + મૂળ ડેવ મેનૂ (%1$s) પર પ્રતિક્રિયા આપો + %1$s ચાલુ છે diff --git a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-ha/strings.xml b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-ha/strings.xml index 084b1b6aac0de0..5fda75f3b55d41 100644 --- a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-ha/strings.xml +++ b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-ha/strings.xml @@ -3,4 +3,6 @@ + Mazaɓar Martanin Native Dev (%1$s) + Gudanar da %1$s diff --git a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-hi/strings.xml b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-hi/strings.xml index 3bca368f01586b..ba20ef7f4979fe 100644 --- a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-hi/strings.xml +++ b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-hi/strings.xml @@ -3,4 +3,6 @@ + रिएक्शन नेटिव डेवलपर मेनू (%1$s) + %1$s चला रहे हैं diff --git a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-hr/strings.xml b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-hr/strings.xml index 97250a3e1f6a4c..e63ea44730384f 100644 --- a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-hr/strings.xml +++ b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-hr/strings.xml @@ -3,4 +3,6 @@ + React native dev izbornik (%1$s) + Pokretanje %1$s diff --git a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-hu/strings.xml b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-hu/strings.xml index 7c28e052110cd6..12a1941326e363 100644 --- a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-hu/strings.xml +++ b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-hu/strings.xml @@ -3,4 +3,6 @@ + React Native-fejlesztői menü – (%1$s) + Futó %1$s diff --git a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-in/strings.xml b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-in/strings.xml index 6d32bd7238156f..46a9c671951166 100644 --- a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-in/strings.xml +++ b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-in/strings.xml @@ -3,4 +3,6 @@ + Menanggapi Menu Dev Asli (%1$s) + Menjalankan %1$s diff --git a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-it/strings.xml b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-it/strings.xml index 89dcf449cfb41d..90c67bb8e04b5d 100644 --- a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-it/strings.xml +++ b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-it/strings.xml @@ -3,4 +3,6 @@ + Menu sviluppatori React Native (%1$s) + %1$s in esecuzione diff --git a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-iw/strings.xml b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-iw/strings.xml index dcca08e175b5d0..e44942ad3942fd 100644 --- a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-iw/strings.xml +++ b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-iw/strings.xml @@ -3,4 +3,5 @@ + %1$s בפעילות diff --git a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-ja/strings.xml b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-ja/strings.xml index 437a25fe2bea8f..7650e689bee8e8 100644 --- a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-ja/strings.xml +++ b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-ja/strings.xml @@ -3,4 +3,6 @@ + React Native開発メニュー(%1$s) + %1$sの実行中 diff --git a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-jv/strings.xml b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-jv/strings.xml index 5bc93b9a564110..700a52183bc544 100644 --- a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-jv/strings.xml +++ b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-jv/strings.xml @@ -3,4 +3,6 @@ + Menu React Native Dev (%1$s) + Lagi tayang %1$s diff --git a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-km/strings.xml b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-km/strings.xml index d6ed5fadf8cf0f..4d3512a5a0f517 100644 --- a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-km/strings.xml +++ b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-km/strings.xml @@ -3,4 +3,6 @@ + ប្រតិកម្ម​ម៉ឺនុយ​​អភិវឌ្ឍដើម (%1$s) + ដំណើរការ %1$s diff --git a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-kn/strings.xml b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-kn/strings.xml index b4a93b39ff0be2..2e276ebb0b2adf 100644 --- a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-kn/strings.xml +++ b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-kn/strings.xml @@ -3,4 +3,6 @@ + ಸ್ಥಳೀಯ ದೇವ್ ಮೆನುವನ್ನು ಪ್ರತಿಕ್ರಿಯಿಸಿ (%1$s) + %1$s ರನ್ ಆಗುತ್ತಿದೆ diff --git a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-ko/strings.xml b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-ko/strings.xml index ba310011f0d554..33a74608b61423 100644 --- a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-ko/strings.xml +++ b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-ko/strings.xml @@ -3,4 +3,6 @@ + React Native 개발자 메뉴 (%1$s) + %1$s 실행 중 diff --git a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-lt/strings.xml b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-lt/strings.xml index c3177bbf23299d..285da215ee4f94 100644 --- a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-lt/strings.xml +++ b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-lt/strings.xml @@ -3,4 +3,6 @@ + Reagavimo savasis kūrėjo meniu „(%1$s)“ + Rodoma „%1$s“ diff --git a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-mk/strings.xml b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-mk/strings.xml index 1c76e1bb07c64e..f9f5f25ffb8d46 100644 --- a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-mk/strings.xml +++ b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-mk/strings.xml @@ -3,4 +3,6 @@ + Реакција на нативно програмерско мени (%1$s) + Се извршува %1$s diff --git a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-ml/strings.xml b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-ml/strings.xml index 5d568f33232987..4bb7b371717d46 100644 --- a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-ml/strings.xml +++ b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-ml/strings.xml @@ -3,4 +3,6 @@ + പ്രതികരണ നേറ്റീവ് ഡെവ മെനു (%1$s) + റൺ ചെയ്യുന്നു %1$s diff --git a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-ms/strings.xml b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-ms/strings.xml index 443eca7a57e1f8..0134ed075df3f6 100644 --- a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-ms/strings.xml +++ b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-ms/strings.xml @@ -3,4 +3,6 @@ + Menu Pembangun Asli Bereaksi (%1$s) + Sedang berjalan %1$s diff --git a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-my/strings.xml b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-my/strings.xml index 65abfdbf7bd192..06efd24185cb8a 100644 --- a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-my/strings.xml +++ b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-my/strings.xml @@ -3,4 +3,6 @@ + Native Dev မီနူး (%1$s) ကို တုံ့ပြန်ရန် + %1$s ကို ပြသနေပါတယ် diff --git a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-nb/strings.xml b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-nb/strings.xml index 873742c208ac05..33f899f194932b 100644 --- a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-nb/strings.xml +++ b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-nb/strings.xml @@ -3,4 +3,6 @@ + React Native-utviklermenyen (%1$s) + Kjører %1$s diff --git a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-nl/strings.xml b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-nl/strings.xml index 75355cf16bd979..4e674738996e75 100644 --- a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-nl/strings.xml +++ b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-nl/strings.xml @@ -3,4 +3,6 @@ + Native ontwikkelaarsmenu (%1$s) opnieuw activeren + %1$s actief diff --git a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-pa/strings.xml b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-pa/strings.xml index ea45e686429267..4ce2dfcd6a392f 100644 --- a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-pa/strings.xml +++ b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-pa/strings.xml @@ -3,4 +3,6 @@ + ਨੇਟਿਵ ਡਿਵੈ ਮੀਨੂ (%1$s) \'ਤੇ ਪ੍ਰਤੀਕਿਰਿਆ ਦਿਓ + %1$s ਚੱਲ ਰਿਹਾ ਹੈ diff --git a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-pl/strings.xml b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-pl/strings.xml index 4f53d3ec705bb8..71d4ae55203e63 100644 --- a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-pl/strings.xml +++ b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-pl/strings.xml @@ -3,4 +3,6 @@ + Menu dewelopera React Native (%1$s) + Wyświetlanie: %1$s diff --git a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-pt-rPT/strings.xml b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-pt-rPT/strings.xml index a0d4564f7f0932..42aee5be861113 100644 --- a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-pt-rPT/strings.xml +++ b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-pt-rPT/strings.xml @@ -3,4 +3,6 @@ + Menu de desenvolvimento do React Native (%1$s) + A apresentar %1$s diff --git a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-pt/strings.xml b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-pt/strings.xml index 3a24466f7006cd..6db39e0de3e36d 100644 --- a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-pt/strings.xml +++ b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-pt/strings.xml @@ -3,4 +3,6 @@ + Menu de desenvolvedor de reações nativas (%1$s) + %1$s em veiculação diff --git a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-ro/strings.xml b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-ro/strings.xml index 445f1af124553e..4f8c3b4aa4bd00 100644 --- a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-ro/strings.xml +++ b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-ro/strings.xml @@ -3,4 +3,6 @@ + Meniu dezvoltare React Native (%1$s) + %1$s în derulare diff --git a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-ru/strings.xml b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-ru/strings.xml index 1105ec010ea037..fac0a47b8c4cb3 100644 --- a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-ru/strings.xml +++ b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-ru/strings.xml @@ -3,4 +3,6 @@ + Меню разработчика React Native (%1$s) + Текущий показ %1$s diff --git a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-si/strings.xml b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-si/strings.xml index 2153d88a0669fb..87265ae2dcf341 100644 --- a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-si/strings.xml +++ b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-si/strings.xml @@ -3,4 +3,6 @@ + (%1$s) React Native Dev මෙනුව + %1$s ප්‍රචාරය කරමින් පවතී diff --git a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-sk/strings.xml b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-sk/strings.xml index 2d1768d211d54d..79b4fef8e92b1c 100644 --- a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-sk/strings.xml +++ b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-sk/strings.xml @@ -3,4 +3,6 @@ + Natívna vývojárska ponuka reakcie (%1$s) + Spustené: %1$s diff --git a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-sl/strings.xml b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-sl/strings.xml index a8d2a680928b58..55b867432646c9 100644 --- a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-sl/strings.xml +++ b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-sl/strings.xml @@ -3,4 +3,5 @@ + V teku %1$s diff --git a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-sr/strings.xml b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-sr/strings.xml index 47782d7cf1000e..8ee23f06dd336e 100644 --- a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-sr/strings.xml +++ b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-sr/strings.xml @@ -3,4 +3,6 @@ + React Native мени за програмере: (%1$s) + Покренуто: %1$s diff --git a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-sv/strings.xml b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-sv/strings.xml index 2eed9288127946..92892f1a2c2fbd 100644 --- a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-sv/strings.xml +++ b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-sv/strings.xml @@ -3,4 +3,5 @@ + Kör %1$s diff --git a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-sw/strings.xml b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-sw/strings.xml index 6dea5b85bb9a65..a8c044f2fa07a1 100644 --- a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-sw/strings.xml +++ b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-sw/strings.xml @@ -3,4 +3,5 @@ + Linaendeshwa %1$s diff --git a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-ta/strings.xml b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-ta/strings.xml index f8bfd1c350e5e0..7c8fd6d4c97ccf 100644 --- a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-ta/strings.xml +++ b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-ta/strings.xml @@ -3,4 +3,6 @@ + ரியாக்ட் நேட்டிவ் டேவ் மெனு (%1$s) + இயங்குகிறது %1$s diff --git a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-te/strings.xml b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-te/strings.xml index 241b213130fe0a..1d82e8321cf8f5 100644 --- a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-te/strings.xml +++ b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-te/strings.xml @@ -3,4 +3,6 @@ + స్థానిక డెవలపర్ మెనూ (%1$s)పై ప్రతిస్పందించండి + %1$s ప్రదర్శించబడుతోంది diff --git a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-th/strings.xml b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-th/strings.xml index a4206503879525..07c8dc11c82f79 100644 --- a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-th/strings.xml +++ b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-th/strings.xml @@ -3,4 +3,6 @@ + แสดงความรู้สึกต่อเมนูผู้พัฒนาแบบเนทีฟ (%1$s) + กำลังเผยแพร่ %1$s diff --git a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-tl/strings.xml b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-tl/strings.xml index dadacb703c930c..d6fcf1a1b5bc7c 100644 --- a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-tl/strings.xml +++ b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-tl/strings.xml @@ -3,4 +3,5 @@ + Tumatakbong %1$s diff --git a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-tr/strings.xml b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-tr/strings.xml index 755cf862c5eb9e..715bbfd559c3bf 100644 --- a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-tr/strings.xml +++ b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-tr/strings.xml @@ -3,4 +3,5 @@ + %1$s çalıştırıyor diff --git a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-uk/strings.xml b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-uk/strings.xml index bf3cc46d1cb490..beb6810c29f03b 100644 --- a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-uk/strings.xml +++ b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-uk/strings.xml @@ -3,4 +3,6 @@ + Меню розробника React Native «(%1$s)» + Поточний показ «%1$s» diff --git a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-ur/strings.xml b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-ur/strings.xml index 6d76f390ea068a..497b0851e2c147 100644 --- a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-ur/strings.xml +++ b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-ur/strings.xml @@ -3,4 +3,5 @@ + %1$s چل رہا ہے diff --git a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-vi/strings.xml b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-vi/strings.xml index 706622a3be9832..e9d23c6df6ddf4 100644 --- a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-vi/strings.xml +++ b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-vi/strings.xml @@ -3,4 +3,6 @@ + Menu phát triển React Native (%1$s) + Đang chạy %1$s diff --git a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-zh-rCN/strings.xml b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-zh-rCN/strings.xml index c50c06c1a71bf2..f613227f53490b 100644 --- a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-zh-rCN/strings.xml +++ b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-zh-rCN/strings.xml @@ -3,4 +3,6 @@ + React Native 开发者菜单(%1$s) + 正在运行%1$s diff --git a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-zh-rHK/strings.xml b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-zh-rHK/strings.xml index 067865f00e1e61..6eaf7cdea6d5cd 100644 --- a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-zh-rHK/strings.xml +++ b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-zh-rHK/strings.xml @@ -3,4 +3,6 @@ + React Native 開發人員選單(%1$s) + 正在執行%1$s diff --git a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-zh-rTW/strings.xml b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-zh-rTW/strings.xml index c56baa9ccc27f0..57cfc00727ce94 100644 --- a/packages/react-native/ReactAndroid/src/main/res/devsupport/values-zh-rTW/strings.xml +++ b/packages/react-native/ReactAndroid/src/main/res/devsupport/values-zh-rTW/strings.xml @@ -3,4 +3,6 @@ + React Native 開發人員功能表(%1$s) + 正在執行%1$s diff --git a/packages/react-native/ReactAndroid/src/main/res/devsupport/values/strings.xml b/packages/react-native/ReactAndroid/src/main/res/devsupport/values/strings.xml index 9ebb11b0830bd4..6149af00047c69 100644 --- a/packages/react-native/ReactAndroid/src/main/res/devsupport/values/strings.xml +++ b/packages/react-native/ReactAndroid/src/main/res/devsupport/values/strings.xml @@ -1,17 +1,13 @@ - + Reload Failed to load bundle. Try restarting the bundler or reconnecting your device. Change Bundle Location Failed to open Flipper. Please check that Metro is running. Open React DevTools Open Debugger - Debug - Stop Debugging Connecting to debugger... Failed to connect to debugger! - Debug with Chrome - Stop Chrome Debugging Enable Fast Refresh Disable Fast Refresh Disabling Fast Refresh because it requires a development bundle. @@ -30,4 +26,6 @@ Loading from %1$s… Disable Sampling Profiler Enable Sampling Profiler + React Native Dev Menu (%1$s) + Running %1$s diff --git a/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/ReactActivityDelegateTest.kt b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/ReactActivityDelegateTest.kt index dcf9da8ed02ee3..2912a9c193645b 100644 --- a/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/ReactActivityDelegateTest.kt +++ b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/ReactActivityDelegateTest.kt @@ -7,6 +7,7 @@ package com.facebook.react +import android.app.Activity import android.os.Bundle import org.junit.Assert.* import org.junit.Test @@ -16,10 +17,12 @@ import org.robolectric.RobolectricTestRunner @RunWith(RobolectricTestRunner::class) class ReactActivityDelegateTest { + val nullDelegate: Activity? = null + @Test fun delegateWithFabricEnabled_populatesInitialPropsCorrectly() { val delegate = - object : ReactActivityDelegate(null, "test-delegate") { + object : ReactActivityDelegate(nullDelegate, "test-delegate") { override fun isFabricEnabled() = true public val inspectLaunchOptions: Bundle? get() = composeLaunchOptions() @@ -33,7 +36,7 @@ class ReactActivityDelegateTest { @Test fun delegateWithoutFabricEnabled_hasNullInitialProperties() { val delegate = - object : ReactActivityDelegate(null, "test-delegate") { + object : ReactActivityDelegate(nullDelegate, "test-delegate") { override fun isFabricEnabled() = false public val inspectLaunchOptions: Bundle? get() = composeLaunchOptions() @@ -45,7 +48,7 @@ class ReactActivityDelegateTest { @Test fun delegateWithFabricEnabled_composesInitialPropertiesCorrectly() { val delegate = - object : ReactActivityDelegate(null, "test-delegate") { + object : ReactActivityDelegate(nullDelegate, "test-delegate") { override fun isFabricEnabled() = true override fun getLaunchOptions(): Bundle = Bundle().apply { putString("test-property", "test-value") } diff --git a/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/RootViewTest.java b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/RootViewTest.java deleted file mode 100644 index 3346b5205526e8..00000000000000 --- a/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/RootViewTest.java +++ /dev/null @@ -1,252 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -package com.facebook.react; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.reset; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.when; - -import android.graphics.Rect; -import android.view.MotionEvent; -import com.facebook.react.bridge.Arguments; -import com.facebook.react.bridge.CatalystInstance; -import com.facebook.react.bridge.JavaOnlyArray; -import com.facebook.react.bridge.JavaOnlyMap; -import com.facebook.react.bridge.ReactApplicationContext; -import com.facebook.react.bridge.ReactContext; -import com.facebook.react.bridge.ReactTestHelper; -import com.facebook.react.bridge.WritableArray; -import com.facebook.react.bridge.WritableMap; -import com.facebook.react.common.SystemClock; -import com.facebook.react.uimanager.DisplayMetricsHolder; -import com.facebook.react.uimanager.UIManagerModule; -import com.facebook.react.uimanager.events.Event; -import com.facebook.react.uimanager.events.EventDispatcher; -import com.facebook.react.uimanager.events.RCTEventEmitter; -import java.util.Date; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.Mockito; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; -import org.powermock.api.mockito.PowerMockito; -import org.powermock.core.classloader.annotations.PowerMockIgnore; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.rule.PowerMockRule; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; - -@PrepareForTest({Arguments.class, SystemClock.class}) -@RunWith(RobolectricTestRunner.class) -@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "androidx.*", "android.*"}) -public class RootViewTest { - - @Rule public PowerMockRule rule = new PowerMockRule(); - - private ReactContext mReactContext; - private CatalystInstance mCatalystInstanceMock; - - @Before - public void setUp() { - final long ts = SystemClock.uptimeMillis(); - PowerMockito.mockStatic(Arguments.class); - PowerMockito.when(Arguments.createArray()) - .thenAnswer( - new Answer() { - @Override - public Object answer(InvocationOnMock invocation) throws Throwable { - return new JavaOnlyArray(); - } - }); - PowerMockito.when(Arguments.createMap()) - .thenAnswer( - new Answer() { - @Override - public Object answer(InvocationOnMock invocation) throws Throwable { - return new JavaOnlyMap(); - } - }); - PowerMockito.mockStatic(SystemClock.class); - PowerMockito.when(SystemClock.uptimeMillis()) - .thenAnswer( - new Answer() { - @Override - public Object answer(InvocationOnMock invocation) throws Throwable { - return ts; - } - }); - - mCatalystInstanceMock = ReactTestHelper.createMockCatalystInstance(); - mReactContext = spy(new ReactApplicationContext(RuntimeEnvironment.application)); - mReactContext.initializeWithInstance(mCatalystInstanceMock); - DisplayMetricsHolder.initDisplayMetricsIfNotInitialized(mReactContext); - - UIManagerModule uiManagerModuleMock = mock(UIManagerModule.class); - when(mCatalystInstanceMock.getNativeModule(UIManagerModule.class)) - .thenReturn(uiManagerModuleMock); - } - - @Test - public void testTouchEmitter() { - ReactInstanceManager instanceManager = mock(ReactInstanceManager.class); - when(instanceManager.getCurrentReactContext()).thenReturn(mReactContext); - - UIManagerModule uiManager = mock(UIManagerModule.class); - EventDispatcher eventDispatcher = mock(EventDispatcher.class); - RCTEventEmitter eventEmitterModuleMock = mock(RCTEventEmitter.class); - when(mCatalystInstanceMock.getNativeModule(UIManagerModule.class)).thenReturn(uiManager); - when(uiManager.getEventDispatcher()).thenReturn(eventDispatcher); - - int rootViewId = 7; - - ReactRootView rootView = new ReactRootView(mReactContext); - rootView.setId(rootViewId); - rootView.setRootViewTag(rootViewId); - rootView.startReactApplication(instanceManager, ""); - rootView.simulateAttachForTesting(); - - long ts = SystemClock.currentTimeMillis(); - - // Test ACTION_DOWN event - rootView.onTouchEvent(MotionEvent.obtain(100, ts, MotionEvent.ACTION_DOWN, 0, 0, 0)); - - ArgumentCaptor downEventCaptor = ArgumentCaptor.forClass(Event.class); - verify(eventDispatcher).dispatchEvent(downEventCaptor.capture()); - verifyNoMoreInteractions(eventDispatcher); - - downEventCaptor.getValue().dispatch(eventEmitterModuleMock); - - ArgumentCaptor downActionTouchesArgCaptor = - ArgumentCaptor.forClass(JavaOnlyArray.class); - verify(eventEmitterModuleMock) - .receiveTouches( - eq("topTouchStart"), downActionTouchesArgCaptor.capture(), any(JavaOnlyArray.class)); - verifyNoMoreInteractions(eventEmitterModuleMock); - - assertThat(downActionTouchesArgCaptor.getValue().size()).isEqualTo(1); - assertThat(downActionTouchesArgCaptor.getValue().getMap(0)) - .isEqualTo( - JavaOnlyMap.of( - "pageX", - 0., - "pageY", - 0., - "locationX", - 0., - "locationY", - 0., - "target", - rootViewId, - "timestamp", - (double) ts, - "identifier", - 0., - "targetSurface", - -1)); - - // Test ACTION_UP event - reset(eventEmitterModuleMock, eventDispatcher); - - ArgumentCaptor upEventCaptor = ArgumentCaptor.forClass(Event.class); - ArgumentCaptor upActionTouchesArgCaptor = - ArgumentCaptor.forClass(JavaOnlyArray.class); - - rootView.onTouchEvent(MotionEvent.obtain(50, ts, MotionEvent.ACTION_UP, 0, 0, 0)); - verify(eventDispatcher).dispatchEvent(upEventCaptor.capture()); - verifyNoMoreInteractions(eventDispatcher); - - upEventCaptor.getValue().dispatch(eventEmitterModuleMock); - verify(eventEmitterModuleMock) - .receiveTouches( - eq("topTouchEnd"), upActionTouchesArgCaptor.capture(), any(WritableArray.class)); - verifyNoMoreInteractions(eventEmitterModuleMock); - - assertThat(upActionTouchesArgCaptor.getValue().size()).isEqualTo(1); - assertThat(upActionTouchesArgCaptor.getValue().getMap(0)) - .isEqualTo( - JavaOnlyMap.of( - "pageX", - 0., - "pageY", - 0., - "locationX", - 0., - "locationY", - 0., - "target", - rootViewId, - "timestamp", - (double) ts, - "identifier", - 0., - "targetSurface", - -1)); - - // Test other action - reset(eventDispatcher); - rootView.onTouchEvent( - MotionEvent.obtain(50, new Date().getTime(), MotionEvent.ACTION_HOVER_MOVE, 0, 0, 0)); - verifyNoMoreInteractions(eventDispatcher); - } - - @Test - public void testRemountApplication() { - ReactInstanceManager instanceManager = mock(ReactInstanceManager.class); - - ReactRootView rootView = new ReactRootView(mReactContext); - - rootView.startReactApplication(instanceManager, ""); - rootView.unmountReactApplication(); - rootView.startReactApplication(instanceManager, ""); - } - - @Test - public void testCheckForKeyboardEvents() { - ReactInstanceManager instanceManager = mock(ReactInstanceManager.class); - - when(instanceManager.getCurrentReactContext()).thenReturn(mReactContext); - ReactRootView rootView = - new ReactRootView(mReactContext) { - @Override - public void getWindowVisibleDisplayFrame(Rect outRect) { - if (outRect.bottom == 0) { - outRect.bottom += 100; - outRect.right += 370; - } else { - outRect.bottom += 370; - } - } - }; - - rootView.startReactApplication(instanceManager, ""); - rootView.simulateCheckForKeyboardForTesting(); - - WritableMap params = Arguments.createMap(); - WritableMap endCoordinates = Arguments.createMap(); - double screenHeight = 470.0; - double keyboardHeight = 100.0; - params.putDouble("duration", 0.0); - endCoordinates.putDouble("width", screenHeight - keyboardHeight); - endCoordinates.putDouble("screenX", 0.0); - endCoordinates.putDouble("height", screenHeight - keyboardHeight); - endCoordinates.putDouble("screenY", keyboardHeight); - params.putMap("endCoordinates", endCoordinates); - params.putString("easing", "keyboard"); - - verify(mReactContext, Mockito.times(1)).emitDeviceEvent("keyboardDidShow", params); - } -} diff --git a/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/RootViewTest.kt b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/RootViewTest.kt new file mode 100644 index 00000000000000..9be2b225b03b3c --- /dev/null +++ b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/RootViewTest.kt @@ -0,0 +1,224 @@ +/* + * 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. + */ + +package com.facebook.react + +import android.app.Activity +import android.graphics.Insets +import android.graphics.Rect +import android.view.MotionEvent +import android.view.WindowInsets +import com.facebook.react.bridge.Arguments +import com.facebook.react.bridge.CatalystInstance +import com.facebook.react.bridge.JavaOnlyArray +import com.facebook.react.bridge.JavaOnlyMap +import com.facebook.react.bridge.ReactApplicationContext +import com.facebook.react.bridge.ReactContext +import com.facebook.react.bridge.ReactTestHelper +import com.facebook.react.bridge.WritableArray +import com.facebook.react.common.SystemClock +import com.facebook.react.uimanager.DisplayMetricsHolder +import com.facebook.react.uimanager.UIManagerModule +import com.facebook.react.uimanager.events.Event +import com.facebook.react.uimanager.events.EventDispatcher +import com.facebook.react.uimanager.events.RCTEventEmitter +import java.util.Date +import org.assertj.core.api.Assertions.* +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.ArgumentCaptor +import org.mockito.ArgumentMatchers +import org.mockito.Mockito.* +import org.powermock.api.mockito.PowerMockito.mockStatic +import org.powermock.api.mockito.PowerMockito.`when` as whenever +import org.powermock.core.classloader.annotations.PowerMockIgnore +import org.powermock.core.classloader.annotations.PrepareForTest +import org.powermock.modules.junit4.rule.PowerMockRule +import org.robolectric.Robolectric +import org.robolectric.RobolectricTestRunner +import org.robolectric.RuntimeEnvironment + +@PrepareForTest(Arguments::class, SystemClock::class) +@RunWith(RobolectricTestRunner::class) +@PowerMockIgnore("org.mockito.*", "org.robolectric.*", "androidx.*", "android.*") +class RootViewTest { + @get:Rule var rule = PowerMockRule() + + private lateinit var reactContext: ReactContext + private lateinit var catalystInstanceMock: CatalystInstance + + @Before + fun setUp() { + val ts = SystemClock.uptimeMillis() + mockStatic(SystemClock::class.java) + mockStatic(Arguments::class.java) + whenever(Arguments.createArray()).thenAnswer { JavaOnlyArray() } + whenever(Arguments.createMap()).thenAnswer { JavaOnlyMap() } + whenever(SystemClock.uptimeMillis()).thenAnswer { ts } + + catalystInstanceMock = ReactTestHelper.createMockCatalystInstance() + reactContext = spy(ReactApplicationContext(RuntimeEnvironment.application)) + reactContext.initializeWithInstance(catalystInstanceMock) + + DisplayMetricsHolder.initDisplayMetricsIfNotInitialized(reactContext) + val uiManagerModuleMock = mock(UIManagerModule::class.java) + whenever(catalystInstanceMock.getNativeModule(UIManagerModule::class.java)) + .thenReturn(uiManagerModuleMock) + } + + @Test + fun testTouchEmitter() { + val instanceManager = mock(ReactInstanceManager::class.java) + whenever(instanceManager.currentReactContext).thenReturn(reactContext) + val uiManager = mock(UIManagerModule::class.java) + val eventDispatcher = mock(EventDispatcher::class.java) + val eventEmitterModuleMock = mock(RCTEventEmitter::class.java) + whenever(catalystInstanceMock.getNativeModule(UIManagerModule::class.java)) + .thenReturn(uiManager) + whenever(uiManager.eventDispatcher).thenReturn(eventDispatcher) + + // RootView IDs is React Native follow the 11, 21, 31, ... progression. + val rootViewId = 11 + val rootView = ReactRootView(reactContext) + rootView.id = rootViewId + rootView.rootViewTag = rootViewId + rootView.startReactApplication(instanceManager, "") + rootView.simulateAttachForTesting() + val ts = SystemClock.currentTimeMillis() + + // Test ACTION_DOWN event + rootView.onTouchEvent(MotionEvent.obtain(100, ts, MotionEvent.ACTION_DOWN, 0f, 0f, 0)) + + val downEventCaptor = ArgumentCaptor.forClass(Event::class.java) + verify(eventDispatcher).dispatchEvent(downEventCaptor.capture()) + verifyNoMoreInteractions(eventDispatcher) + downEventCaptor.value.dispatch(eventEmitterModuleMock) + val downActionTouchesArgCaptor = ArgumentCaptor.forClass(JavaOnlyArray::class.java) + verify(eventEmitterModuleMock) + .receiveTouches( + ArgumentMatchers.eq("topTouchStart"), + downActionTouchesArgCaptor.capture(), + ArgumentMatchers.any(JavaOnlyArray::class.java)) + verifyNoMoreInteractions(eventEmitterModuleMock) + assertThat(downActionTouchesArgCaptor.value.size()).isEqualTo(1) + assertThat(downActionTouchesArgCaptor.value.getMap(0)) + .isEqualTo( + JavaOnlyMap.of( + "pageX", + 0.0, + "pageY", + 0.0, + "locationX", + 0.0, + "locationY", + 0.0, + "target", + rootViewId, + "timestamp", + ts.toDouble(), + "identifier", + 0.0, + "targetSurface", + -1)) + + // Test ACTION_UP event + reset(eventEmitterModuleMock, eventDispatcher) + val upEventCaptor = ArgumentCaptor.forClass(Event::class.java) + val upActionTouchesArgCaptor = ArgumentCaptor.forClass(JavaOnlyArray::class.java) + + rootView.onTouchEvent(MotionEvent.obtain(50, ts, MotionEvent.ACTION_UP, 0f, 0f, 0)) + + verify(eventDispatcher).dispatchEvent(upEventCaptor.capture()) + verifyNoMoreInteractions(eventDispatcher) + upEventCaptor.value.dispatch(eventEmitterModuleMock) + verify(eventEmitterModuleMock) + .receiveTouches( + ArgumentMatchers.eq("topTouchEnd"), + upActionTouchesArgCaptor.capture(), + ArgumentMatchers.any(WritableArray::class.java)) + verifyNoMoreInteractions(eventEmitterModuleMock) + assertThat(upActionTouchesArgCaptor.value.size()).isEqualTo(1) + assertThat(upActionTouchesArgCaptor.value.getMap(0)) + .isEqualTo( + JavaOnlyMap.of( + "pageX", + 0.0, + "pageY", + 0.0, + "locationX", + 0.0, + "locationY", + 0.0, + "target", + rootViewId, + "timestamp", + ts.toDouble(), + "identifier", + 0.0, + "targetSurface", + -1)) + + // Test other action + reset(eventDispatcher) + + rootView.onTouchEvent( + MotionEvent.obtain(50, Date().time, MotionEvent.ACTION_HOVER_MOVE, 0f, 0f, 0)) + + verifyNoMoreInteractions(eventDispatcher) + } + + @Test + fun testRemountApplication() { + val instanceManager = mock(ReactInstanceManager::class.java) + val rootView = ReactRootView(reactContext) + rootView.startReactApplication(instanceManager, "") + rootView.unmountReactApplication() + rootView.startReactApplication(instanceManager, "") + } + + @Test + fun testCheckForKeyboardEvents() { + val instanceManager = mock(ReactInstanceManager::class.java) + val activity = Robolectric.buildActivity(Activity::class.java).create().get() + whenever(instanceManager.currentReactContext).thenReturn(reactContext) + val rootView: ReactRootView = + object : ReactRootView(activity) { + override fun getWindowVisibleDisplayFrame(outRect: Rect) { + if (outRect.bottom == 0) { + outRect.bottom += 100 + outRect.right += 370 + } else { + outRect.bottom += 370 + } + } + + override fun getRootWindowInsets() = + WindowInsets.Builder() + .setInsets(WindowInsets.Type.ime(), Insets.of(0, 0, 0, 370)) + .setVisible(WindowInsets.Type.ime(), true) + .build() + } + + rootView.startReactApplication(instanceManager, "") + rootView.simulateCheckForKeyboardForTesting() + + val params = Arguments.createMap() + val endCoordinates = Arguments.createMap() + val screenHeight = 470.0 + val keyboardHeight = 100.0 + params.putDouble("duration", 0.0) + endCoordinates.putDouble("width", screenHeight - keyboardHeight) + endCoordinates.putDouble("screenX", 0.0) + endCoordinates.putDouble("height", screenHeight - keyboardHeight) + endCoordinates.putDouble("screenY", keyboardHeight) + params.putMap("endCoordinates", endCoordinates) + params.putString("easing", "keyboard") + verify(reactContext, times(1)).emitDeviceEvent("keyboardDidShow", params) + } +} diff --git a/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/bridge/interop/FakeRCTEventEmitter.java b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/bridge/interop/FakeRCTEventEmitter.java new file mode 100644 index 00000000000000..8a2dc19f869c3c --- /dev/null +++ b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/bridge/interop/FakeRCTEventEmitter.java @@ -0,0 +1,23 @@ +/* + * 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. + */ + +package com.facebook.react.bridge.interop; + +import androidx.annotation.Nullable; +import com.facebook.react.bridge.WritableArray; +import com.facebook.react.bridge.WritableMap; +import com.facebook.react.uimanager.events.RCTEventEmitter; + +public class FakeRCTEventEmitter implements RCTEventEmitter { + + @Override + public void receiveEvent(int targetReactTag, String eventName, @Nullable WritableMap event) {} + + @Override + public void receiveTouches( + String eventName, WritableArray touches, WritableArray changedIndices) {} +} diff --git a/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/bridge/interop/InteropModuleRegistryTest.java b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/bridge/interop/InteropModuleRegistryTest.java new file mode 100644 index 00000000000000..158598078480d2 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/bridge/interop/InteropModuleRegistryTest.java @@ -0,0 +1,92 @@ +/* + * 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. + */ + +package com.facebook.react.bridge.interop; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import com.facebook.react.config.ReactFeatureFlags; +import com.facebook.react.modules.core.JSTimers; +import com.facebook.react.uimanager.events.RCTEventEmitter; +import org.junit.Before; +import org.junit.Test; + +public class InteropModuleRegistryTest { + + InteropModuleRegistry underTest; + + @Before + public void setup() { + underTest = new InteropModuleRegistry(); + } + + @Test + public void shouldReturnInteropModule_withFabricDisabled_returnsFalse() { + ReactFeatureFlags.enableFabricRenderer = false; + + assertFalse(underTest.shouldReturnInteropModule(RCTEventEmitter.class)); + } + + @Test + public void shouldReturnInteropModule_withFabricInteropDisabled_returnsFalse() { + ReactFeatureFlags.enableFabricRenderer = true; + ReactFeatureFlags.unstable_useFabricInterop = false; + + assertFalse(underTest.shouldReturnInteropModule(RCTEventEmitter.class)); + } + + @Test + public void shouldReturnInteropModule_withUnregisteredClass_returnsFalse() { + ReactFeatureFlags.enableFabricRenderer = true; + ReactFeatureFlags.unstable_useFabricInterop = true; + + assertFalse(underTest.shouldReturnInteropModule(JSTimers.class)); + } + + @Test + public void shouldReturnInteropModule_withRegisteredClass_returnsTrue() { + ReactFeatureFlags.enableFabricRenderer = true; + ReactFeatureFlags.unstable_useFabricInterop = true; + + underTest.registerInteropModule(RCTEventEmitter.class, new FakeRCTEventEmitter()); + + assertTrue(underTest.shouldReturnInteropModule(RCTEventEmitter.class)); + } + + @Test + public void getInteropModule_withRegisteredClassAndInvalidFlags_returnsNull() { + ReactFeatureFlags.enableFabricRenderer = false; + ReactFeatureFlags.unstable_useFabricInterop = false; + underTest.registerInteropModule(RCTEventEmitter.class, new FakeRCTEventEmitter()); + + RCTEventEmitter interopModule = underTest.getInteropModule(RCTEventEmitter.class); + + assertNull(interopModule); + } + + @Test + public void getInteropModule_withRegisteredClassAndValidFlags_returnsInteropModule() { + ReactFeatureFlags.enableFabricRenderer = true; + ReactFeatureFlags.unstable_useFabricInterop = true; + underTest.registerInteropModule(RCTEventEmitter.class, new FakeRCTEventEmitter()); + + RCTEventEmitter interopModule = underTest.getInteropModule(RCTEventEmitter.class); + + assertTrue(interopModule instanceof FakeRCTEventEmitter); + } + + @Test + public void getInteropModule_withUnregisteredClass_returnsNull() { + ReactFeatureFlags.enableFabricRenderer = true; + ReactFeatureFlags.unstable_useFabricInterop = true; + JSTimers missingModule = underTest.getInteropModule(JSTimers.class); + + assertNull(missingModule); + } +} diff --git a/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/bridgeless/BridgelessReactContextTest.java b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/bridgeless/BridgelessReactContextTest.java index c02aad0f9ffc3f..34b31d9c32e8b0 100644 --- a/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/bridgeless/BridgelessReactContextTest.java +++ b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/bridgeless/BridgelessReactContextTest.java @@ -14,16 +14,16 @@ import android.content.Context; import com.facebook.react.bridge.JSIModuleType; import com.facebook.react.uimanager.UIManagerModule; -import com.facebook.testing.robolectric.v4.WithTestDefaultsRunner; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentMatchers; import org.mockito.Mockito; import org.robolectric.Robolectric; +import org.robolectric.RobolectricTestRunner; /** Tests {@link BridgelessReactContext} */ -@RunWith(WithTestDefaultsRunner.class) +@RunWith(RobolectricTestRunner.class) public class BridgelessReactContextTest { private Context mContext; diff --git a/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/bridgeless/ReactHostDelegateTest.kt b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/bridgeless/ReactHostDelegateTest.kt new file mode 100644 index 00000000000000..19aefb0df07763 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/bridgeless/ReactHostDelegateTest.kt @@ -0,0 +1,53 @@ +/* + * 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. + */ + +package com.facebook.react.bridgeless + +import com.facebook.react.ReactPackage +import com.facebook.react.bridge.JSBundleLoader +import com.facebook.react.common.annotations.UnstableReactNativeAPI +import com.facebook.react.fabric.ReactNativeConfig +import com.facebook.react.turbomodule.core.TurboModuleManagerDelegate +import com.facebook.testutils.shadows.ShadowSoLoader +import org.assertj.core.api.Assertions.assertThat +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mockito +import org.robolectric.RobolectricTestRunner +import org.robolectric.annotation.Config + +@RunWith(RobolectricTestRunner::class) +@OptIn(UnstableReactNativeAPI::class) +@Config(shadows = [ShadowSoLoader::class]) +class ReactHostDelegateTest { + + /** Mock test for ReactInstanceDelegate, used to setup the process to create a stable API */ + @Test + fun testReactInstanceDelegateCreation() { + val jsBundleLoader: JSBundleLoader = Mockito.mock(JSBundleLoader::class.java) + val reactPackage: ReactPackage = Mockito.mock(ReactPackage::class.java) + val bindingsInstallerMock: BindingsInstaller = Mockito.mock(BindingsInstaller::class.java) + val turboModuleManagerDelegateMock: TurboModuleManagerDelegate = + Mockito.mock(TurboModuleManagerDelegate::class.java) + val jsEngineInstanceMock: JSEngineInstance = Mockito.mock(JSEngineInstance::class.java) + val reactNativeConfigMock: ReactNativeConfig = Mockito.mock(ReactNativeConfig::class.java) + val reactPackages = listOf(reactPackage) + val jsMainModulePathMocked = "mockedJSMainModulePath" + val delegate = + ReactHostDelegate.ReactHostDelegateBase( + jsMainModulePathMocked, + jsBundleLoader = jsBundleLoader, + reactPackages = reactPackages, + bindingsInstaller = bindingsInstallerMock, + jsEngineInstance = jsEngineInstanceMock, + reactNativeConfig = reactNativeConfigMock, + turboModuleManagerDelegate = turboModuleManagerDelegateMock, + exceptionHandler = {}) + + assertThat(delegate.jSMainModulePath).isEqualTo(jsMainModulePathMocked) + } +} diff --git a/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/bridgeless/ReactHostTest.java b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/bridgeless/ReactHostTest.java index 9b41fc683ed22e..7ce2af4a1ade2d 100644 --- a/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/bridgeless/ReactHostTest.java +++ b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/bridgeless/ReactHostTest.java @@ -17,18 +17,16 @@ import static org.powermock.api.mockito.PowerMockito.whenNew; import android.app.Activity; -import bolts.TaskCompletionSource; import com.facebook.react.MemoryPressureRouter; import com.facebook.react.bridge.JSBundleLoader; import com.facebook.react.bridge.MemoryPressureListener; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.UIManager; +import com.facebook.react.bridgeless.internal.bolts.TaskCompletionSource; import com.facebook.react.devsupport.interfaces.PackagerStatusCallback; import com.facebook.react.fabric.ComponentFactory; import com.facebook.react.uimanager.events.BlackHoleEventDispatcher; import com.facebook.react.uimanager.events.EventDispatcher; -import com.facebook.testing.robolectric.v4.WithTestDefaultsRunner; -import com.facebook.ultralight.testing.MockitoWithUltralightAutoMockSupport; import org.junit.Before; import org.junit.Ignore; import org.junit.Rule; @@ -40,11 +38,12 @@ import org.powermock.core.classloader.annotations.SuppressStaticInitializationFor; import org.powermock.modules.junit4.rule.PowerMockRule; import org.robolectric.Robolectric; +import org.robolectric.RobolectricTestRunner; import org.robolectric.android.controller.ActivityController; /** Tests {@linkcom.facebook.react.bridgeless.ReactHost} */ @SuppressStaticInitializationFor("com.facebook.react.fabric.ComponentFactory") -@RunWith(WithTestDefaultsRunner.class) +@RunWith(RobolectricTestRunner.class) @PowerMockIgnore({ "org.mockito.*", "org.robolectric.*", @@ -53,9 +52,10 @@ "javax.net.ssl.*" }) @PrepareForTest({ReactHost.class, ComponentFactory.class}) -public class ReactHostTest extends MockitoWithUltralightAutoMockSupport { +@Ignore("Ignore for now as these tests fail in OSS only") +public class ReactHostTest { - private ReactInstanceDelegate mReactInstanceDelegate; + private ReactHostDelegate mReactHostDelegate; private ReactInstance mReactInstance; private MemoryPressureRouter mMemoryPressureRouter; private BridgelessDevSupportManager mDevSupportManager; @@ -71,9 +71,8 @@ public void setUp() throws Exception { initMocks(this); mActivityController = Robolectric.buildActivity(Activity.class).create().start().resume(); - initializeNiceMockInjector(mActivityController.get()); - mReactInstanceDelegate = mock(ReactInstanceDelegate.class); + mReactHostDelegate = mock(ReactHostDelegate.class); mReactInstance = mock(ReactInstance.class); mMemoryPressureRouter = mock(MemoryPressureRouter.class); mDevSupportManager = mock(BridgelessDevSupportManager.class); @@ -85,13 +84,13 @@ public void setUp() throws Exception { whenNew(BridgelessDevSupportManager.class).withAnyArguments().thenReturn(mDevSupportManager); doReturn(mJSBundleLoader) - .when(mReactInstanceDelegate) + .when(mReactHostDelegate) .getJSBundleLoader(ArgumentMatchers.any()); mReactHost = new ReactHost( mActivityController.get().getApplication(), - mReactInstanceDelegate, + mReactHostDelegate, mComponentFactory, false, null, diff --git a/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/bridgeless/ReactSurfaceTest.java b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/bridgeless/ReactSurfaceTest.java index df3edd4c3ce0a0..aeba7ffe654698 100644 --- a/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/bridgeless/ReactSurfaceTest.java +++ b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/bridgeless/ReactSurfaceTest.java @@ -18,11 +18,10 @@ import android.app.Activity; import android.content.Context; import android.view.View; -import bolts.Task; import com.facebook.react.bridge.NativeMap; +import com.facebook.react.bridgeless.internal.bolts.Task; import com.facebook.react.fabric.SurfaceHandler; import com.facebook.react.uimanager.events.EventDispatcher; -import com.facebook.testing.robolectric.v4.WithTestDefaultsRunner; import java.util.concurrent.Callable; import org.junit.Before; import org.junit.Test; @@ -32,10 +31,11 @@ import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import org.robolectric.Robolectric; +import org.robolectric.RobolectricTestRunner; -@RunWith(WithTestDefaultsRunner.class) +@RunWith(RobolectricTestRunner.class) public class ReactSurfaceTest { - @Mock ReactInstanceDelegate mReactInstanceDelegate; + @Mock ReactHostDelegate mReactHostDelegate; @Mock EventDispatcher mEventDispatcher; private ReactHost mReactHost; @@ -49,7 +49,7 @@ public void setUp() { mContext = Robolectric.buildActivity(Activity.class).create().get(); - mReactHost = spy(new ReactHost(mContext, mReactInstanceDelegate, null, false, null, false)); + mReactHost = spy(new ReactHost(mContext, mReactHostDelegate, null, false, null, false)); doAnswer(mockedStartSurface()).when(mReactHost).startSurface(any(ReactSurface.class)); doAnswer(mockedStartSurface()).when(mReactHost).prerenderSurface(any(ReactSurface.class)); doAnswer(mockedStopSurface()).when(mReactHost).stopSurface(any(ReactSurface.class)); diff --git a/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/fabric/interop/FakeEventDispatcher.java b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/fabric/interop/FakeEventDispatcher.java new file mode 100644 index 00000000000000..f747845b1533e4 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/fabric/interop/FakeEventDispatcher.java @@ -0,0 +1,55 @@ +/* + * 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. + */ + +package com.facebook.react.fabric.interop; + +import com.facebook.react.uimanager.events.BatchEventDispatchedListener; +import com.facebook.react.uimanager.events.Event; +import com.facebook.react.uimanager.events.EventDispatcher; +import com.facebook.react.uimanager.events.EventDispatcherListener; +import com.facebook.react.uimanager.events.RCTEventEmitter; +import com.facebook.react.uimanager.events.RCTModernEventEmitter; +import java.util.ArrayList; +import java.util.List; + +@SuppressWarnings("rawtypes") +public class FakeEventDispatcher implements EventDispatcher { + + List recordedDispatchedEvents = new ArrayList<>(); + + @Override + public void dispatchEvent(Event event) { + recordedDispatchedEvents.add(event); + } + + @Override + public void dispatchAllEvents() {} + + @Override + public void addListener(EventDispatcherListener listener) {} + + @Override + public void removeListener(EventDispatcherListener listener) {} + + @Override + public void addBatchEventDispatchedListener(BatchEventDispatchedListener listener) {} + + @Override + public void removeBatchEventDispatchedListener(BatchEventDispatchedListener listener) {} + + @Override + public void registerEventEmitter(int uiManagerType, RCTEventEmitter eventEmitter) {} + + @Override + public void registerEventEmitter(int uiManagerType, RCTModernEventEmitter eventEmitter) {} + + @Override + public void unregisterEventEmitter(int uiManagerType) {} + + @Override + public void onCatalystInstanceDestroyed() {} +} diff --git a/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/fabric/interop/InteropEventEmitterTest.java b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/fabric/interop/InteropEventEmitterTest.java new file mode 100644 index 00000000000000..c26e9b36ac13fd --- /dev/null +++ b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/fabric/interop/InteropEventEmitterTest.java @@ -0,0 +1,66 @@ +/* + * 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. + */ + +package com.facebook.react.fabric.interop; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import com.facebook.react.bridge.JavaOnlyMap; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReactContext; +import com.facebook.react.bridge.WritableMap; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; + +@RunWith(RobolectricTestRunner.class) +public class InteropEventEmitterTest { + + ReactContext mReactContext; + FakeEventDispatcher mEventDispatcher; + + @Before + public void setup() { + mReactContext = new ReactApplicationContext(RuntimeEnvironment.application); + mEventDispatcher = new FakeEventDispatcher(); + } + + @Test + public void receiveEvent_dispatchesCorrectly() { + InteropEventEmitter eventEmitter = new InteropEventEmitter(mReactContext); + eventEmitter.overrideEventDispatcher(mEventDispatcher); + + eventEmitter.receiveEvent(42, "onTest", null); + + assertEquals(1, mEventDispatcher.recordedDispatchedEvents.size()); + assertEquals("onTest", mEventDispatcher.recordedDispatchedEvents.get(0).getEventName()); + assertEquals(InteropEvent.class, mEventDispatcher.recordedDispatchedEvents.get(0).getClass()); + } + + @Test + public void receiveEvent_dataIsPreserved() { + InteropEventEmitter eventEmitter = new InteropEventEmitter(mReactContext); + eventEmitter.overrideEventDispatcher(mEventDispatcher); + WritableMap eventData = JavaOnlyMap.of("color", "indigo"); + + eventEmitter.receiveEvent(42, "onTest", eventData); + + InteropEvent event = (InteropEvent) mEventDispatcher.recordedDispatchedEvents.get(0); + WritableMap dispatchedEventData = event.getEventData(); + assertNotNull(dispatchedEventData); + assertEquals("indigo", dispatchedEventData.getString("color")); + } + + @Test(expected = UnsupportedOperationException.class) + public void receiveTouches_isNotSupported() { + InteropEventEmitter eventEmitter = new InteropEventEmitter(mReactContext); + eventEmitter.receiveTouches("a touch", null, null); + } +} diff --git a/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/uimanager/UIManagerModuleConstantsHelperTest.java b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/uimanager/UIManagerModuleConstantsHelperTest.java new file mode 100644 index 00000000000000..78ba487e519c91 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/uimanager/UIManagerModuleConstantsHelperTest.java @@ -0,0 +1,89 @@ +/* + * 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. + */ + +package com.facebook.react.uimanager; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import com.facebook.react.common.MapBuilder; +import java.util.Map; +import org.junit.Test; + +public class UIManagerModuleConstantsHelperTest { + + @Test + public void normalizeEventTypes_withNull_doesNothing() { + UIManagerModuleConstantsHelper.normalizeEventTypes(null); + } + + @Test + public void normalizeEventTypes_withEmptyMap_doesNothing() { + Map emptyMap = MapBuilder.builder().build(); + + UIManagerModuleConstantsHelper.normalizeEventTypes(emptyMap); + + assertTrue(emptyMap.isEmpty()); + } + + @Test + public void normalizeEventTypes_withOnEvent_doesNormalize() { + Map onClickMap = MapBuilder.builder().put("onClick", "¯\\_(ツ)_/¯").build(); + + UIManagerModuleConstantsHelper.normalizeEventTypes(onClickMap); + + assertTrue(onClickMap.containsKey("topOnClick")); + assertTrue(onClickMap.containsKey("onClick")); + } + + @Test + public void normalizeEventTypes_withTopEvent_doesNormalize() { + Map onClickMap = MapBuilder.builder().put("topOnClick", "¯\\_(ツ)_/¯").build(); + + UIManagerModuleConstantsHelper.normalizeEventTypes(onClickMap); + + assertTrue(onClickMap.containsKey("topOnClick")); + assertFalse(onClickMap.containsKey("onClick")); + } + + @SuppressWarnings("unchecked") + @Test + public void normalizeEventTypes_withNestedObjects_doesNotLoseThem() { + Map nestedObjects = + MapBuilder.builder() + .put( + "onColorChanged", + MapBuilder.of( + "phasedRegistrationNames", + MapBuilder.of( + "bubbled", "onColorChanged", "captured", "onColorChangedCapture"))) + .build(); + + UIManagerModuleConstantsHelper.normalizeEventTypes(nestedObjects); + + assertTrue(nestedObjects.containsKey("topOnColorChanged")); + Map innerMap = (Map) nestedObjects.get("topOnColorChanged"); + assertNotNull(innerMap); + assertTrue(innerMap.containsKey("phasedRegistrationNames")); + Map innerInnerMap = + (Map) innerMap.get("phasedRegistrationNames"); + assertNotNull(innerInnerMap); + assertEquals("onColorChanged", innerInnerMap.get("bubbled")); + assertEquals("onColorChangedCapture", innerInnerMap.get("captured")); + + assertTrue(nestedObjects.containsKey("onColorChanged")); + innerMap = (Map) nestedObjects.get("topOnColorChanged"); + assertNotNull(innerMap); + assertTrue(innerMap.containsKey("phasedRegistrationNames")); + innerInnerMap = (Map) innerMap.get("phasedRegistrationNames"); + assertNotNull(innerInnerMap); + assertEquals("onColorChanged", innerInnerMap.get("bubbled")); + assertEquals("onColorChangedCapture", innerInnerMap.get("captured")); + } +} diff --git a/packages/react-native/ReactAndroid/src/test/resources/robolectric.properties b/packages/react-native/ReactAndroid/src/test/resources/robolectric.properties index b0d79302d02b6a..824645ee0384ff 100644 --- a/packages/react-native/ReactAndroid/src/test/resources/robolectric.properties +++ b/packages/react-native/ReactAndroid/src/test/resources/robolectric.properties @@ -1,2 +1,2 @@ # Set this to minimum supported API level for React Native. -sdk=21 +sdk=33 diff --git a/packages/react-native/ReactCommon/React-Fabric.podspec b/packages/react-native/ReactCommon/React-Fabric.podspec index 2f345d4fa861da..4102565442373e 100644 --- a/packages/react-native/ReactCommon/React-Fabric.podspec +++ b/packages/react-native/ReactCommon/React-Fabric.podspec @@ -47,6 +47,16 @@ Pod::Spec.new do |s| s.dependency "RCTTypeSafety", version s.dependency "ReactCommon/turbomodule/core", version s.dependency "React-jsi", version + s.dependency "React-logger" + s.dependency "glog" + s.dependency "DoubleConversion" + s.dependency "React-Core" + + if ENV["USE_HERMES"] == nil || ENV["USE_HERMES"] == "1" + s.dependency "hermes-engine" + else + s.dependency "React-jsi" + end s.subspec "animations" do |ss| ss.dependency folly_dep_name, folly_version @@ -82,11 +92,12 @@ Pod::Spec.new do |s| "\"$(PODS_ROOT)/boost\"", "\"$(PODS_TARGET_SRCROOT)/ReactCommon\"", "\"$(PODS_ROOT)/RCT-Folly\"", + "\"$(PODS_ROOT)/Headers/Private/Yoga\"", + "\"$(PODS_TARGET_SRCROOT)\"", ] if ENV['USE_FRAMEWORKS'] header_search_path = header_search_path + [ - "\"$(PODS_TARGET_SRCROOT)\"", "\"$(PODS_ROOT)/DoubleConversion\"", "\"$(PODS_CONFIGURATION_BUILD_DIR)/React-Codegen/React_Codegen.framework/Headers\"", "\"$(PODS_CONFIGURATION_BUILD_DIR)/React-graphics/React_graphics.framework/Headers/react/renderer/graphics/platform/ios\"", @@ -120,21 +131,6 @@ Pod::Spec.new do |s| end s.subspec "components" do |ss| - ss.subspec "activityindicator" do |sss| - sss.dependency folly_dep_name, folly_version - sss.compiler_flags = folly_compiler_flags - sss.source_files = "react/renderer/components/activityindicator/**/*.{m,mm,cpp,h}" - sss.exclude_files = "react/renderer/components/activityindicator/tests" - sss.header_dir = "react/renderer/components/activityindicator" - end - - ss.subspec "image" do |sss| - sss.dependency folly_dep_name, folly_version - sss.compiler_flags = folly_compiler_flags - sss.source_files = "react/renderer/components/image/**/*.{m,mm,cpp,h}" - sss.exclude_files = "react/renderer/components/image/tests" - sss.header_dir = "react/renderer/components/image" - end ss.subspec "inputaccessory" do |sss| sss.dependency folly_dep_name, folly_version @@ -228,7 +224,7 @@ Pod::Spec.new do |s| sss.source_files = "react/renderer/components/view/**/*.{m,mm,cpp,h}" sss.exclude_files = "react/renderer/components/view/tests" sss.header_dir = "react/renderer/components/view" - + sss.pod_target_xcconfig = { "HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/Headers/Private/Yoga\"" } end end diff --git a/packages/react-native/ReactCommon/React-FabricImage.podspec b/packages/react-native/ReactCommon/React-FabricImage.podspec new file mode 100644 index 00000000000000..e5a4be90b50d90 --- /dev/null +++ b/packages/react-native/ReactCommon/React-FabricImage.podspec @@ -0,0 +1,87 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +require "json" + +package = JSON.parse(File.read(File.join(__dir__, "..", "package.json"))) +version = package['version'] + +source = { :git => 'https://github.com/facebook/react-native.git' } +if version == '1000.0.0' + # This is an unpublished version, use the latest commit hash of the react-native repo, which we’re presumably in. + source[:commit] = `git rev-parse HEAD`.strip if system("git rev-parse --git-dir > /dev/null 2>&1") +else + source[:tag] = "v#{version}" +end + +folly_compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -Wno-comma -Wno-shorten-64-to-32 -Wno-gnu-zero-variadic-macro-arguments' +folly_version = '2021.07.22.00' +folly_dep_name = 'RCT-Folly/Fabric' +boost_compiler_flags = '-Wno-documentation' +react_native_path = ".." + +header_search_path = [ + "\"$(PODS_ROOT)/boost\"", + "\"$(PODS_TARGET_SRCROOT)/ReactCommon\"", + "\"$(PODS_ROOT)/RCT-Folly\"", + "\"$(PODS_ROOT)/Headers/Private/Yoga\"", +] + +if ENV['USE_FRAMEWORKS'] + header_search_path = header_search_path + [ + "\"$(PODS_TARGET_SRCROOT)\"", + "\"$(PODS_ROOT)/DoubleConversion\"", + "\"$(PODS_CONFIGURATION_BUILD_DIR)/React-Codegen/React_Codegen.framework/Headers\"", + "\"$(PODS_CONFIGURATION_BUILD_DIR)/React-graphics/React_graphics.framework/Headers/react/renderer/graphics/platform/ios\"", + "\"${PODS_CONFIGURATION_BUILD_DIR}/React-Fabric/React_Fabric.framework/Headers/react/renderer/imagemanager/platform/ios\"", + "\"$(PODS_TARGET_SRCROOT)/react/renderer/textlayoutmanager/platform/ios\"", + "\"$(PODS_TARGET_SRCROOT)/react/renderer/components/textinput/iostextinput\"", + "\"${PODS_CONFIGURATION_BUILD_DIR}/React-Fabric/React_Fabric.framework/Headers\"" + ] +end + +Pod::Spec.new do |s| + s.name = "React-FabricImage" + s.version = version + s.summary = "Image Component for Fabric for React Native." + s.homepage = "https://reactnative.dev/" + s.license = package["license"] + s.author = "Meta Platforms, Inc. and its affiliates" + s.platforms = { :ios => min_ios_version_supported } + s.source = source + s.source_files = "react/renderer/components/image/**/*.{m,mm,cpp,h}" + s.exclude_files = "react/renderer/components/image/tests" + s.header_dir = "react/renderer/components/image" + s.compiler_flags = folly_compiler_flags + s.pod_target_xcconfig = { "USE_HEADERMAP" => "YES", + "CLANG_CXX_LANGUAGE_STANDARD" => "c++17", + "HEADER_SEARCH_PATHS" => header_search_path.join(" ") + } + + if ENV['USE_FRAMEWORKS'] + s.header_mappings_dir = './' + s.module_name = 'React_FabricImage' + end + + s.dependency folly_dep_name, folly_version + s.dependency "React-graphics", version + s.dependency "React-jsiexecutor", version + s.dependency "RCTRequired", version + s.dependency "RCTTypeSafety", version + s.dependency "ReactCommon/turbomodule/core", version + s.dependency "React-jsi", version + s.dependency "React-logger" + s.dependency "glog" + s.dependency "DoubleConversion" + s.dependency "React-ImageManager" + s.dependency "React-Fabric" + s.dependency "Yoga" + + if ENV["USE_HERMES"] == nil || ENV["USE_HERMES"] == "1" + s.dependency "hermes-engine" + else + s.dependency "React-jsi" + end +end diff --git a/packages/react-native/ReactCommon/callinvoker/ReactCommon/CallInvoker.h b/packages/react-native/ReactCommon/callinvoker/ReactCommon/CallInvoker.h index 30996e8f83d6cc..55aa865bfad717 100644 --- a/packages/react-native/ReactCommon/callinvoker/ReactCommon/CallInvoker.h +++ b/packages/react-native/ReactCommon/callinvoker/ReactCommon/CallInvoker.h @@ -12,8 +12,7 @@ #include "SchedulerPriority.h" -namespace facebook { -namespace react { +namespace facebook::react { using CallFunc = std::function; @@ -33,5 +32,4 @@ class CallInvoker { virtual ~CallInvoker() {} }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/callinvoker/ReactCommon/SchedulerPriority.h b/packages/react-native/ReactCommon/callinvoker/ReactCommon/SchedulerPriority.h index ffa14321ef8e11..6e6a0d62e579f6 100644 --- a/packages/react-native/ReactCommon/callinvoker/ReactCommon/SchedulerPriority.h +++ b/packages/react-native/ReactCommon/callinvoker/ReactCommon/SchedulerPriority.h @@ -9,8 +9,7 @@ #include -namespace facebook { -namespace react { +namespace facebook::react { enum class SchedulerPriority : int { ImmediatePriority = 1, @@ -20,5 +19,4 @@ enum class SchedulerPriority : int { IdlePriority = 5, }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/cxxreact/CxxModule.h b/packages/react-native/ReactCommon/cxxreact/CxxModule.h index a5a89f79423a40..c6af2bf9f1e0ca 100644 --- a/packages/react-native/ReactCommon/cxxreact/CxxModule.h +++ b/packages/react-native/ReactCommon/cxxreact/CxxModule.h @@ -16,13 +16,11 @@ using namespace std::placeholders; -namespace facebook { -namespace react { +namespace facebook::react { class Instance; -} -} // namespace facebook +} // namespace facebook::react namespace facebook { namespace xplat { diff --git a/packages/react-native/ReactCommon/cxxreact/CxxNativeModule.cpp b/packages/react-native/ReactCommon/cxxreact/CxxNativeModule.cpp index ef5c5ea532b670..53959a8112ac93 100644 --- a/packages/react-native/ReactCommon/cxxreact/CxxNativeModule.cpp +++ b/packages/react-native/ReactCommon/cxxreact/CxxNativeModule.cpp @@ -19,8 +19,7 @@ #include using facebook::xplat::module::CxxModule; -namespace facebook { -namespace react { +namespace facebook::react { std::function makeCallback( std::weak_ptr instance, @@ -257,5 +256,4 @@ void CxxNativeModule::lazyInit() { } } -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/cxxreact/CxxNativeModule.h b/packages/react-native/ReactCommon/cxxreact/CxxNativeModule.h index e9902132000e22..61d21cb14e00ef 100644 --- a/packages/react-native/ReactCommon/cxxreact/CxxNativeModule.h +++ b/packages/react-native/ReactCommon/cxxreact/CxxNativeModule.h @@ -14,8 +14,7 @@ #define RN_EXPORT __attribute__((visibility("default"))) #endif -namespace facebook { -namespace react { +namespace facebook::react { class Instance; class MessageQueueThread; @@ -66,5 +65,4 @@ class RN_EXPORT CxxNativeModule : public NativeModule { static bool shouldWarnOnUse_; }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/cxxreact/ErrorUtils.h b/packages/react-native/ReactCommon/cxxreact/ErrorUtils.h index d9e42f7d221fc6..aaf31b6502ab23 100644 --- a/packages/react-native/ReactCommon/cxxreact/ErrorUtils.h +++ b/packages/react-native/ReactCommon/cxxreact/ErrorUtils.h @@ -7,8 +7,7 @@ #include -namespace facebook { -namespace react { +namespace facebook::react { inline static void handleJSError(jsi::Runtime &runtime, const jsi::JSError &error, bool isFatal) { @@ -40,5 +39,4 @@ handleJSError(jsi::Runtime &runtime, const jsi::JSError &error, bool isFatal) { } } -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/cxxreact/Instance.cpp b/packages/react-native/ReactCommon/cxxreact/Instance.cpp index 71bb1512be2865..1dfa0e682a34b6 100644 --- a/packages/react-native/ReactCommon/cxxreact/Instance.cpp +++ b/packages/react-native/ReactCommon/cxxreact/Instance.cpp @@ -30,8 +30,7 @@ #include #include -namespace facebook { -namespace react { +namespace facebook::react { Instance::~Instance() { if (nativeToJsBridge_) { @@ -292,5 +291,4 @@ void Instance::JSCallInvoker::scheduleAsync(std::function &&work) { } } -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/cxxreact/Instance.h b/packages/react-native/ReactCommon/cxxreact/Instance.h index cf20a3529e5a86..567e72fc124a84 100644 --- a/packages/react-native/ReactCommon/cxxreact/Instance.h +++ b/packages/react-native/ReactCommon/cxxreact/Instance.h @@ -23,8 +23,7 @@ namespace folly { struct dynamic; } -namespace facebook { -namespace react { +namespace facebook::react { class JSBigString; class JSExecutorFactory; @@ -172,5 +171,4 @@ class RN_EXPORT Instance { std::make_shared(); }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/cxxreact/JSBigString.cpp b/packages/react-native/ReactCommon/cxxreact/JSBigString.cpp index 59e117c0818e5c..436aeec9e3a8e6 100644 --- a/packages/react-native/ReactCommon/cxxreact/JSBigString.cpp +++ b/packages/react-native/ReactCommon/cxxreact/JSBigString.cpp @@ -18,8 +18,7 @@ #include -namespace facebook { -namespace react { +namespace facebook::react { JSBigFileString::JSBigFileString(int fd, size_t size, off_t offset /*= 0*/) : m_fd{-1}, m_data{nullptr} { @@ -95,5 +94,4 @@ std::unique_ptr JSBigFileString::fromPath( return std::make_unique(fd, fileInfo.st_size); } -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/cxxreact/JSBigString.h b/packages/react-native/ReactCommon/cxxreact/JSBigString.h index 691bb1ac3ee5bf..79fdb666e3a71d 100644 --- a/packages/react-native/ReactCommon/cxxreact/JSBigString.h +++ b/packages/react-native/ReactCommon/cxxreact/JSBigString.h @@ -17,8 +17,7 @@ #endif #endif -namespace facebook { -namespace react { +namespace facebook::react { // JSExecutor functions sometimes take large strings, on the order of // megabytes. Copying these can be expensive. Introducing a @@ -133,5 +132,4 @@ class RN_EXPORT JSBigFileString : public JSBigString { mutable const char *m_data; // Pointer to the mmapped region. }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/cxxreact/JSBundleType.cpp b/packages/react-native/ReactCommon/cxxreact/JSBundleType.cpp index 8e6f17ab00822c..b869ceacf2928d 100644 --- a/packages/react-native/ReactCommon/cxxreact/JSBundleType.cpp +++ b/packages/react-native/ReactCommon/cxxreact/JSBundleType.cpp @@ -7,8 +7,7 @@ #include "JSBundleType.h" -namespace facebook { -namespace react { +namespace facebook::react { static uint32_t constexpr RAMBundleMagicNumber = 0xFB0BD1E5; @@ -38,5 +37,4 @@ bool isHermesBytecodeBundle(const BundleHeader &header) { return header.magic64 == HermesBCBundleMagicNumber; } -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/cxxreact/JSBundleType.h b/packages/react-native/ReactCommon/cxxreact/JSBundleType.h index 7a966a94b7e8f9..945e19c58ba82e 100644 --- a/packages/react-native/ReactCommon/cxxreact/JSBundleType.h +++ b/packages/react-native/ReactCommon/cxxreact/JSBundleType.h @@ -15,8 +15,7 @@ #define RN_EXPORT __attribute__((visibility("default"))) #endif -namespace facebook { -namespace react { +namespace facebook::react { /* * Scripts given to the JS Executors to run could be in any of the following @@ -71,5 +70,4 @@ RN_EXPORT const char *stringForScriptTag(const ScriptTag &tag); */ RN_EXPORT bool isHermesBytecodeBundle(const BundleHeader &header); -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/cxxreact/JSExecutor.cpp b/packages/react-native/ReactCommon/cxxreact/JSExecutor.cpp index 7f7bfd32e99037..dbca822cf190ce 100644 --- a/packages/react-native/ReactCommon/cxxreact/JSExecutor.cpp +++ b/packages/react-native/ReactCommon/cxxreact/JSExecutor.cpp @@ -13,8 +13,7 @@ #include -namespace facebook { -namespace react { +namespace facebook::react { std::string JSExecutor::getSyntheticBundlePath( uint32_t bundleId, @@ -35,5 +34,4 @@ double JSExecutor::performanceNow() { return duration / NANOSECONDS_IN_MILLISECOND; } -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/cxxreact/JSExecutor.h b/packages/react-native/ReactCommon/cxxreact/JSExecutor.h index 112426a1da4144..02dbf1928b71aa 100644 --- a/packages/react-native/ReactCommon/cxxreact/JSExecutor.h +++ b/packages/react-native/ReactCommon/cxxreact/JSExecutor.h @@ -17,8 +17,7 @@ #define RN_EXPORT __attribute__((visibility("default"))) #endif -namespace facebook { -namespace react { +namespace facebook::react { class JSBigString; class JSExecutor; @@ -142,5 +141,4 @@ class RN_EXPORT JSExecutor { static double performanceNow(); }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/cxxreact/JSIndexedRAMBundle.cpp b/packages/react-native/ReactCommon/cxxreact/JSIndexedRAMBundle.cpp index 5be7c1b446d1bd..f1d05a06b3ba46 100644 --- a/packages/react-native/ReactCommon/cxxreact/JSIndexedRAMBundle.cpp +++ b/packages/react-native/ReactCommon/cxxreact/JSIndexedRAMBundle.cpp @@ -12,8 +12,7 @@ #include #include -namespace facebook { -namespace react { +namespace facebook::react { std::function(std::string)> JSIndexedRAMBundle::buildFactory() { @@ -127,5 +126,4 @@ void JSIndexedRAMBundle::readBundle( readBundle(buffer, bytes); } -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/cxxreact/JSIndexedRAMBundle.h b/packages/react-native/ReactCommon/cxxreact/JSIndexedRAMBundle.h index a8aa34166ada38..8f5c548e916fb8 100644 --- a/packages/react-native/ReactCommon/cxxreact/JSIndexedRAMBundle.h +++ b/packages/react-native/ReactCommon/cxxreact/JSIndexedRAMBundle.h @@ -17,8 +17,7 @@ #define RN_EXPORT __attribute__((visibility("default"))) #endif -namespace facebook { -namespace react { +namespace facebook::react { class RN_EXPORT JSIndexedRAMBundle : public JSModulesUnbundle { public: @@ -69,5 +68,4 @@ class RN_EXPORT JSIndexedRAMBundle : public JSModulesUnbundle { std::unique_ptr m_startupCode; }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/cxxreact/JSModulesUnbundle.h b/packages/react-native/ReactCommon/cxxreact/JSModulesUnbundle.h index 56376758292f7d..85bf46a7714f56 100644 --- a/packages/react-native/ReactCommon/cxxreact/JSModulesUnbundle.h +++ b/packages/react-native/ReactCommon/cxxreact/JSModulesUnbundle.h @@ -13,8 +13,7 @@ #include -namespace facebook { -namespace react { +namespace facebook::react { class JSModulesUnbundle { /** @@ -44,5 +43,4 @@ class JSModulesUnbundle { JSModulesUnbundle(const JSModulesUnbundle &) = delete; }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/cxxreact/MessageQueueThread.h b/packages/react-native/ReactCommon/cxxreact/MessageQueueThread.h index 3313b1a0fd0554..b31f2168731f88 100644 --- a/packages/react-native/ReactCommon/cxxreact/MessageQueueThread.h +++ b/packages/react-native/ReactCommon/cxxreact/MessageQueueThread.h @@ -11,8 +11,7 @@ #include #include -namespace facebook { -namespace react { +namespace facebook::react { class MessageQueueThread { public: @@ -25,5 +24,4 @@ class MessageQueueThread { virtual void quitSynchronous() = 0; }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/cxxreact/MethodCall.cpp b/packages/react-native/ReactCommon/cxxreact/MethodCall.cpp index c5e068195d3ec0..463a31ee510b52 100644 --- a/packages/react-native/ReactCommon/cxxreact/MethodCall.cpp +++ b/packages/react-native/ReactCommon/cxxreact/MethodCall.cpp @@ -10,8 +10,7 @@ #include #include -namespace facebook { -namespace react { +namespace facebook::react { #define REQUEST_MODULE_IDS 0 #define REQUEST_METHOD_IDS 1 @@ -85,5 +84,4 @@ std::vector parseMethodCalls(folly::dynamic &&jsonData) { return methodCalls; } -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/cxxreact/MethodCall.h b/packages/react-native/ReactCommon/cxxreact/MethodCall.h index f2fad2f025694d..4394bcb8247ea2 100644 --- a/packages/react-native/ReactCommon/cxxreact/MethodCall.h +++ b/packages/react-native/ReactCommon/cxxreact/MethodCall.h @@ -13,8 +13,7 @@ #include -namespace facebook { -namespace react { +namespace facebook::react { struct MethodCall { int moduleId; @@ -32,5 +31,4 @@ struct MethodCall { /// \throws std::invalid_argument std::vector parseMethodCalls(folly::dynamic &&calls); -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/cxxreact/ModuleRegistry.cpp b/packages/react-native/ReactCommon/cxxreact/ModuleRegistry.cpp index 962a84e0bacebe..75f6a350c3669e 100644 --- a/packages/react-native/ReactCommon/cxxreact/ModuleRegistry.cpp +++ b/packages/react-native/ReactCommon/cxxreact/ModuleRegistry.cpp @@ -13,8 +13,7 @@ #include "NativeModule.h" #include "SystraceSection.h" -namespace facebook { -namespace react { +namespace facebook::react { namespace { @@ -236,5 +235,4 @@ MethodCallResult ModuleRegistry::callSerializableNativeHook( methodId, std::move(params)); } -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/cxxreact/ModuleRegistry.h b/packages/react-native/ReactCommon/cxxreact/ModuleRegistry.h index 55d9c0b6b045b3..a9b5555d1f5bbe 100644 --- a/packages/react-native/ReactCommon/cxxreact/ModuleRegistry.h +++ b/packages/react-native/ReactCommon/cxxreact/ModuleRegistry.h @@ -19,8 +19,7 @@ #define RN_EXPORT __attribute__((visibility("default"))) #endif -namespace facebook { -namespace react { +namespace facebook::react { class NativeModule; @@ -88,5 +87,4 @@ class RN_EXPORT ModuleRegistry { ModuleNotFoundCallback moduleNotFoundCallback_; }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/cxxreact/NativeModule.h b/packages/react-native/ReactCommon/cxxreact/NativeModule.h index 5fa439703e1282..211eefeb333dc1 100644 --- a/packages/react-native/ReactCommon/cxxreact/NativeModule.h +++ b/packages/react-native/ReactCommon/cxxreact/NativeModule.h @@ -13,8 +13,7 @@ #include #include -namespace facebook { -namespace react { +namespace facebook::react { struct MethodDescriptor { std::string name; @@ -41,5 +40,4 @@ class NativeModule { folly::dynamic &&args) = 0; }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/cxxreact/NativeToJsBridge.cpp b/packages/react-native/ReactCommon/cxxreact/NativeToJsBridge.cpp index ce54a90dea0afd..456bfca43d583f 100644 --- a/packages/react-native/ReactCommon/cxxreact/NativeToJsBridge.cpp +++ b/packages/react-native/ReactCommon/cxxreact/NativeToJsBridge.cpp @@ -32,8 +32,7 @@ using fbsystrace::FbSystraceAsyncFlow; #endif -namespace facebook { -namespace react { +namespace facebook::react { // This class manages calls from JS to native code. class JsToNativeBridge : public react::ExecutorDelegate { @@ -340,5 +339,4 @@ std::shared_ptr NativeToJsBridge::getDecoratedNativeCallInvoker( return std::make_shared(m_delegate, nativeInvoker); } -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/cxxreact/NativeToJsBridge.h b/packages/react-native/ReactCommon/cxxreact/NativeToJsBridge.h index b8ba6a69c331d0..13c358614e9bba 100644 --- a/packages/react-native/ReactCommon/cxxreact/NativeToJsBridge.h +++ b/packages/react-native/ReactCommon/cxxreact/NativeToJsBridge.h @@ -20,8 +20,7 @@ namespace folly { struct dynamic; } -namespace facebook { -namespace react { +namespace facebook::react { struct InstanceCallback; class JsToNativeBridge; @@ -132,5 +131,4 @@ class NativeToJsBridge { #endif }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/cxxreact/RAMBundleRegistry.cpp b/packages/react-native/ReactCommon/cxxreact/RAMBundleRegistry.cpp index 7946334dcdb149..ff3cd6b3cde72d 100644 --- a/packages/react-native/ReactCommon/cxxreact/RAMBundleRegistry.cpp +++ b/packages/react-native/ReactCommon/cxxreact/RAMBundleRegistry.cpp @@ -11,8 +11,7 @@ #include -namespace facebook { -namespace react { +namespace facebook::react { constexpr uint32_t RAMBundleRegistry::MAIN_BUNDLE_ID; @@ -74,5 +73,4 @@ JSModulesUnbundle *RAMBundleRegistry::getBundle(uint32_t bundleId) const { return m_bundles.at(bundleId).get(); } -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/cxxreact/RAMBundleRegistry.h b/packages/react-native/ReactCommon/cxxreact/RAMBundleRegistry.h index d310ef1f42c139..db6931ea2d2093 100644 --- a/packages/react-native/ReactCommon/cxxreact/RAMBundleRegistry.h +++ b/packages/react-native/ReactCommon/cxxreact/RAMBundleRegistry.h @@ -19,8 +19,7 @@ #define RN_EXPORT __attribute__((visibility("default"))) #endif -namespace facebook { -namespace react { +namespace facebook::react { class RN_EXPORT RAMBundleRegistry { public: @@ -52,5 +51,4 @@ class RN_EXPORT RAMBundleRegistry { std::unordered_map> m_bundles; }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/cxxreact/ReactMarker.cpp b/packages/react-native/ReactCommon/cxxreact/ReactMarker.cpp index c154fccc1cb61c..a84b8d71b3aae0 100644 --- a/packages/react-native/ReactCommon/cxxreact/ReactMarker.cpp +++ b/packages/react-native/ReactCommon/cxxreact/ReactMarker.cpp @@ -8,8 +8,7 @@ #include "ReactMarker.h" #include -namespace facebook { -namespace react { +namespace facebook::react { namespace ReactMarker { #if __clang__ @@ -85,5 +84,4 @@ double StartupLogger::getRunJSBundleEndTime() { } } // namespace ReactMarker -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/cxxreact/ReactMarker.h b/packages/react-native/ReactCommon/cxxreact/ReactMarker.h index e0640ae672c2d1..76b8e7a165e8dc 100644 --- a/packages/react-native/ReactCommon/cxxreact/ReactMarker.h +++ b/packages/react-native/ReactCommon/cxxreact/ReactMarker.h @@ -11,8 +11,7 @@ #include #endif -namespace facebook { -namespace react { +namespace facebook::react { namespace ReactMarker { enum ReactMarkerId { @@ -87,5 +86,4 @@ class StartupLogger { }; } // namespace ReactMarker -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/cxxreact/RecoverableError.h b/packages/react-native/ReactCommon/cxxreact/RecoverableError.h index 4ea9fa9f91ff51..3f01dd561a81fe 100644 --- a/packages/react-native/ReactCommon/cxxreact/RecoverableError.h +++ b/packages/react-native/ReactCommon/cxxreact/RecoverableError.h @@ -11,8 +11,7 @@ #include #include -namespace facebook { -namespace react { +namespace facebook::react { /** * RecoverableError @@ -46,5 +45,4 @@ struct RecoverableError : public std::exception { std::string m_what; }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/cxxreact/SystraceSection.h b/packages/react-native/ReactCommon/cxxreact/SystraceSection.h index 46996ff2bb74d9..f1579db8fc46c0 100644 --- a/packages/react-native/ReactCommon/cxxreact/SystraceSection.h +++ b/packages/react-native/ReactCommon/cxxreact/SystraceSection.h @@ -11,8 +11,7 @@ #include #endif -namespace facebook { -namespace react { +namespace facebook::react { /** * Allow providing an fbsystrace implementation that can short-circuit out @@ -57,5 +56,4 @@ struct DummySystraceSection { using SystraceSection = DummySystraceSection; #endif -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/hermes/executor/HermesExecutorFactory.cpp b/packages/react-native/ReactCommon/hermes/executor/HermesExecutorFactory.cpp index 9d68c8c5104d48..1b4f65e4eb8d2f 100644 --- a/packages/react-native/ReactCommon/hermes/executor/HermesExecutorFactory.cpp +++ b/packages/react-native/ReactCommon/hermes/executor/HermesExecutorFactory.cpp @@ -22,8 +22,7 @@ using namespace facebook::hermes; using namespace facebook::jsi; -namespace facebook { -namespace react { +namespace facebook::react { namespace { @@ -235,5 +234,4 @@ HermesExecutor::HermesExecutor( jsi::addNativeTracingHooks(*runtime); } -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/hermes/executor/HermesExecutorFactory.h b/packages/react-native/ReactCommon/hermes/executor/HermesExecutorFactory.h index d0d5352ba5450e..1be5b60e215c4a 100644 --- a/packages/react-native/ReactCommon/hermes/executor/HermesExecutorFactory.h +++ b/packages/react-native/ReactCommon/hermes/executor/HermesExecutorFactory.h @@ -12,8 +12,7 @@ #include #include -namespace facebook { -namespace react { +namespace facebook::react { class HermesExecutorFactory : public JSExecutorFactory { public: @@ -59,5 +58,4 @@ class HermesExecutor : public JSIExecutor { JSIScopedTimeoutInvoker timeoutInvoker_; }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/jsc/JSCRuntime.cpp b/packages/react-native/ReactCommon/jsc/JSCRuntime.cpp index 7958519e683f6d..fea1d0bc2d33c7 100644 --- a/packages/react-native/ReactCommon/jsc/JSCRuntime.cpp +++ b/packages/react-native/ReactCommon/jsc/JSCRuntime.cpp @@ -1240,6 +1240,11 @@ jsi::Function JSCRuntime::createFunctionFromHostFunction( exceptionString += ex.what(); *exception = makeError(rt, exceptionString); res = JSValueMakeUndefined(ctx); + } catch (const std::string &ex) { + std::string exceptionString("Exception in HostFunction: "); + exceptionString += ex; + *exception = makeError(rt, exceptionString); + res = JSValueMakeUndefined(ctx); } catch (...) { std::string exceptionString("Exception in HostFunction: "); *exception = makeError(rt, exceptionString); diff --git a/packages/react-native/ReactCommon/jserrorhandler/JsErrorHandler.cpp b/packages/react-native/ReactCommon/jserrorhandler/JsErrorHandler.cpp index 0902e68b2b1644..8b25ff1e95b45d 100644 --- a/packages/react-native/ReactCommon/jserrorhandler/JsErrorHandler.cpp +++ b/packages/react-native/ReactCommon/jserrorhandler/JsErrorHandler.cpp @@ -12,8 +12,7 @@ #include #include -namespace facebook { -namespace react { +namespace facebook::react { using facebook::react::JSErrorHandlerKey; @@ -103,5 +102,4 @@ void JsErrorHandler::handleJsError(const jsi::JSError &error, bool isFatal) { _jsErrorHandlingFunc(std::move(errorMap)); } -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/jserrorhandler/JsErrorHandler.h b/packages/react-native/ReactCommon/jserrorhandler/JsErrorHandler.h index d0bc25c908855b..a188169a670e1b 100644 --- a/packages/react-native/ReactCommon/jserrorhandler/JsErrorHandler.h +++ b/packages/react-native/ReactCommon/jserrorhandler/JsErrorHandler.h @@ -10,8 +10,7 @@ #include #include -namespace facebook { -namespace react { +namespace facebook::react { enum JSErrorHandlerKey : uint16_t { kFrameFileName = 0, @@ -37,5 +36,4 @@ class JsErrorHandler { JsErrorHandlingFunc _jsErrorHandlingFunc; }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/jsiexecutor/jsireact/JSIExecutor.cpp b/packages/react-native/ReactCommon/jsiexecutor/jsireact/JSIExecutor.cpp index 3e72ed8e25bb80..ec882e3da73a85 100644 --- a/packages/react-native/ReactCommon/jsiexecutor/jsireact/JSIExecutor.cpp +++ b/packages/react-native/ReactCommon/jsiexecutor/jsireact/JSIExecutor.cpp @@ -24,8 +24,7 @@ using namespace facebook::jsi; -namespace facebook { -namespace react { +namespace facebook::react { class JSIExecutor::NativeModuleProxy : public jsi::HostObject { public: @@ -579,5 +578,4 @@ void bindNativePerformanceNow(Runtime &runtime) { size_t count) { return Value(JSExecutor::performanceNow()); })); } -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/jsiexecutor/jsireact/JSIExecutor.h b/packages/react-native/ReactCommon/jsiexecutor/jsireact/JSIExecutor.h index c17a052e866d90..d5101df849f93b 100644 --- a/packages/react-native/ReactCommon/jsiexecutor/jsireact/JSIExecutor.h +++ b/packages/react-native/ReactCommon/jsiexecutor/jsireact/JSIExecutor.h @@ -17,8 +17,7 @@ #include #include -namespace facebook { -namespace react { +namespace facebook::react { // A JSIScopedTimeoutInvoker is a trampoline-type function for introducing // timeouts. Call the TimeoutInvoker with a function to execute, the invokee. @@ -140,5 +139,4 @@ void bindNativeLogger(jsi::Runtime &runtime, Logger logger); void bindNativePerformanceNow(jsi::Runtime &runtime); double performanceNow(); -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/jsiexecutor/jsireact/JSINativeModules.cpp b/packages/react-native/ReactCommon/jsiexecutor/jsireact/JSINativeModules.cpp index de51c93dcbfb9a..15919802a43157 100644 --- a/packages/react-native/ReactCommon/jsiexecutor/jsireact/JSINativeModules.cpp +++ b/packages/react-native/ReactCommon/jsiexecutor/jsireact/JSINativeModules.cpp @@ -18,8 +18,7 @@ using namespace facebook::jsi; -namespace facebook { -namespace react { +namespace facebook::react { JSINativeModules::JSINativeModules( std::shared_ptr moduleRegistry) @@ -103,5 +102,4 @@ std::optional JSINativeModules::createModule( return module; } -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/jsiexecutor/jsireact/JSINativeModules.h b/packages/react-native/ReactCommon/jsiexecutor/jsireact/JSINativeModules.h index fd769a703b40c0..365158f620715d 100644 --- a/packages/react-native/ReactCommon/jsiexecutor/jsireact/JSINativeModules.h +++ b/packages/react-native/ReactCommon/jsiexecutor/jsireact/JSINativeModules.h @@ -14,8 +14,7 @@ #include #include -namespace facebook { -namespace react { +namespace facebook::react { /** * Holds and creates JS representations of the modules in ModuleRegistry @@ -36,5 +35,4 @@ class JSINativeModules { const std::string &name); }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/jsinspector/InspectorInterfaces.cpp b/packages/react-native/ReactCommon/jsinspector/InspectorInterfaces.cpp index fbd38e13e3df53..dc02471b9cd018 100644 --- a/packages/react-native/ReactCommon/jsinspector/InspectorInterfaces.cpp +++ b/packages/react-native/ReactCommon/jsinspector/InspectorInterfaces.cpp @@ -11,8 +11,7 @@ #include #include -namespace facebook { -namespace react { +namespace facebook::react { // pure destructors in C++ are odd. You would think they don't want an // implementation, but in fact the linker requires one. Define them to be @@ -104,5 +103,4 @@ std::unique_ptr makeTestInspectorInstance() { return std::make_unique(); } -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/jsinspector/InspectorInterfaces.h b/packages/react-native/ReactCommon/jsinspector/InspectorInterfaces.h index 77fd6e1d546a10..115a56382c8fd9 100644 --- a/packages/react-native/ReactCommon/jsinspector/InspectorInterfaces.h +++ b/packages/react-native/ReactCommon/jsinspector/InspectorInterfaces.h @@ -24,8 +24,7 @@ #endif // _MSC_VER #endif // !defined(JSINSPECTOR_EXPORT) -namespace facebook { -namespace react { +namespace facebook::react { class IDestructible { public: @@ -90,5 +89,4 @@ extern IInspector &getInspectorInstance(); /// should only be used in tests. extern std::unique_ptr makeTestInspectorInstance(); -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/bridgeless/BindingsInstaller.h b/packages/react-native/ReactCommon/react/bridgeless/BindingsInstaller.h index 3d02fd90c3accc..fc3d889a553e41 100644 --- a/packages/react-native/ReactCommon/react/bridgeless/BindingsInstaller.h +++ b/packages/react-native/ReactCommon/react/bridgeless/BindingsInstaller.h @@ -9,8 +9,7 @@ #include -namespace facebook { -namespace react { +namespace facebook::react { class BindingsInstaller { public: @@ -18,5 +17,5 @@ class BindingsInstaller { return nullptr; } }; -} // namespace react -} // namespace facebook + +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/bridgeless/README.md b/packages/react-native/ReactCommon/react/bridgeless/README.md new file mode 100644 index 00000000000000..31b0a095904cc4 --- /dev/null +++ b/packages/react-native/ReactCommon/react/bridgeless/README.md @@ -0,0 +1,3 @@ +# Bridgeless Mode for iOS + +This library is not ready for integration for production nor local experimentation. Expect breaking changes regularly if you use any of these APIs. Use at your own risk! diff --git a/packages/react-native/ReactCommon/react/bridgeless/ReactInstance.cpp b/packages/react-native/ReactCommon/react/bridgeless/ReactInstance.cpp index 701780b6c55b59..07edae1f8dcc00 100644 --- a/packages/react-native/ReactCommon/react/bridgeless/ReactInstance.cpp +++ b/packages/react-native/ReactCommon/react/bridgeless/ReactInstance.cpp @@ -155,6 +155,12 @@ static void defineReadOnlyGlobal( jsi::Runtime &runtime, std::string propName, jsi::Value &&value) { + if (runtime.global().hasProperty(runtime, propName.c_str())) { + throw jsi::JSError( + runtime, + "Tried to redefine read-only global \"" + propName + + "\", but read-only globals can only be defined once."); + } jsi::Object jsObject = runtime.global().getProperty(runtime, "Object").asObject(runtime); jsi::Function defineProperty = jsObject.getProperty(runtime, "defineProperty") diff --git a/packages/react-native/ReactCommon/react/bridgeless/ReactInstance.h b/packages/react-native/ReactCommon/react/bridgeless/ReactInstance.h index ee43ae9b7ff4a2..880c642a0eaf7d 100644 --- a/packages/react-native/ReactCommon/react/bridgeless/ReactInstance.h +++ b/packages/react-native/ReactCommon/react/bridgeless/ReactInstance.h @@ -7,9 +7,9 @@ #pragma once -#include #include #include +#include #include #include #include diff --git a/packages/react-native/ReactCommon/react/bridgeless/platform/ios/Core/ObjCTimerRegistry.h b/packages/react-native/ReactCommon/react/bridgeless/platform/ios/Core/ObjCTimerRegistry.h new file mode 100644 index 00000000000000..60219eb7211c98 --- /dev/null +++ b/packages/react-native/ReactCommon/react/bridgeless/platform/ios/Core/ObjCTimerRegistry.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +#import +#import +#import +#import + +@interface RCTJSTimerExecutor : NSObject + +- (void)setTimerManager:(std::weak_ptr)timerManager FB_OBJC_DIRECT; + +@end + +class ObjCTimerRegistry : public facebook::react::PlatformTimerRegistry { + public: + ObjCTimerRegistry(); + void createTimer(uint32_t timerID, double delayMS) override; + void deleteTimer(uint32_t timerID) override; + void createRecurringTimer(uint32_t timerID, double delayMS) override; + void setTimerManager(std::weak_ptr timerManager); + RCTTiming *_Null_unspecified timing; + + private: + RCTJSTimerExecutor *_Null_unspecified jsTimerExecutor_; + double toSeconds(double ms); +}; diff --git a/packages/react-native/ReactCommon/react/bridgeless/platform/ios/Core/ObjCTimerRegistry.mm b/packages/react-native/ReactCommon/react/bridgeless/platform/ios/Core/ObjCTimerRegistry.mm new file mode 100644 index 00000000000000..194e9b22f14c89 --- /dev/null +++ b/packages/react-native/ReactCommon/react/bridgeless/platform/ios/Core/ObjCTimerRegistry.mm @@ -0,0 +1,73 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import "ObjCTimerRegistry.h" + +@implementation RCTJSTimerExecutor { + std::weak_ptr _timerManager; +} + +- (void)setTimerManager:(std::weak_ptr)timerManager +{ + _timerManager = timerManager; +} + +- (void)callTimers:(NSArray *)timers +{ + if (auto timerManager = _timerManager.lock()) { + for (NSNumber *timer in timers) { + timerManager->callTimer([timer unsignedIntValue]); + } + } +} + +- (void)immediatelyCallTimer:(nonnull NSNumber *)callbackID +{ + if (auto timerManager = _timerManager.lock()) { + timerManager->callTimer([callbackID unsignedIntValue]); + } +} + +- (void)callIdleCallbacks:(nonnull NSNumber *)absoluteFrameStartMS +{ + // TODO(T53992765)(petetheheat) - Implement this +} + +@end + +ObjCTimerRegistry::ObjCTimerRegistry() +{ + jsTimerExecutor_ = [RCTJSTimerExecutor new]; + timing = [[RCTTiming alloc] initWithDelegate:jsTimerExecutor_]; +} + +void ObjCTimerRegistry::createTimer(uint32_t timerID, double delayMS) +{ + [timing createTimerForNextFrame:@(timerID) duration:toSeconds(delayMS) jsSchedulingTime:nil repeats:NO]; +} + +void ObjCTimerRegistry::deleteTimer(uint32_t timerID) +{ + [timing deleteTimer:(double)timerID]; +} + +void ObjCTimerRegistry::createRecurringTimer(uint32_t timerID, double delayMS) +{ + [timing createTimerForNextFrame:@(timerID) duration:toSeconds(delayMS) jsSchedulingTime:nil repeats:YES]; +} + +void ObjCTimerRegistry::setTimerManager(std::weak_ptr timerManager) +{ + [jsTimerExecutor_ setTimerManager:timerManager]; +} + +// ObjC timing native module expects a NSTimeInterval which is always specified in seconds. JS expresses timer delay +// in ms. Perform a simple conversion here. +double ObjCTimerRegistry::toSeconds(double ms) +{ + return ms / 1000.0; +} diff --git a/packages/react-native/ReactCommon/react/bridgeless/platform/ios/Core/RCTHost+Internal.h b/packages/react-native/ReactCommon/react/bridgeless/platform/ios/Core/RCTHost+Internal.h new file mode 100644 index 00000000000000..7d3f5cf3e08bc7 --- /dev/null +++ b/packages/react-native/ReactCommon/react/bridgeless/platform/ios/Core/RCTHost+Internal.h @@ -0,0 +1,14 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import "RCTHost.h" + +@interface RCTHost (Internal) + +- (void)registerSegmentWithId:(NSNumber *)segmentId path:(NSString *)path; + +@end diff --git a/packages/react-native/ReactCommon/react/bridgeless/platform/ios/Core/RCTHost.h b/packages/react-native/ReactCommon/react/bridgeless/platform/ios/Core/RCTHost.h new file mode 100644 index 00000000000000..603e795f1778ed --- /dev/null +++ b/packages/react-native/ReactCommon/react/bridgeless/platform/ios/Core/RCTHost.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +#import +#import +#import +#import +#import + +#import "RCTInstance.h" + +NS_ASSUME_NONNULL_BEGIN + +@class RCTFabricSurface; +@class RCTHost; +@class RCTJSThreadManager; +@class RCTModuleRegistry; +@protocol RCTInstanceDelegate; +FB_RUNTIME_PROTOCOL +@protocol RCTTurboModuleManagerDelegate; + +/** + * This notification fires just before RCTHost releases it's RCTInstance reference. + */ +RCT_EXTERN NSString *const RCTHostWillReloadNotification; + +/** + * This notification fires just after RCTHost releases it's RCTInstance reference. + */ +RCT_EXTERN NSString *const RCTHostDidReloadNotification; + +typedef std::shared_ptr (^RCTHostJSEngineProvider)(void); + +@protocol RCTHostDelegate + +- (std::shared_ptr)getJSEngine; +- (NSURL *)getBundleURL; +- (std::shared_ptr)createContextContainer; + +- (void)host:(RCTHost *)host + didReceiveJSErrorStack:(NSArray *> *)stack + message:(NSString *)message + exceptionId:(NSUInteger)exceptionId + isFatal:(BOOL)isFatal; + +@end + +/** + * RCTHost is an object which is responsible for managing the lifecycle of a single RCTInstance. + * RCTHost is long lived, while an instance may be deallocated and re-initialized. Some examples of when this happens: + * CMD+R reload in DEV or a JS crash. The host should be the single owner of an RCTInstance. + */ +@interface RCTHost : NSObject + +- (instancetype)initWithHostDelegate:(id)hostDelegate + turboModuleManagerDelegate:(id)turboModuleManagerDelegate + bindingsInstallFunc:(facebook::react::ReactInstance::BindingsInstallFunc)bindingsInstallFunc + jsEngineProvider:(nullable RCTHostJSEngineProvider)jsEngineProvider NS_DESIGNATED_INITIALIZER + FB_OBJC_DIRECT; + +/** + * This function initializes an RCTInstance if one does not yet exist. This function is currently only called on the + * main thread, but it should be threadsafe. + * TODO T74233481 - Verify if this function is threadsafe. + */ +- (void)preload; + +- (RCTFabricSurface *)createSurfaceWithModuleName:(NSString *)moduleName + mode:(facebook::react::DisplayMode)displayMode + initialProperties:(NSDictionary *)properties FB_OBJC_DIRECT; + +- (RCTFabricSurface *)createSurfaceWithModuleName:(NSString *)moduleName + initialProperties:(NSDictionary *)properties FB_OBJC_DIRECT; + +- (RCTModuleRegistry *)getModuleRegistry FB_OBJC_DIRECT; + +- (RCTSurfacePresenter *)getSurfacePresenter FB_OBJC_DIRECT; + +/** + * Calls a method on a JS module that has been registered with `registerCallableModule`. Used to invoke a JS function + * from platform code. + */ +- (void)callFunctionOnJSModule:(NSString *)moduleName method:(NSString *)method args:(NSArray *)args; + +@end + +NS_ASSUME_NONNULL_END diff --git a/packages/react-native/ReactCommon/react/bridgeless/platform/ios/Core/RCTHost.mm b/packages/react-native/ReactCommon/react/bridgeless/platform/ios/Core/RCTHost.mm new file mode 100644 index 00000000000000..7826069b1a7838 --- /dev/null +++ b/packages/react-native/ReactCommon/react/bridgeless/platform/ios/Core/RCTHost.mm @@ -0,0 +1,311 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import "RCTHost.h" +#import "RCTHost+Internal.h" + +#import +#import +#import +#import +#import +#import +#import +#import +#import + +using namespace facebook::react; + +NSString *const RCTHostWillReloadNotification = @"RCTHostWillReloadNotification"; +NSString *const RCTHostDidReloadNotification = @"RCTHostDidReloadNotification"; + +@interface RCTHost () +@end + +@implementation RCTHost { + RCTInstance *_instance; + __weak id _hostDelegate; + __weak id _turboModuleManagerDelegate; + NSURL *_oldDelegateBundleURL; + NSURL *_bundleURL; + RCTBundleManager *_bundleManager; + facebook::react::ReactInstance::BindingsInstallFunc _bindingsInstallFunc; + RCTHostJSEngineProvider _jsEngineProvider; + + // All the surfaces that need to be started after main bundle execution + NSMutableArray *_surfaceStartBuffer; + std::mutex _surfaceStartBufferMutex; + + RCTInstanceInitialBundleLoadCompletionBlock _onInitialBundleLoad; + std::vector<__weak RCTFabricSurface *> _attachedSurfaces; + + RCTModuleRegistry *_moduleRegistry; +} + ++ (void)initialize +{ + _RCTInitializeJSThreadConstantInternal(); +} + +/** + Host initialization should not be resource intensive. A host may be created before any intention of using React Native + has been expressed. + */ +- (instancetype)initWithHostDelegate:(id)hostDelegate + turboModuleManagerDelegate:(id)turboModuleManagerDelegate + bindingsInstallFunc:(facebook::react::ReactInstance::BindingsInstallFunc)bindingsInstallFunc + jsEngineProvider:(nullable RCTHostJSEngineProvider)jsEngineProvider +{ + if (self = [super init]) { + _hostDelegate = hostDelegate; + _turboModuleManagerDelegate = turboModuleManagerDelegate; + _surfaceStartBuffer = [NSMutableArray new]; + _bundleManager = [RCTBundleManager new]; + _bindingsInstallFunc = bindingsInstallFunc; + _moduleRegistry = [RCTModuleRegistry new]; + _jsEngineProvider = [jsEngineProvider copy]; + + __weak RCTHost *weakHost = self; + + auto bundleURLGetter = ^NSURL *() + { + RCTHost *strongHost = weakHost; + if (!strongHost) { + return nil; + } + + return strongHost->_bundleURL; + }; + + auto bundleURLSetter = ^(NSURL *bundleURL) { + RCTHost *strongHost = weakHost; + if (!strongHost) { + return; + } + strongHost->_bundleURL = bundleURL; + }; + + auto defaultBundleURLGetter = ^NSURL *() + { + RCTHost *strongHost = weakHost; + if (!strongHost) { + return nil; + } + + return [strongHost->_hostDelegate getBundleURL]; + }; + + [_bundleManager setBridgelessBundleURLGetter:bundleURLGetter + andSetter:bundleURLSetter + andDefaultGetter:defaultBundleURLGetter]; + + /** + * TODO (T108401473) Remove _onInitialBundleLoad, because it was initially + * introduced to start surfaces after the main JSBundle was fully executed. + * It is no longer needed because Fabric now dispatches all native-to-JS calls + * onto the JS thread, including JS calls to start Fabric surfaces. + * JS calls should be dispatched using the BufferedRuntimeExecutor, which can buffer + * JS calls before the main JSBundle finishes execution, and execute them after. + */ + _onInitialBundleLoad = ^{ + RCTHost *strongHost = weakHost; + if (!strongHost) { + return; + } + + NSArray *unstartedSurfaces = @[]; + + { + std::lock_guard guard{strongHost->_surfaceStartBufferMutex}; + unstartedSurfaces = [NSArray arrayWithArray:strongHost->_surfaceStartBuffer]; + strongHost->_surfaceStartBuffer = nil; + } + + for (RCTFabricSurface *surface in unstartedSurfaces) { + [surface start]; + } + }; + + // Listen to reload commands + dispatch_async(dispatch_get_main_queue(), ^{ + RCTRegisterReloadCommandListener(self); + }); + } + return self; +} + +#pragma mark - Public + +- (void)preload +{ + if (_instance) { + RCTLogWarn( + @"RCTHost should not be creating a new instance if one already exists. This implies there is a bug with how/when this method is being called."); + [_instance invalidate]; + } + [self _refreshBundleURL]; + RCTReloadCommandSetBundleURL(_bundleURL); + _instance = + [[RCTInstance alloc] initWithDelegate:self + jsEngineInstance:_jsEngineProvider ? _jsEngineProvider() : [_hostDelegate getJSEngine] + bundleManager:_bundleManager + turboModuleManagerDelegate:_turboModuleManagerDelegate + onInitialBundleLoad:_onInitialBundleLoad + bindingsInstallFunc:_bindingsInstallFunc + moduleRegistry:_moduleRegistry]; +} + +- (RCTFabricSurface *)createSurfaceWithModuleName:(NSString *)moduleName + mode:(DisplayMode)displayMode + initialProperties:(NSDictionary *)properties +{ + RCTFabricSurface *surface = [[RCTFabricSurface alloc] initWithSurfacePresenter:[self getSurfacePresenter] + moduleName:moduleName + initialProperties:properties]; + surface.surfaceHandler.setDisplayMode(displayMode); + [self _attachSurface:surface]; + + { + std::lock_guard guard{_surfaceStartBufferMutex}; + if (_surfaceStartBuffer) { + [_surfaceStartBuffer addObject:surface]; + return surface; + } + } + + [surface start]; + return surface; +} + +- (RCTFabricSurface *)createSurfaceWithModuleName:(NSString *)moduleName initialProperties:(NSDictionary *)properties +{ + return [self createSurfaceWithModuleName:moduleName mode:DisplayMode::Visible initialProperties:properties]; +} + +- (RCTModuleRegistry *)getModuleRegistry +{ + return _moduleRegistry; +} + +- (RCTSurfacePresenter *)getSurfacePresenter +{ + return [_instance surfacePresenter]; +} + +- (void)callFunctionOnJSModule:(NSString *)moduleName method:(NSString *)method args:(NSArray *)args +{ + [_instance callFunctionOnJSModule:moduleName method:method args:args]; +} + +#pragma mark - RCTReloadListener + +- (void)didReceiveReloadCommand +{ + [[NSNotificationCenter defaultCenter] + postNotification:[NSNotification notificationWithName:RCTHostWillReloadNotification object:nil]]; + [_instance invalidate]; + _instance = nil; + [self _refreshBundleURL]; + RCTReloadCommandSetBundleURL(_bundleURL); + + // Ensure all attached surfaces are restarted after reload + { + std::lock_guard guard{_surfaceStartBufferMutex}; + _surfaceStartBuffer = [NSMutableArray arrayWithArray:[self _getAttachedSurfaces]]; + } + + _instance = + [[RCTInstance alloc] initWithDelegate:self + jsEngineInstance:_jsEngineProvider ? _jsEngineProvider() : [_hostDelegate getJSEngine] + bundleManager:_bundleManager + turboModuleManagerDelegate:_turboModuleManagerDelegate + onInitialBundleLoad:_onInitialBundleLoad + bindingsInstallFunc:_bindingsInstallFunc + moduleRegistry:_moduleRegistry]; + [[NSNotificationCenter defaultCenter] + postNotification:[NSNotification notificationWithName:RCTHostDidReloadNotification object:nil]]; + + for (RCTFabricSurface *surface in [self _getAttachedSurfaces]) { + [surface resetWithSurfacePresenter:[self getSurfacePresenter]]; + } +} + +- (void)dealloc +{ + [_instance invalidate]; +} + +#pragma mark - RCTInstanceDelegate + +- (std::shared_ptr)createContextContainer +{ + return [_hostDelegate createContextContainer]; +} + +- (void)instance:(RCTInstance *)instance didReceiveErrorMap:(facebook::react::MapBuffer)errorMap +{ + NSString *message = [NSString stringWithCString:errorMap.getString(JSErrorHandlerKey::kErrorMessage).c_str() + encoding:[NSString defaultCStringEncoding]]; + std::vector frames = errorMap.getMapBufferList(JSErrorHandlerKey::kAllStackFrames); + NSMutableArray *> *stack = [NSMutableArray new]; + for (facebook::react::MapBuffer const &mapBuffer : frames) { + NSDictionary *frame = @{ + @"file" : [NSString stringWithCString:mapBuffer.getString(JSErrorHandlerKey::kFrameFileName).c_str() + encoding:[NSString defaultCStringEncoding]], + @"methodName" : [NSString stringWithCString:mapBuffer.getString(JSErrorHandlerKey::kFrameMethodName).c_str() + encoding:[NSString defaultCStringEncoding]], + @"lineNumber" : [NSNumber numberWithInt:mapBuffer.getInt(JSErrorHandlerKey::kFrameLineNumber)], + @"column" : [NSNumber numberWithInt:mapBuffer.getInt(JSErrorHandlerKey::kFrameColumnNumber)], + }; + [stack addObject:frame]; + } + [_hostDelegate host:self + didReceiveJSErrorStack:stack + message:message + exceptionId:errorMap.getInt(JSErrorHandlerKey::kExceptionId) + isFatal:errorMap.getBool(JSErrorHandlerKey::kIsFatal)]; +} + +#pragma mark - Internal + +- (void)registerSegmentWithId:(NSNumber *)segmentId path:(NSString *)path +{ + [_instance registerSegmentWithId:segmentId path:path]; +} + +#pragma mark - Private +- (void)_refreshBundleURL FB_OBJC_DIRECT +{ + // Reset the _bundleURL ivar if the RCTHost delegate presents a new bundleURL + NSURL *newDelegateBundleURL = [_hostDelegate getBundleURL]; + if (newDelegateBundleURL && ![newDelegateBundleURL isEqual:_oldDelegateBundleURL]) { + _oldDelegateBundleURL = newDelegateBundleURL; + _bundleURL = newDelegateBundleURL; + } + + // Sanitize the bundle URL + _bundleURL = [RCTConvert NSURL:_bundleURL.absoluteString]; +} + +- (void)_attachSurface:(RCTFabricSurface *)surface FB_OBJC_DIRECT +{ + _attachedSurfaces.push_back(surface); +} + +- (NSArray *)_getAttachedSurfaces FB_OBJC_DIRECT +{ + NSMutableArray *surfaces = [NSMutableArray new]; + for (RCTFabricSurface *surface : _attachedSurfaces) { + if (surface) { + [surfaces addObject:surface]; + } + } + + return surfaces; +} + +@end diff --git a/packages/react-native/ReactCommon/react/bridgeless/platform/ios/Core/RCTHostCreationHelpers.h b/packages/react-native/ReactCommon/react/bridgeless/platform/ios/Core/RCTHostCreationHelpers.h new file mode 100644 index 00000000000000..5006e14ef0c63a --- /dev/null +++ b/packages/react-native/ReactCommon/react/bridgeless/platform/ios/Core/RCTHostCreationHelpers.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import +#import + +#import "RCTHost.h" + +@class RCTHost; + +@protocol RCTHostDelegate; +@protocol RCTTurboModuleManagerDelegate; + +NS_ASSUME_NONNULL_BEGIN + +RCT_EXTERN_C_BEGIN + +RCTHost *RCTHostCreateDefault( + id hostDelegate, + id turboModuleManagerDelegate, + RCTHostJSEngineProvider jsEngineProvider); + +RCT_EXTERN_C_END + +NS_ASSUME_NONNULL_END diff --git a/packages/react-native/ReactCommon/react/bridgeless/platform/ios/Core/RCTHostCreationHelpers.mm b/packages/react-native/ReactCommon/react/bridgeless/platform/ios/Core/RCTHostCreationHelpers.mm new file mode 100644 index 00000000000000..31d1af728d2691 --- /dev/null +++ b/packages/react-native/ReactCommon/react/bridgeless/platform/ios/Core/RCTHostCreationHelpers.mm @@ -0,0 +1,19 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import "RCTHostCreationHelpers.h" + +RCTHost *RCTHostCreateDefault( + id hostDelegate, + id turboModuleManagerDelegate, + RCTHostJSEngineProvider jsEngineProvider) +{ + return [[RCTHost alloc] initWithHostDelegate:hostDelegate + turboModuleManagerDelegate:turboModuleManagerDelegate + bindingsInstallFunc:nullptr + jsEngineProvider:jsEngineProvider]; +} diff --git a/packages/react-native/ReactCommon/react/bridgeless/platform/ios/Core/RCTInstance.h b/packages/react-native/ReactCommon/react/bridgeless/platform/ios/Core/RCTInstance.h new file mode 100644 index 00000000000000..90ed79d9b117e0 --- /dev/null +++ b/packages/react-native/ReactCommon/react/bridgeless/platform/ios/Core/RCTInstance.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +#import +#import +#import +#import +#import +#import + +/** + * A utility to enable diagnostics mode at runtime. Useful for test runs. + * The flags are comma-separated string tokens, or an empty string when + * nothing is enabled. + */ +RCT_EXTERN NSString *RCTInstanceRuntimeDiagnosticFlags(void); +RCT_EXTERN void RCTInstanceSetRuntimeDiagnosticFlags(NSString *flags); + +NS_ASSUME_NONNULL_BEGIN + +@class RCTBundleManager; +@class RCTInstance; +@class RCTJSThreadManager; +@class RCTModuleRegistry; +@class RCTPerformanceLogger; +@class RCTSource; +@class RCTSurfacePresenter; + +FB_RUNTIME_PROTOCOL +@protocol RCTTurboModuleManagerDelegate; + +@protocol RCTInstanceDelegate + +- (std::shared_ptr)createContextContainer; + +- (void)instance:(RCTInstance *)instance didReceiveErrorMap:(facebook::react::MapBuffer)errorMap; + +@end + +typedef void (^_Null_unspecified RCTInstanceInitialBundleLoadCompletionBlock)(); + +/** + * RCTInstance owns and manages most of the pieces of infrastructure required to display a screen powered by React + * Native. RCTInstance should never be instantiated in product code, but rather accessed through RCTHost. The host + * ensures that any access to the instance is safe, and manages instance lifecycle. + */ +@interface RCTInstance : NSObject + +- (instancetype)initWithDelegate:(id)delegate + jsEngineInstance:(std::shared_ptr)jsEngineInstance + bundleManager:(RCTBundleManager *)bundleManager + turboModuleManagerDelegate:(id)turboModuleManagerDelegate + onInitialBundleLoad:(RCTInstanceInitialBundleLoadCompletionBlock)onInitialBundleLoad + bindingsInstallFunc:(facebook::react::ReactInstance::BindingsInstallFunc)bindingsInstallFunc + moduleRegistry:(RCTModuleRegistry *)moduleRegistry FB_OBJC_DIRECT; + +- (void)callFunctionOnJSModule:(NSString *)moduleName method:(NSString *)method args:(NSArray *)args; + +- (void)registerSegmentWithId:(NSNumber *)segmentId path:(NSString *)path; + +- (void)invalidate; + +@property (nonatomic, readonly, strong) RCTSurfacePresenter *surfacePresenter; + +@end + +NS_ASSUME_NONNULL_END diff --git a/packages/react-native/ReactCommon/react/bridgeless/platform/ios/Core/RCTInstance.mm b/packages/react-native/ReactCommon/react/bridgeless/platform/ios/Core/RCTInstance.mm new file mode 100644 index 00000000000000..5839e202d2b0b7 --- /dev/null +++ b/packages/react-native/ReactCommon/react/bridgeless/platform/ios/Core/RCTInstance.mm @@ -0,0 +1,418 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import "RCTInstance.h" + +#import + +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import + +#import "ObjCTimerRegistry.h" +#import "RCTJSThreadManager.h" +#import "RCTPerformanceLoggerUtils.h" + +#if RCT_DEV_MENU && __has_include() +#import +#import +#endif + +using namespace facebook; +using namespace facebook::react; + +static NSString *sRuntimeDiagnosticFlags = nil; +NSString *RCTInstanceRuntimeDiagnosticFlags(void) +{ + return sRuntimeDiagnosticFlags ? [sRuntimeDiagnosticFlags copy] : [NSString new]; +} + +void RCTInstanceSetRuntimeDiagnosticFlags(NSString *flags) +{ + if (!flags) { + return; + } + sRuntimeDiagnosticFlags = [flags copy]; +} + +@interface RCTInstance () +@end + +@implementation RCTInstance { + std::unique_ptr _reactInstance; + std::shared_ptr _jsEngineInstance; + __weak id _appTMMDelegate; + __weak id _delegate; + RCTSurfacePresenter *_surfacePresenter; + RCTPerformanceLogger *_performanceLogger; + RCTDisplayLink *_displayLink; + RCTInstanceInitialBundleLoadCompletionBlock _onInitialBundleLoad; + ReactInstance::BindingsInstallFunc _bindingsInstallFunc; + RCTTurboModuleManager *_turboModuleManager; + std::mutex _invalidationMutex; + std::atomic _valid; + RCTJSThreadManager *_jsThreadManager; + + // APIs supporting interop with native modules and view managers + RCTBridgeModuleDecorator *_bridgeModuleDecorator; +} + +#pragma mark - Public + +- (instancetype)initWithDelegate:(id)delegate + jsEngineInstance:(std::shared_ptr)jsEngineInstance + bundleManager:(RCTBundleManager *)bundleManager + turboModuleManagerDelegate:(id)tmmDelegate + onInitialBundleLoad:(RCTInstanceInitialBundleLoadCompletionBlock)onInitialBundleLoad + bindingsInstallFunc:(ReactInstance::BindingsInstallFunc)bindingsInstallFunc + moduleRegistry:(RCTModuleRegistry *)moduleRegistry +{ + if (self = [super init]) { + _performanceLogger = [RCTPerformanceLogger new]; + registerPerformanceLoggerHooks(_performanceLogger); + [_performanceLogger markStartForTag:RCTPLReactInstanceInit]; + + _delegate = delegate; + _jsEngineInstance = jsEngineInstance; + _appTMMDelegate = tmmDelegate; + _jsThreadManager = [RCTJSThreadManager new]; + _onInitialBundleLoad = onInitialBundleLoad; + _bindingsInstallFunc = bindingsInstallFunc; + _bridgeModuleDecorator = [[RCTBridgeModuleDecorator alloc] initWithViewRegistry:[RCTViewRegistry new] + moduleRegistry:moduleRegistry + bundleManager:bundleManager + callableJSModules:[RCTCallableJSModules new]]; + { + __weak __typeof(self) weakInstance = self; + [_bridgeModuleDecorator.callableJSModules + setBridgelessJSModuleMethodInvoker:^( + NSString *moduleName, NSString *methodName, NSArray *args, dispatch_block_t onComplete) { + // TODO: Make RCTInstance call onComplete + [weakInstance callFunctionOnJSModule:moduleName method:methodName args:args]; + }]; + } + + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(_notifyEventDispatcherObserversOfEvent_DEPRECATED:) + name:@"RCTNotifyEventDispatcherObserversOfEvent_DEPRECATED" + object:nil]; + + [self _start]; + } + return self; +} + +- (void)callFunctionOnJSModule:(NSString *)moduleName method:(NSString *)method args:(NSArray *)args +{ + if (_valid) { + _reactInstance->callFunctionOnModule( + [moduleName UTF8String], [method UTF8String], convertIdToFollyDynamic(args ?: @[])); + } +} + +- (void)invalidate +{ + std::lock_guard lock(_invalidationMutex); + _valid = false; + + [_surfacePresenter suspend]; + [_jsThreadManager dispatchToJSThread:^{ + /** + * Every TurboModule is invalidated on its own method queue. + * TurboModuleManager invalidate blocks the calling thread until all TurboModules are invalidated. + */ + [self->_turboModuleManager invalidate]; + + // Clean up all the Resources + self->_reactInstance = nullptr; + self->_jsEngineInstance = nullptr; + self->_appTMMDelegate = nil; + self->_delegate = nil; + self->_displayLink = nil; + + self->_turboModuleManager = nil; + self->_performanceLogger = nil; + + // Terminate the JavaScript thread, so that no other work executes after this block. + self->_jsThreadManager = nil; + }]; +} + +- (void)registerSegmentWithId:(NSNumber *)segmentId path:(NSString *)path +{ + if (_valid) { + _reactInstance->registerSegment(static_cast([segmentId unsignedIntValue]), path.UTF8String); + } +} + +#pragma mark - RCTTurboModuleManagerDelegate + +- (Class)getModuleClassFromName:(const char *)name +{ + if ([_appTMMDelegate respondsToSelector:@selector(getModuleClassFromName:)]) { + return [_appTMMDelegate getModuleClassFromName:name]; + } + + return nil; +} + +- (id)getModuleInstanceFromClass:(Class)moduleClass +{ + if ([_appTMMDelegate respondsToSelector:@selector(getModuleInstanceFromClass:)]) { + id module = [_appTMMDelegate getModuleInstanceFromClass:moduleClass]; + [self _attachBridgelessAPIsToModule:module]; + return module; + } + + return nil; +} + +- (std::shared_ptr)getTurboModule:(const std::string &)name + jsInvoker:(std::shared_ptr)jsInvoker +{ + if ([_appTMMDelegate respondsToSelector:@selector(getTurboModule:jsInvoker:)]) { + return [_appTMMDelegate getTurboModule:name jsInvoker:jsInvoker]; + } + + return nullptr; +} + +#pragma mark - Private + +- (void)_start +{ + // Set up timers + auto objCTimerRegistry = std::make_unique(); + auto timing = objCTimerRegistry->timing; + auto *objCTimerRegistryRawPtr = objCTimerRegistry.get(); + + auto timerManager = std::make_shared(std::move(objCTimerRegistry)); + objCTimerRegistryRawPtr->setTimerManager(timerManager); + + __weak __typeof(self) weakSelf = self; + auto jsErrorHandlingFunc = [=](MapBuffer errorMap) { [weakSelf _handleJSErrorMap:std::move(errorMap)]; }; + + // Create the React Instance + _reactInstance = std::make_unique( + _jsEngineInstance->createJSRuntime(), _jsThreadManager.jsMessageThread, timerManager, jsErrorHandlingFunc); + _valid = true; + + RuntimeExecutor bufferedRuntimeExecutor = _reactInstance->getBufferedRuntimeExecutor(); + timerManager->setRuntimeExecutor(bufferedRuntimeExecutor); + + // Set up TurboModules + _turboModuleManager = + [[RCTTurboModuleManager alloc] initWithBridge:nil + delegate:self + jsInvoker:std::make_shared(bufferedRuntimeExecutor)]; + + // Initialize RCTModuleRegistry so that TurboModules can require other TurboModules. + [_bridgeModuleDecorator.moduleRegistry setTurboModuleRegistry:_turboModuleManager]; + + RCTLogSetBridgelessModuleRegistry(_bridgeModuleDecorator.moduleRegistry); + RCTLogSetBridgelessCallableJSModules(_bridgeModuleDecorator.callableJSModules); + + auto contextContainer = [_delegate createContextContainer]; + contextContainer->insert( + "RCTImageLoader", facebook::react::wrapManagedObject([_turboModuleManager moduleForName:"RCTImageLoader"])); + contextContainer->insert( + "RCTEventDispatcher", + facebook::react::wrapManagedObject([_turboModuleManager moduleForName:"RCTEventDispatcher"])); + contextContainer->insert("RCTBridgeModuleDecorator", facebook::react::wrapManagedObject(_bridgeModuleDecorator)); + contextContainer->insert("RuntimeScheduler", std::weak_ptr(_reactInstance->getRuntimeScheduler())); + + _surfacePresenter = [[RCTSurfacePresenter alloc] + initWithContextContainer:contextContainer + runtimeExecutor:bufferedRuntimeExecutor + bridgelessBindingsExecutor:std::optional(_reactInstance->getUnbufferedRuntimeExecutor())]; + + // This enables RCTViewRegistry in modules to return UIViews from its viewForReactTag method + __weak RCTSurfacePresenter *weakSurfacePresenter = _surfacePresenter; + [_bridgeModuleDecorator.viewRegistry_DEPRECATED setBridgelessComponentViewProvider:^UIView *(NSNumber *reactTag) { + RCTSurfacePresenter *strongSurfacePresenter = weakSurfacePresenter; + if (strongSurfacePresenter == nil) { + return nil; + } + + return [strongSurfacePresenter findComponentViewWithTag_DO_NOT_USE_DEPRECATED:reactTag.integerValue]; + }]; + + // DisplayLink is used to call timer callbacks. + _displayLink = [RCTDisplayLink new]; + + ReactInstance::JSRuntimeFlags options = { + .isProfiling = false, .runtimeDiagnosticFlags = [RCTInstanceRuntimeDiagnosticFlags() UTF8String]}; + _reactInstance->initializeRuntime(options, [=](jsi::Runtime &runtime) { + __strong __typeof(self) strongSelf = weakSelf; + if (!strongSelf) { + return; + } + + facebook::react::RuntimeExecutor syncRuntimeExecutor = + [&](std::function &&callback) { callback(runtime); }; + [strongSelf->_turboModuleManager installJSBindingWithRuntimeExecutor:syncRuntimeExecutor]; + facebook::react::bindNativeLogger(runtime, [](const std::string &message, unsigned int logLevel) { + _RCTLogJavaScriptInternal(static_cast(logLevel), [NSString stringWithUTF8String:message.c_str()]); + }); + RCTInstallNativeComponentRegistryBinding(runtime); + + if (strongSelf->_bindingsInstallFunc) { + strongSelf->_bindingsInstallFunc(runtime); + } + + // Set up Display Link + RCTModuleData *timingModuleData = [[RCTModuleData alloc] initWithModuleInstance:timing + bridge:nil + moduleRegistry:nil + viewRegistry_DEPRECATED:nil + bundleManager:nil + callableJSModules:nil]; + [strongSelf->_displayLink registerModuleForFrameUpdates:timing withModuleData:timingModuleData]; + [strongSelf->_displayLink addToRunLoop:[NSRunLoop currentRunLoop]]; + + // Attempt to load bundle synchronously, fallback to asynchronously. + [strongSelf->_performanceLogger markStartForTag:RCTPLScriptDownload]; + [strongSelf _loadJSBundle:[strongSelf->_bridgeModuleDecorator.bundleManager bundleURL]]; + }); + + [_performanceLogger markStopForTag:RCTPLReactInstanceInit]; +} + +- (void)_attachBridgelessAPIsToModule:(id)module FB_OBJC_DIRECT +{ + __weak RCTInstance *weakInstance = self; + if ([module respondsToSelector:@selector(setDispatchToJSThread:)]) { + ((id)module).dispatchToJSThread = ^(dispatch_block_t block) { + __strong __typeof(self) strongSelf = weakInstance; + + if (strongSelf && strongSelf->_valid) { + strongSelf->_reactInstance->getBufferedRuntimeExecutor()([=](jsi::Runtime &runtime) { block(); }); + } + }; + } + + if ([module respondsToSelector:@selector(setSurfacePresenter:)]) { + [module performSelector:@selector(setSurfacePresenter:) withObject:_surfacePresenter]; + } + + // Replaces bridge.isInspectable + if ([module respondsToSelector:@selector(setIsInspectable:)]) { +#if RCT_DEV_MENU + if (_valid) { + _reactInstance->getBufferedRuntimeExecutor()([module](jsi::Runtime &runtime) { + ((id)module).isInspectable = runtime.isInspectable(); + }); + } +#endif + } + + [_bridgeModuleDecorator attachInteropAPIsToModule:(id)module]; +} + +- (void)_loadJSBundle:(NSURL *)sourceURL FB_OBJC_DIRECT +{ +#if RCT_DEV_MENU && __has_include() + { + id loadingView = + (id)[_turboModuleManager moduleForName:"DevLoadingView"]; + [loadingView showWithURL:sourceURL]; + } +#endif + + __weak __typeof(self) weakSelf = self; + [RCTJavaScriptLoader loadBundleAtURL:sourceURL + onProgress:^(RCTLoadingProgress *progressData) { + __typeof(self) strongSelf = weakSelf; + if (!strongSelf) { + return; + } + +#if RCT_DEV_MENU && __has_include() + id loadingView = + (id)[strongSelf->_turboModuleManager moduleForName:"DevLoadingView"]; + [loadingView updateProgress:progressData]; +#endif + } + onComplete:^(NSError *error, RCTSource *source) { + __typeof(self) strongSelf = weakSelf; + if (!strongSelf) { + return; + } + + if (error) { + // TODO(T91461138): Properly address bundle loading errors. + RCTLogError(@"RCTInstance: Error while loading bundle: %@", error); + [strongSelf invalidate]; + return; + } + // DevSettings module is needed by _loadScriptFromSource's callback so prior initialization is required + RCTDevSettings *const devSettings = + (RCTDevSettings *)[strongSelf->_turboModuleManager moduleForName:"DevSettings"]; + [strongSelf _loadScriptFromSource:source]; + // Set up hot module reloading in Dev only. + [strongSelf->_performanceLogger markStopForTag:RCTPLScriptDownload]; + [devSettings setupHMRClientWithBundleURL:sourceURL]; + }]; +} + +- (void)_loadScriptFromSource:(RCTSource *)source FB_OBJC_DIRECT +{ + std::lock_guard lock(_invalidationMutex); + if (!_valid) { + return; + } + + auto script = std::make_unique(source.data); + const auto *url = deriveSourceURL(source.url).UTF8String; + _reactInstance->loadScript(std::move(script), url); + [[NSNotificationCenter defaultCenter] postNotificationName:@"RCTInstanceDidLoadBundle" object:nil]; + + if (_onInitialBundleLoad) { + _onInitialBundleLoad(); + _onInitialBundleLoad = nil; + } +} + +- (void)_notifyEventDispatcherObserversOfEvent_DEPRECATED:(NSNotification *)notification +{ + NSDictionary *userInfo = notification.userInfo; + id event = [userInfo objectForKey:@"event"]; + + RCTModuleRegistry *moduleRegistry = _bridgeModuleDecorator.moduleRegistry; + if (event && moduleRegistry) { + id legacyEventDispatcher = [moduleRegistry moduleForName:"EventDispatcher" + lazilyLoadIfNecessary:YES]; + [legacyEventDispatcher notifyObserversOfEvent:event]; + } +} + +- (void)_handleJSErrorMap:(facebook::react::MapBuffer)errorMap +{ + [_delegate instance:self didReceiveErrorMap:std::move(errorMap)]; +} + +@end diff --git a/packages/react-native/ReactCommon/react/bridgeless/platform/ios/Core/RCTJSThreadManager.h b/packages/react-native/ReactCommon/react/bridgeless/platform/ios/Core/RCTJSThreadManager.h new file mode 100644 index 00000000000000..3fd4edda7bc9f7 --- /dev/null +++ b/packages/react-native/ReactCommon/react/bridgeless/platform/ios/Core/RCTJSThreadManager.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface RCTJSThreadManager : NSObject + +- (void)dispatchToJSThread:(dispatch_block_t)block FB_OBJC_DIRECT; +- (std::shared_ptr)jsMessageThread FB_OBJC_DIRECT; + +@end + +NS_ASSUME_NONNULL_END diff --git a/packages/react-native/ReactCommon/react/bridgeless/platform/ios/Core/RCTJSThreadManager.mm b/packages/react-native/ReactCommon/react/bridgeless/platform/ios/Core/RCTJSThreadManager.mm new file mode 100644 index 00000000000000..20fcfce9414381 --- /dev/null +++ b/packages/react-native/ReactCommon/react/bridgeless/platform/ios/Core/RCTJSThreadManager.mm @@ -0,0 +1,125 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import "RCTJSThreadManager.h" + +#import +#import +#import + +static NSString *const RCTJSThreadName = @"com.facebook.react.bridgeless.JavaScript"; + +#define RCTAssertJSThread() \ + RCTAssert(self->_jsThread == [NSThread currentThread], @"This method must be called on JS thread") + +@implementation RCTJSThreadManager { + NSThread *_jsThread; + std::shared_ptr _jsMessageThread; +} + +- (instancetype)init +{ + if (self = [super init]) { + [self startJSThread]; + __weak RCTJSThreadManager *weakSelf = self; + + dispatch_block_t captureJSThreadRunLoop = ^(void) { + __strong RCTJSThreadManager *strongSelf = weakSelf; + strongSelf->_jsMessageThread = + std::make_shared([NSRunLoop currentRunLoop], ^(NSError *error) { + if (error) { + [weakSelf _handleError:error]; + } + }); + }; + + [self performSelector:@selector(_tryAndHandleError:) + onThread:_jsThread + withObject:captureJSThreadRunLoop + waitUntilDone:YES]; + } + return self; +} + +- (std::shared_ptr)jsMessageThread +{ + return _jsMessageThread; +} + +- (void)dealloc +{ + // This avoids a race condition, where work can be executed on JS thread after + // other peices of infra are cleaned up. + _jsMessageThread->quitSynchronous(); +} + +#pragma mark - JSThread Management + +- (void)startJSThread FB_OBJC_DIRECT +{ + _jsThread = [[NSThread alloc] initWithTarget:[self class] selector:@selector(runRunLoop) object:nil]; + _jsThread.name = RCTJSThreadName; + _jsThread.qualityOfService = NSOperationQualityOfServiceUserInteractive; +#if RCT_DEBUG + _jsThread.stackSize *= 2; +#endif + [_jsThread start]; +} + +/** + * Ensure block is run on the JS thread. If we're already on the JS thread, the block will execute synchronously. + * If we're not on the JS thread, the block is dispatched to that thread. + */ +- (void)dispatchToJSThread:(dispatch_block_t)block +{ + RCTAssert(_jsThread, @"This method must not be called before the JS thread is created"); + + if ([NSThread currentThread] == _jsThread) { + [self _tryAndHandleError:block]; + } else { + __weak __typeof(self) weakSelf = self; + _jsMessageThread->runOnQueue([weakSelf, block] { [weakSelf _tryAndHandleError:block]; }); + } +} + ++ (void)runRunLoop +{ + @autoreleasepool { + // copy thread name to pthread name + pthread_setname_np([NSThread currentThread].name.UTF8String); + + // Set up a dummy runloop source to avoid spinning + CFRunLoopSourceContext noSpinCtx = {0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; + CFRunLoopSourceRef noSpinSource = CFRunLoopSourceCreate(NULL, 0, &noSpinCtx); + CFRunLoopAddSource(CFRunLoopGetCurrent(), noSpinSource, kCFRunLoopDefaultMode); + CFRelease(noSpinSource); + + // run the run loop + while (kCFRunLoopRunStopped != + CFRunLoopRunInMode( + kCFRunLoopDefaultMode, ((NSDate *)[NSDate distantFuture]).timeIntervalSinceReferenceDate, NO)) { + RCTAssert(NO, @"not reached assertion"); // runloop spun. that's bad. + } + } +} + +#pragma mark - Private + +- (void)_handleError:(NSError *)error FB_OBJC_DIRECT +{ + RCTFatal(error); +} + +- (void)_tryAndHandleError:(dispatch_block_t)block +{ + NSError *error = facebook::react::tryAndReturnError(block); + if (error) { + [self _handleError:error]; + } +} + +@end diff --git a/packages/react-native/ReactCommon/react/bridgeless/platform/ios/Core/RCTPerformanceLoggerUtils.h b/packages/react-native/ReactCommon/react/bridgeless/platform/ios/Core/RCTPerformanceLoggerUtils.h new file mode 100644 index 00000000000000..85a86fc07f94c0 --- /dev/null +++ b/packages/react-native/ReactCommon/react/bridgeless/platform/ios/Core/RCTPerformanceLoggerUtils.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +@class RCTPerformanceLogger; + +NS_ASSUME_NONNULL_BEGIN + +extern void registerPerformanceLoggerHooks(RCTPerformanceLogger *performanceLogger); + +NS_ASSUME_NONNULL_END diff --git a/packages/react-native/ReactCommon/react/bridgeless/platform/ios/Core/RCTPerformanceLoggerUtils.mm b/packages/react-native/ReactCommon/react/bridgeless/platform/ios/Core/RCTPerformanceLoggerUtils.mm new file mode 100644 index 00000000000000..a8c20b83f46757 --- /dev/null +++ b/packages/react-native/ReactCommon/react/bridgeless/platform/ios/Core/RCTPerformanceLoggerUtils.mm @@ -0,0 +1,62 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import "RCTPerformanceLoggerUtils.h" + +#import +#import + +using namespace facebook::react; + +static void mapReactMarkerToPerformanceLogger( + const ReactMarker::ReactMarkerId markerId, + RCTPerformanceLogger *performanceLogger) +{ + switch (markerId) { + case ReactMarker::RUN_JS_BUNDLE_START: + [performanceLogger markStartForTag:RCTPLScriptExecution]; + break; + case ReactMarker::RUN_JS_BUNDLE_STOP: + [performanceLogger markStopForTag:RCTPLScriptExecution]; + break; + case ReactMarker::NATIVE_REQUIRE_START: + [performanceLogger appendStartForTag:RCTPLRAMNativeRequires]; + break; + case ReactMarker::NATIVE_REQUIRE_STOP: + [performanceLogger appendStopForTag:RCTPLRAMNativeRequires]; + [performanceLogger addValue:1 forTag:RCTPLRAMNativeRequiresCount]; + break; + case ReactMarker::NATIVE_MODULE_SETUP_START: + [performanceLogger markStartForTag:RCTPLNativeModuleSetup]; + break; + case ReactMarker::NATIVE_MODULE_SETUP_STOP: + [performanceLogger markStopForTag:RCTPLNativeModuleSetup]; + break; + case ReactMarker::REACT_INSTANCE_INIT_START: + [performanceLogger markStartForTag:RCTPLReactInstanceInit]; + break; + case ReactMarker::REACT_INSTANCE_INIT_STOP: + [performanceLogger markStopForTag:RCTPLReactInstanceInit]; + break; + case ReactMarker::CREATE_REACT_CONTEXT_STOP: + case ReactMarker::JS_BUNDLE_STRING_CONVERT_START: + case ReactMarker::JS_BUNDLE_STRING_CONVERT_STOP: + case ReactMarker::REGISTER_JS_SEGMENT_START: + case ReactMarker::REGISTER_JS_SEGMENT_STOP: + // These are not used on iOS. + break; + } +} + +void registerPerformanceLoggerHooks(RCTPerformanceLogger *performanceLogger) +{ + __weak RCTPerformanceLogger *weakPerformanceLogger = performanceLogger; + ReactMarker::logTaggedMarkerBridgelessImpl = [weakPerformanceLogger]( + const ReactMarker::ReactMarkerId markerId, const char *tag) { + mapReactMarkerToPerformanceLogger(markerId, weakPerformanceLogger); + }; +} diff --git a/packages/react-native/ReactCommon/react/bridgeless/platform/ios/Hermes/RCTHermesInstance.h b/packages/react-native/ReactCommon/react/bridgeless/platform/ios/Hermes/RCTHermesInstance.h new file mode 100644 index 00000000000000..5cd910a2a71a43 --- /dev/null +++ b/packages/react-native/ReactCommon/react/bridgeless/platform/ios/Hermes/RCTHermesInstance.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +#import +#import +#import +#import + +namespace facebook { +namespace react { +using CrashManagerProvider = + std::function()>; + +// ObjC++ wrapper for HermesInstance.cpp +class RCTHermesInstance : public JSEngineInstance { + public: + RCTHermesInstance(); + RCTHermesInstance( + std::shared_ptr reactNativeConfig, + CrashManagerProvider crashManagerProvider); + + std::unique_ptr createJSRuntime() noexcept override; + + ~RCTHermesInstance(){}; + + private: + std::shared_ptr _reactNativeConfig; + CrashManagerProvider _crashManagerProvider; + std::unique_ptr _hermesInstance; +}; +} // namespace react +} // namespace facebook diff --git a/packages/react-native/ReactCommon/react/bridgeless/platform/ios/Hermes/RCTHermesInstance.mm b/packages/react-native/ReactCommon/react/bridgeless/platform/ios/Hermes/RCTHermesInstance.mm new file mode 100644 index 00000000000000..681114d9af7fc3 --- /dev/null +++ b/packages/react-native/ReactCommon/react/bridgeless/platform/ios/Hermes/RCTHermesInstance.mm @@ -0,0 +1,29 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import "RCTHermesInstance.h" + +namespace facebook { +namespace react { +RCTHermesInstance::RCTHermesInstance() : RCTHermesInstance(nullptr, nullptr) {} + +RCTHermesInstance::RCTHermesInstance( + std::shared_ptr reactNativeConfig, + CrashManagerProvider crashManagerProvider) + : _reactNativeConfig(std::move(reactNativeConfig)), + _crashManagerProvider(std::move(crashManagerProvider)), + _hermesInstance(std::make_unique()) +{ +} + +std::unique_ptr RCTHermesInstance::createJSRuntime() noexcept +{ + return _hermesInstance->createJSRuntime( + _reactNativeConfig, _crashManagerProvider ? _crashManagerProvider() : nullptr); +} +} // namespace react +} // namespace facebook diff --git a/packages/react-native/ReactCommon/react/bridging/Bridging.h b/packages/react-native/ReactCommon/react/bridging/Bridging.h index 26cf99b5208302..b8a02290d1aee1 100644 --- a/packages/react-native/ReactCommon/react/bridging/Bridging.h +++ b/packages/react-native/ReactCommon/react/bridging/Bridging.h @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include diff --git a/packages/react-native/ReactCommon/react/bridging/Dynamic.h b/packages/react-native/ReactCommon/react/bridging/Dynamic.h new file mode 100644 index 00000000000000..be9555b49d594c --- /dev/null +++ b/packages/react-native/ReactCommon/react/bridging/Dynamic.h @@ -0,0 +1,26 @@ +/* + * 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. + */ + +#pragma once + +#include +#include + +namespace facebook::react { + +template <> +struct Bridging { + static folly::dynamic fromJs(jsi::Runtime &rt, const jsi::Value &value) { + return jsi::dynamicFromValue(rt, value); + } + + static jsi::Value toJs(jsi::Runtime &rt, const folly::dynamic &value) { + return jsi::valueFromDynamic(rt, value); + } +}; + +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/bridging/tests/BridgingTest.cpp b/packages/react-native/ReactCommon/react/bridging/tests/BridgingTest.cpp index 995bce42e62d2a..6d739619f90df5 100644 --- a/packages/react-native/ReactCommon/react/bridging/tests/BridgingTest.cpp +++ b/packages/react-native/ReactCommon/react/bridging/tests/BridgingTest.cpp @@ -532,4 +532,90 @@ TEST_F(BridgingTest, supportTest) { EXPECT_FALSE((bridging::supportsToJs, jsi::Function>)); } +TEST_F(BridgingTest, dynamicTest) { + // Null + auto nullFromJsResult = + bridging::fromJs(rt, jsi::Value::null(), invoker); + EXPECT_TRUE(nullFromJsResult.isNull()); + + auto nullToJsResult = bridging::toJs(rt, nullptr, invoker); + EXPECT_TRUE(nullToJsResult.isNull()); + + // Boolean + auto booleanFromJsResult = + bridging::fromJs(rt, jsi::Value(true), invoker); + EXPECT_TRUE(booleanFromJsResult.isBool()); + EXPECT_TRUE(booleanFromJsResult.asBool()); + + auto booleanToJsResult = bridging::toJs(rt, true, invoker); + EXPECT_TRUE(booleanToJsResult.isBool()); + EXPECT_TRUE(booleanToJsResult.asBool()); + + // Number + auto numberFromJsResult = + bridging::fromJs(rt, jsi::Value(1.2), invoker); + EXPECT_TRUE(numberFromJsResult.isNumber()); + EXPECT_DOUBLE_EQ(1.2, numberFromJsResult.asDouble()); + + auto numberToJsResult = bridging::toJs(rt, 1.2, invoker); + EXPECT_TRUE(numberToJsResult.isNumber()); + EXPECT_DOUBLE_EQ(1.2, numberToJsResult.asNumber()); + + // String + auto stringFromJsResult = bridging::fromJs( + rt, jsi::Value(jsi::String::createFromAscii(rt, "hello")), invoker); + EXPECT_TRUE(stringFromJsResult.isString()); + EXPECT_EQ("hello"s, stringFromJsResult.asString()); + + auto stringToJsResult = bridging::toJs(rt, "hello", invoker); + EXPECT_TRUE(stringToJsResult.isString()); + EXPECT_EQ("hello"s, stringToJsResult.asString(rt).utf8(rt)); + + // Array + auto arrayFromJsResult = bridging::fromJs( + rt, + jsi::Value(jsi::Array::createWithElements(rt, "foo", "bar")), + invoker); + EXPECT_TRUE(arrayFromJsResult.isArray()); + EXPECT_EQ(2, arrayFromJsResult.size()); + EXPECT_EQ("foo"s, arrayFromJsResult[0].asString()); + EXPECT_EQ("bar"s, arrayFromJsResult[1].asString()); + + auto arrayToJsResult = bridging::toJs( + rt, folly::dynamic::array("foo", "bar"), invoker); + EXPECT_TRUE(arrayToJsResult.isObject()); + EXPECT_TRUE(arrayToJsResult.asObject(rt).isArray(rt)); + auto arrayToJsResultArray = arrayToJsResult.asObject(rt).asArray(rt); + EXPECT_EQ(2, arrayToJsResultArray.size(rt)); + EXPECT_EQ( + "foo"s, + arrayToJsResultArray.getValueAtIndex(rt, 0).asString(rt).utf8(rt)); + EXPECT_EQ( + "bar"s, + arrayToJsResultArray.getValueAtIndex(rt, 1).asString(rt).utf8(rt)); + + // Object + auto jsiObject = jsi::Object(rt); + jsiObject.setProperty(rt, "foo", "bar"); + auto objectFromJsResult = bridging::fromJs( + rt, jsi::Value(std::move(jsiObject)), invoker); + + EXPECT_TRUE(objectFromJsResult.isObject()); + EXPECT_EQ(1, objectFromJsResult.size()); + EXPECT_EQ("bar"s, objectFromJsResult["foo"].asString()); + + auto objectToJsResult = bridging::toJs( + rt, folly::dynamic::object("foo", "bar"), invoker); + EXPECT_TRUE(objectToJsResult.isObject()); + auto objectToJsResultObject = objectToJsResult.asObject(rt); + EXPECT_EQ( + "bar"s, + objectToJsResultObject.getProperty(rt, "foo").asString(rt).utf8(rt)); + + // Undefined + auto undefinedFromJsResult = + bridging::fromJs(rt, jsi::Value::undefined(), invoker); + EXPECT_TRUE(undefinedFromJsResult.isNull()); +} + } // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/nativemodule/core/ReactCommon/TurboModuleBinding.cpp b/packages/react-native/ReactCommon/react/nativemodule/core/ReactCommon/TurboModuleBinding.cpp index e85c253cdf847a..e7039b5850934b 100644 --- a/packages/react-native/ReactCommon/react/nativemodule/core/ReactCommon/TurboModuleBinding.cpp +++ b/packages/react-native/ReactCommon/react/nativemodule/core/ReactCommon/TurboModuleBinding.cpp @@ -68,6 +68,12 @@ static void defineReadOnlyGlobal( jsi::Runtime &runtime, std::string propName, jsi::Value &&value) { + if (runtime.global().hasProperty(runtime, propName.c_str())) { + throw jsi::JSError( + runtime, + "Tried to redefine read-only global \"" + propName + + "\", but read-only globals can only be defined once."); + } jsi::Object jsObject = runtime.global().getProperty(runtime, "Object").asObject(runtime); jsi::Function defineProperty = jsObject.getProperty(runtime, "defineProperty") diff --git a/packages/react-native/ReactCommon/react/nativemodule/core/platform/android/ReactCommon/JavaTurboModule.cpp b/packages/react-native/ReactCommon/react/nativemodule/core/platform/android/ReactCommon/JavaTurboModule.cpp index 35fbba1af840be..477d144773b852 100644 --- a/packages/react-native/ReactCommon/react/nativemodule/core/platform/android/ReactCommon/JavaTurboModule.cpp +++ b/packages/react-native/ReactCommon/react/nativemodule/core/platform/android/ReactCommon/JavaTurboModule.cpp @@ -400,6 +400,53 @@ jsi::Value convertFromJMapToValue(JNIEnv *env, jsi::Runtime &rt, jobject arg) { return jsi::valueFromDynamic(rt, result->cthis()->consume()); } +jsi::Value createJSRuntimeError( + jsi::Runtime &runtime, + const std::string &message) { + return runtime.global() + .getPropertyAsFunction(runtime, "Error") + .call(runtime, message); +} + +/** + * Creates JSError with current JS runtime stack and Throwable stack trace. + */ +jsi::JSError convertThrowableToJSError( + jsi::Runtime &runtime, + jni::local_ref throwable) { + auto stackTrace = throwable->getStackTrace(); + + jsi::Array stackElements(runtime, stackTrace->size()); + for (int i = 0; i < stackTrace->size(); ++i) { + auto frame = stackTrace->getElement(i); + + jsi::Object frameObject(runtime); + frameObject.setProperty(runtime, "className", frame->getClassName()); + frameObject.setProperty(runtime, "fileName", frame->getFileName()); + frameObject.setProperty(runtime, "lineNumber", frame->getLineNumber()); + frameObject.setProperty(runtime, "methodName", frame->getMethodName()); + stackElements.setValueAtIndex(runtime, i, std::move(frameObject)); + } + + jsi::Object cause(runtime); + auto getName = throwable->getClass() + ->getClass() + ->getMethod()>("getName"); + auto getMessage = + throwable->getClass()->getMethod()>( + "getMessage"); + auto message = getMessage(throwable)->toStdString(); + cause.setProperty( + runtime, "name", getName(throwable->getClass())->toStdString()); + cause.setProperty(runtime, "message", message); + cause.setProperty(runtime, "stackElements", std::move(stackElements)); + + jsi::Value error = + createJSRuntimeError(runtime, "Exception in HostFunction: " + message); + error.asObject(runtime).setProperty(runtime, "cause", std::move(cause)); + return {runtime, std::move(error)}; +} + } // namespace jsi::Value JavaTurboModule::invokeJavaMethod( @@ -467,7 +514,9 @@ jsi::Value JavaTurboModule::invokeJavaMethod( } else { TMPL::asyncMethodCallFail(moduleName, methodName); } - throw; + auto exception = std::current_exception(); + auto throwable = jni::getJavaExceptionForCppException(exception); + throw convertThrowableToJSError(runtime, throwable); } }; diff --git a/packages/react-native/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTTurboModule.h b/packages/react-native/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTTurboModule.h index b971372e9b837d..4dc6b8f2330eff 100644 --- a/packages/react-native/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTTurboModule.h +++ b/packages/react-native/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTTurboModule.h @@ -28,6 +28,10 @@ namespace facebook::react { class CallbackWrapper; class Instance; +namespace TurboModuleConvertUtils { +jsi::Value convertObjCObjectToJSIValue(jsi::Runtime &runtime, id value); +} + /** * ObjC++ specific TurboModule base class. */ @@ -36,7 +40,7 @@ class JSI_EXPORT ObjCTurboModule : public TurboModule { // TODO(T65603471): Should we unify this with a Fabric abstraction? struct InitParams { std::string moduleName; - id instance; + id instance; std::shared_ptr jsInvoker; std::shared_ptr nativeInvoker; bool isSyncModule; @@ -46,17 +50,22 @@ class JSI_EXPORT ObjCTurboModule : public TurboModule { jsi::Value invokeObjCMethod( jsi::Runtime &runtime, - TurboModuleMethodValueKind valueKind, + TurboModuleMethodValueKind returnType, const std::string &methodName, SEL selector, const jsi::Value *args, size_t count); - id instance_; + id instance_; std::shared_ptr nativeInvoker_; protected: void setMethodArgConversionSelector(NSString *methodName, int argIndex, NSString *fnName); + virtual jsi::Value convertReturnIdToJSIValue( + jsi::Runtime &runtime, + const char *methodName, + TurboModuleMethodValueKind returnType, + id result); private: // Does the NativeModule dispatch async methods to the JS thread? @@ -72,18 +81,26 @@ class JSI_EXPORT ObjCTurboModule : public TurboModule { bool isMethodSync(TurboModuleMethodValueKind returnType); BOOL hasMethodArgConversionSelector(NSString *methodName, int argIndex); SEL getMethodArgConversionSelector(NSString *methodName, int argIndex); - NSString *getArgumentTypeName(NSString *methodName, int argIndex); - NSInvocation *getMethodInvocation( + NSString *getArgumentTypeName(jsi::Runtime &runtime, NSString *methodName, int argIndex); + NSInvocation *createMethodInvocation( jsi::Runtime &runtime, - TurboModuleMethodValueKind returnType, + bool isSync, const char *methodName, SEL selector, const jsi::Value *args, size_t count, NSMutableArray *retainedObjectsForInvocation); - jsi::Value performMethodInvocation( + void setInvocationArg( jsi::Runtime &runtime, - TurboModuleMethodValueKind returnType, + const char *methodName, + const std::string &objCArgType, + const jsi::Value &arg, + size_t i, + NSInvocation *inv, + NSMutableArray *retainedObjectsForInvocation); + id performMethodInvocation( + jsi::Runtime &runtime, + bool isSync, const char *methodName, NSInvocation *inv, NSMutableArray *retainedObjectsForInvocation); diff --git a/packages/react-native/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTTurboModule.mm b/packages/react-native/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTTurboModule.mm index 7a1ca33ccc2213..93271d2f81899c 100644 --- a/packages/react-native/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTTurboModule.mm +++ b/packages/react-native/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTTurboModule.mm @@ -29,6 +29,7 @@ using namespace facebook; using namespace facebook::react; +using namespace facebook::react::TurboModuleConvertUtils; static int32_t getUniqueId() { @@ -36,6 +37,10 @@ static int32_t getUniqueId() return counter++; } +namespace facebook { +namespace react { + +namespace TurboModuleConvertUtils { /** * All static helper functions are ObjC++ specific. */ @@ -54,7 +59,6 @@ static int32_t getUniqueId() return jsi::String::createFromUtf8(runtime, [value UTF8String] ?: ""); } -static jsi::Value convertObjCObjectToJSIValue(jsi::Runtime &runtime, id value); static jsi::Object convertNSDictionaryToJSIObject(jsi::Runtime &runtime, NSDictionary *value) { jsi::Object result = jsi::Object(runtime); @@ -82,7 +86,7 @@ static int32_t getUniqueId() return result; } -static jsi::Value convertObjCObjectToJSIValue(jsi::Runtime &runtime, id value) +jsi::Value convertObjCObjectToJSIValue(jsi::Runtime &runtime, id value) { if ([value isKindOfClass:[NSString class]]) { return convertNSStringToJSIString(runtime, (NSString *)value); @@ -211,7 +215,31 @@ static int32_t getUniqueId() return [callback copy]; } -namespace facebook::react { +static jsi::Value createJSRuntimeError(jsi::Runtime &runtime, const std::string &message) +{ + return runtime.global().getPropertyAsFunction(runtime, "Error").call(runtime, message); +} + +/** + * Creates JSError with current JS runtime and NSException stack trace. + */ +static jsi::JSError convertNSExceptionToJSError(jsi::Runtime &runtime, NSException *exception) +{ + std::string reason = [exception.reason UTF8String]; + + jsi::Object cause(runtime); + cause.setProperty(runtime, "name", [exception.name UTF8String]); + cause.setProperty(runtime, "message", reason); + cause.setProperty(runtime, "stackSymbols", convertNSArrayToJSIArray(runtime, exception.callStackSymbols)); + cause.setProperty( + runtime, "stackReturnAddresses", convertNSArrayToJSIArray(runtime, exception.callStackReturnAddresses)); + + jsi::Value error = createJSRuntimeError(runtime, "Exception in HostFunction: " + reason); + error.asObject(runtime).setProperty(runtime, "cause", std::move(cause)); + return {runtime, std::move(error)}; +} + +} jsi::Value ObjCTurboModule::createPromise(jsi::Runtime &runtime, std::string methodName, PromiseInvocationBlock invoke) { @@ -349,56 +377,68 @@ static int32_t getUniqueId() * - ObjC module methods will be always be called from JS thread. * They may decide to dispatch to a different queue as needed. */ -jsi::Value ObjCTurboModule::performMethodInvocation( +id ObjCTurboModule::performMethodInvocation( jsi::Runtime &runtime, - TurboModuleMethodValueKind returnType, + bool isSync, const char *methodName, NSInvocation *inv, NSMutableArray *retainedObjectsForInvocation) { __block id result; - jsi::Runtime *rt = &runtime; - __weak id weakModule = instance_; + __weak id weakModule = instance_; const char *moduleName = name_.c_str(); std::string methodNameStr{methodName}; __block int32_t asyncCallCounter = 0; - bool wasMethodSync = isMethodSync(returnType); void (^block)() = ^{ - id strongModule = weakModule; + id strongModule = weakModule; if (!strongModule) { return; } - if (wasMethodSync) { + if (isSync) { TurboModulePerfLogger::syncMethodCallExecutionStart(moduleName, methodNameStr.c_str()); } else { TurboModulePerfLogger::asyncMethodCallExecutionStart(moduleName, methodNameStr.c_str(), asyncCallCounter); } - // TODO(T66699874) Should we guard this with a try/catch? - [inv invokeWithTarget:strongModule]; - [retainedObjectsForInvocation removeAllObjects]; + @try { + [inv invokeWithTarget:strongModule]; + } @catch (NSException *exception) { + throw convertNSExceptionToJSError(runtime, exception); + } @finally { + [retainedObjectsForInvocation removeAllObjects]; + } - if (!wasMethodSync) { + if (!isSync) { TurboModulePerfLogger::asyncMethodCallExecutionEnd(moduleName, methodNameStr.c_str(), asyncCallCounter); return; } - TurboModulePerfLogger::syncMethodCallExecutionEnd(moduleName, methodNameStr.c_str()); - TurboModulePerfLogger::syncMethodCallReturnConversionStart(moduleName, methodNameStr.c_str()); - void *rawResult; [inv getReturnValue:&rawResult]; result = (__bridge id)rawResult; + TurboModulePerfLogger::syncMethodCallExecutionEnd(moduleName, methodNameStr.c_str()); }; - if (wasMethodSync) { + if (isSync) { block(); + return result; } else { asyncCallCounter = getUniqueId(); TurboModulePerfLogger::asyncMethodCallDispatch(moduleName, methodName); nativeInvoker_->invokeAsync([block]() -> void { block(); }); + return nil; + } +} + +jsi::Value ObjCTurboModule::convertReturnIdToJSIValue( + jsi::Runtime &runtime, + const char *methodName, + TurboModuleMethodValueKind returnType, + id result) +{ + if (returnType == VoidKind) { return jsi::Value::undefined(); } @@ -414,32 +454,31 @@ static int32_t getUniqueId() break; } case BooleanKind: { - returnValue = convertNSNumberToJSIBoolean(*rt, (NSNumber *)result); + returnValue = convertNSNumberToJSIBoolean(runtime, (NSNumber *)result); break; } case NumberKind: { - returnValue = convertNSNumberToJSINumber(*rt, (NSNumber *)result); + returnValue = convertNSNumberToJSINumber(runtime, (NSNumber *)result); break; } case StringKind: { - returnValue = convertNSStringToJSIString(*rt, (NSString *)result); + returnValue = convertNSStringToJSIString(runtime, (NSString *)result); break; } case ObjectKind: { - returnValue = convertNSDictionaryToJSIObject(*rt, (NSDictionary *)result); + returnValue = convertNSDictionaryToJSIObject(runtime, (NSDictionary *)result); break; } case ArrayKind: { - returnValue = convertNSArrayToJSIArray(*rt, (NSArray *)result); + returnValue = convertNSArrayToJSIArray(runtime, (NSArray *)result); break; } case FunctionKind: - throw std::runtime_error("convertInvocationResultToJSIValue: FunctionKind is not supported yet."); + throw std::runtime_error("convertReturnIdToJSIValue: FunctionKind is not supported yet."); case PromiseKind: - throw std::runtime_error("convertInvocationResultToJSIValue: PromiseKind wasn't handled properly."); + throw std::runtime_error("convertReturnIdToJSIValue: PromiseKind wasn't handled properly."); } - TurboModulePerfLogger::syncMethodCallReturnConversionEnd(moduleName, methodName); return returnValue; } @@ -454,7 +493,7 @@ static int32_t getUniqueId() * Note: This is only being introduced for backward compatibility. It will be removed * in the future. */ -NSString *ObjCTurboModule::getArgumentTypeName(NSString *methodName, int argIndex) +NSString *ObjCTurboModule::getArgumentTypeName(jsi::Runtime &runtime, NSString *methodName, int argIndex) { if (!methodArgumentTypeNames_) { NSMutableDictionary *> *methodArgumentTypeNames = [NSMutableDictionary new]; @@ -501,9 +540,109 @@ static int32_t getUniqueId() return nil; } -NSInvocation *ObjCTurboModule::getMethodInvocation( +void ObjCTurboModule::setInvocationArg( jsi::Runtime &runtime, - TurboModuleMethodValueKind returnType, + const char *methodName, + const std::string &objCArgType, + const jsi::Value &arg, + size_t i, + NSInvocation *inv, + NSMutableArray *retainedObjectsForInvocation) +{ + if (arg.isBool()) { + bool v = arg.getBool(); + + /** + * JS type checking ensures the Objective C argument here is either a BOOL or NSNumber*. + */ + if (objCArgType == @encode(id)) { + id objCArg = [NSNumber numberWithBool:v]; + [inv setArgument:(void *)&objCArg atIndex:i + 2]; + [retainedObjectsForInvocation addObject:objCArg]; + } else { + [inv setArgument:(void *)&v atIndex:i + 2]; + } + + return; + } + + if (arg.isNumber()) { + double v = arg.getNumber(); + + /** + * JS type checking ensures the Objective C argument here is either a double or NSNumber*. + */ + if (objCArgType == @encode(id)) { + id objCArg = [NSNumber numberWithDouble:v]; + [inv setArgument:(void *)&objCArg atIndex:i + 2]; + [retainedObjectsForInvocation addObject:objCArg]; + } else { + [inv setArgument:(void *)&v atIndex:i + 2]; + } + + return; + } + + /** + * Convert arg to ObjC objects. + */ + id objCArg = convertJSIValueToObjCObject(runtime, arg, jsInvoker_); + if (objCArg) { + NSString *methodNameNSString = @(methodName); + + /** + * Convert objects using RCTConvert. + */ + if (objCArgType == @encode(id)) { + NSString *argumentType = getArgumentTypeName(runtime, methodNameNSString, i); + if (argumentType != nil) { + NSString *rctConvertMethodName = [NSString stringWithFormat:@"%@:", argumentType]; + SEL rctConvertSelector = NSSelectorFromString(rctConvertMethodName); + + if ([RCTConvert respondsToSelector:rctConvertSelector]) { + // Message dispatch logic from old infra + id (*convert)(id, SEL, id) = (__typeof__(convert))objc_msgSend; + id convertedObjCArg = convert([RCTConvert class], rctConvertSelector, objCArg); + + [inv setArgument:(void *)&convertedObjCArg atIndex:i + 2]; + if (convertedObjCArg) { + [retainedObjectsForInvocation addObject:convertedObjCArg]; + } + return; + } + } + } + + /** + * Convert objects using RCTCxxConvert to structs. + */ + if ([objCArg isKindOfClass:[NSDictionary class]] && hasMethodArgConversionSelector(methodNameNSString, i)) { + SEL methodArgConversionSelector = getMethodArgConversionSelector(methodNameNSString, i); + + // Message dispatch logic from old infra (link: + // https://github.com/facebook/react-native/commit/6783694158057662fd7b11fc123c339b2b21bfe6#diff-263fc157dfce55895cdc16495b55d190R350) + RCTManagedPointer *(*convert)(id, SEL, id) = (__typeof__(convert))objc_msgSend; + RCTManagedPointer *box = convert([RCTCxxConvert class], methodArgConversionSelector, objCArg); + + void *pointer = box.voidPointer; + [inv setArgument:&pointer atIndex:i + 2]; + [retainedObjectsForInvocation addObject:box]; + return; + } + } + + /** + * Insert converted args unmodified. + */ + [inv setArgument:(void *)&objCArg atIndex:i + 2]; + if (objCArg) { + [retainedObjectsForInvocation addObject:objCArg]; + } +} + +NSInvocation *ObjCTurboModule::createMethodInvocation( + jsi::Runtime &runtime, + bool isSync, const char *methodName, SEL selector, const jsi::Value *args, @@ -511,9 +650,9 @@ static int32_t getUniqueId() NSMutableArray *retainedObjectsForInvocation) { const char *moduleName = name_.c_str(); - const id module = instance_; + const id module = instance_; - if (isMethodSync(returnType)) { + if (isSync) { TurboModulePerfLogger::syncMethodCallArgConversionStart(moduleName, methodName); } else { TurboModulePerfLogger::asyncMethodCallArgConversionStart(moduleName, methodName); @@ -526,101 +665,13 @@ static int32_t getUniqueId() NSMethodSignature *methodSignature = [[module class] instanceMethodSignatureForSelector:selector]; for (size_t i = 0; i < count; i++) { - const jsi::Value *arg = &args[i]; + const jsi::Value &arg = args[i]; const std::string objCArgType = [methodSignature getArgumentTypeAtIndex:i + 2]; - if (arg->isBool()) { - bool v = arg->getBool(); - - /** - * JS type checking ensures the Objective C argument here is either a BOOL or NSNumber*. - */ - if (objCArgType == @encode(id)) { - id objCArg = [NSNumber numberWithBool:v]; - [inv setArgument:(void *)&objCArg atIndex:i + 2]; - [retainedObjectsForInvocation addObject:objCArg]; - } else { - [inv setArgument:(void *)&v atIndex:i + 2]; - } - - continue; - } - - if (arg->isNumber()) { - double v = arg->getNumber(); - - /** - * JS type checking ensures the Objective C argument here is either a double or NSNumber*. - */ - if (objCArgType == @encode(id)) { - id objCArg = [NSNumber numberWithDouble:v]; - [inv setArgument:(void *)&objCArg atIndex:i + 2]; - [retainedObjectsForInvocation addObject:objCArg]; - } else { - [inv setArgument:(void *)&v atIndex:i + 2]; - } - - continue; - } - - /** - * Convert arg to ObjC objects. - */ - id objCArg = convertJSIValueToObjCObject(runtime, *arg, jsInvoker_); - if (objCArg) { - NSString *methodNameNSString = @(methodName); - - /** - * Convert objects using RCTConvert. - */ - if (objCArgType == @encode(id)) { - NSString *argumentType = getArgumentTypeName(methodNameNSString, i); - if (argumentType != nil) { - NSString *rctConvertMethodName = [NSString stringWithFormat:@"%@:", argumentType]; - SEL rctConvertSelector = NSSelectorFromString(rctConvertMethodName); - - if ([RCTConvert respondsToSelector:rctConvertSelector]) { - // Message dispatch logic from old infra - id (*convert)(id, SEL, id) = (__typeof__(convert))objc_msgSend; - id convertedObjCArg = convert([RCTConvert class], rctConvertSelector, objCArg); - - [inv setArgument:(void *)&convertedObjCArg atIndex:i + 2]; - if (convertedObjCArg) { - [retainedObjectsForInvocation addObject:convertedObjCArg]; - } - continue; - } - } - } - - /** - * Convert objects using RCTCxxConvert to structs. - */ - if ([objCArg isKindOfClass:[NSDictionary class]] && hasMethodArgConversionSelector(methodNameNSString, i)) { - SEL methodArgConversionSelector = getMethodArgConversionSelector(methodNameNSString, i); - - // Message dispatch logic from old infra (link: - // https://github.com/facebook/react-native/commit/6783694158057662fd7b11fc123c339b2b21bfe6#diff-263fc157dfce55895cdc16495b55d190R350) - RCTManagedPointer *(*convert)(id, SEL, id) = (__typeof__(convert))objc_msgSend; - RCTManagedPointer *box = convert([RCTCxxConvert class], methodArgConversionSelector, objCArg); - - void *pointer = box.voidPointer; - [inv setArgument:&pointer atIndex:i + 2]; - [retainedObjectsForInvocation addObject:box]; - continue; - } - } - - /** - * Insert converted args unmodified. - */ - [inv setArgument:(void *)&objCArg atIndex:i + 2]; - if (objCArg) { - [retainedObjectsForInvocation addObject:objCArg]; - } + setInvocationArg(runtime, methodName, objCArgType, arg, i, inv, retainedObjectsForInvocation); } - if (isMethodSync(returnType)) { + if (isSync) { TurboModulePerfLogger::syncMethodCallArgConversionEnd(moduleName, methodName); } else { TurboModulePerfLogger::asyncMethodCallArgConversionEnd(moduleName, methodName); @@ -660,25 +711,38 @@ static int32_t getUniqueId() } NSMutableArray *retainedObjectsForInvocation = [NSMutableArray arrayWithCapacity:count + 2]; - NSInvocation *inv = - getMethodInvocation(runtime, returnType, methodName, selector, args, count, retainedObjectsForInvocation); - - jsi::Value returnValue = returnType == PromiseKind - ? createPromise( - runtime, - methodNameStr, - ^(RCTPromiseResolveBlock resolveBlock, RCTPromiseRejectBlock rejectBlock) { - RCTPromiseResolveBlock resolveCopy = [resolveBlock copy]; - RCTPromiseRejectBlock rejectCopy = [rejectBlock copy]; - - [inv setArgument:(void *)&resolveCopy atIndex:count + 2]; - [inv setArgument:(void *)&rejectCopy atIndex:count + 3]; - [retainedObjectsForInvocation addObject:resolveCopy]; - [retainedObjectsForInvocation addObject:rejectCopy]; - // The return type becomes void in the ObjC side. - performMethodInvocation(runtime, VoidKind, methodName, inv, retainedObjectsForInvocation); - }) - : performMethodInvocation(runtime, returnType, methodName, inv, retainedObjectsForInvocation); + NSInvocation *inv = createMethodInvocation( + runtime, isMethodSync(returnType), methodName, selector, args, count, retainedObjectsForInvocation); + + jsi::Value returnValue = jsi::Value::undefined(); + + if (returnType == PromiseKind) { + returnValue = createPromise( + runtime, methodNameStr, ^(RCTPromiseResolveBlock resolveBlock, RCTPromiseRejectBlock rejectBlock) { + RCTPromiseResolveBlock resolveCopy = [resolveBlock copy]; + RCTPromiseRejectBlock rejectCopy = [rejectBlock copy]; + + [inv setArgument:(void *)&resolveCopy atIndex:count + 2]; + [inv setArgument:(void *)&rejectCopy atIndex:count + 3]; + [retainedObjectsForInvocation addObject:resolveCopy]; + [retainedObjectsForInvocation addObject:rejectCopy]; + // The return type becomes void in the ObjC side. + performMethodInvocation(runtime, isMethodSync(VoidKind), methodName, inv, retainedObjectsForInvocation); + }); + } else { + id result = + performMethodInvocation(runtime, isMethodSync(returnType), methodName, inv, retainedObjectsForInvocation); + + if (isMethodSync(returnType)) { + TurboModulePerfLogger::syncMethodCallReturnConversionStart(moduleName, methodName); + } + + returnValue = convertReturnIdToJSIValue(runtime, methodName, returnType, result); + + if (isMethodSync(returnType)) { + TurboModulePerfLogger::syncMethodCallReturnConversionEnd(moduleName, methodName); + } + } if (isMethodSync(returnType)) { TurboModulePerfLogger::syncMethodCallEnd(moduleName, methodName); @@ -723,4 +787,5 @@ static int32_t getUniqueId() methodArgConversionSelectors_[methodName][argIndex] = selectorValue; } +} } // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTTurboModuleManager.h b/packages/react-native/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTTurboModuleManager.h index c129391fa90b4a..23c8d93365adff 100644 --- a/packages/react-native/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTTurboModuleManager.h +++ b/packages/react-native/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTTurboModuleManager.h @@ -19,18 +19,18 @@ RCT_EXTERN void RCTTurboModuleSetBindingMode(facebook::react::TurboModuleBinding @protocol RCTTurboModuleManagerDelegate -@optional - /** - * Given a module name, return its actual class. If not provided, basic ObjC class lookup is performed. + * Given a module name, return its actual class. If nil is returned, basic ObjC class lookup is performed. */ - (Class)getModuleClassFromName:(const char *)name; /** - * Given a module class, provide an instance for it. If not provided, default initializer is used. + * Given a module class, provide an instance for it. If nil is returned, default initializer is used. */ - (id)getModuleInstanceFromClass:(Class)moduleClass; +@optional + /** * Create an instance of a TurboModule without relying on any ObjC++ module instance. */ diff --git a/packages/react-native/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTTurboModuleManager.mm b/packages/react-native/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTTurboModuleManager.mm index 5d7e84f1446895..bbeda506b9df39 100644 --- a/packages/react-native/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTTurboModuleManager.mm +++ b/packages/react-native/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTTurboModuleManager.mm @@ -38,7 +38,7 @@ void RCTTurboModuleSetBindingMode(TurboModuleBindingMode bindingMode) } /** - * A global variable whose address we use to associate method queues to id objects. + * A global variable whose address we use to associate method queues to id objects. */ static char kAssociatedMethodQueueKey; @@ -49,18 +49,17 @@ int32_t getUniqueId() return counter++; } -class TurboModuleHolder { +class ModuleHolder { private: const int32_t moduleId_; - id module_; + id module_; bool isTryingToCreateModule_; bool isDoneCreatingModule_; std::mutex mutex_; std::condition_variable cv_; public: - TurboModuleHolder() - : moduleId_(getUniqueId()), module_(nil), isTryingToCreateModule_(false), isDoneCreatingModule_(false) + ModuleHolder() : moduleId_(getUniqueId()), module_(nil), isTryingToCreateModule_(false), isDoneCreatingModule_(false) { } @@ -69,12 +68,12 @@ int32_t getModuleId() const return moduleId_; } - void setModule(id module) + void setModule(id module) { module_ = module; } - id getModule() const + id getModule() const { return module_; } @@ -167,17 +166,17 @@ @implementation RCTTurboModuleManager { * We need to come up with a mechanism to allow modules to specify whether * they want to be long-lived or short-lived. * - * All instances of TurboModuleHolder are owned by the _turboModuleHolders map. - * We only reference TurboModuleHolders via pointers to entries in the _turboModuleHolders map. + * All instances of ModuleHolder are owned by the _moduleHolders map. + * We only reference ModuleHolders via pointers to entries in the _moduleHolders map. */ - std::unordered_map _turboModuleHolders; + std::unordered_map _moduleHolders; std::unordered_map> _turboModuleCache; // Enforce synchronous access into _delegate std::mutex _turboModuleManagerDelegateMutex; - // Enforce synchronous access to _invalidating and _turboModuleHolders - std::mutex _turboModuleHoldersMutex; + // Enforce synchronous access to _invalidating and _moduleHolders + std::mutex _moduleHoldersMutex; std::atomic _invalidating; } @@ -257,12 +256,12 @@ - (void)notifyAboutTurboModuleSetup:(const char *)name /** * Step 2: Look for platform-specific modules. */ - id module = [self provideRCTTurboModule:moduleName]; + id module = [self _provideObjCModule:moduleName]; TurboModulePerfLogger::moduleJSRequireEndingStart(moduleName); // If we request that a TurboModule be created, its respective ObjC class must exist - // If the class doesn't exist, then provideRCTTurboModule returns nil + // If the class doesn't exist, then _provideObjCModule returns nil if (!module) { return nullptr; } @@ -299,57 +298,64 @@ - (void)notifyAboutTurboModuleSetup:(const char *)name return turboModule; } - ObjCTurboModule::InitParams params = { - .moduleName = moduleName, - .instance = module, - .jsInvoker = _jsInvoker, - .nativeInvoker = nativeInvoker, - .isSyncModule = methodQueue == RCTJSThread, - }; - /** * Step 2e: Return an exact sub-class of ObjC TurboModule + * + * Use respondsToSelector: below to infer conformance to @protocol(RCTTurboModule). Using conformsToProtocol: is + * expensive. */ - auto turboModule = [module getTurboModule:params]; - if (turboModule == nullptr) { - RCTLogError(@"TurboModule \"%@\"'s getTurboModule: method returned nil.", moduleClass); + if ([module respondsToSelector:@selector(getTurboModule:)]) { + ObjCTurboModule::InitParams params = { + .moduleName = moduleName, + .instance = module, + .jsInvoker = _jsInvoker, + .nativeInvoker = nativeInvoker, + .isSyncModule = methodQueue == RCTJSThread, + }; + + auto turboModule = [(id)module getTurboModule:params]; + if (turboModule == nullptr) { + RCTLogError(@"TurboModule \"%@\"'s getTurboModule: method returned nil.", moduleClass); + } + _turboModuleCache.insert({moduleName, turboModule}); + return turboModule; } - _turboModuleCache.insert({moduleName, turboModule}); - return turboModule; + + return nullptr; } -- (TurboModuleHolder *)_getOrCreateTurboModuleHolder:(const char *)moduleName +- (ModuleHolder *)_getOrCreateModuleHolder:(const char *)moduleName { - std::lock_guard guard(_turboModuleHoldersMutex); + std::lock_guard guard(_moduleHoldersMutex); if (_invalidating) { return nullptr; } - return &_turboModuleHolders[moduleName]; + return &_moduleHolders[moduleName]; } /** - * Given a name for a TurboModule, return an ObjC object which is the instance - * of that TurboModule ObjC class. If no TurboModule exist with the provided name, + * Given a name for a NativeModule, return an ObjC object which is the instance + * of that NativeModule ObjC class. If no NativeModule exist with the provided name, * return nil. * - * Note: All TurboModule instances are cached, which means they're all long-lived + * Note: All NativeModule instances are cached, which means they're all long-lived * (for now). */ -- (id)provideRCTTurboModule:(const char *)moduleName +- (id)_provideObjCModule:(const char *)moduleName { if (strncmp("RCT", moduleName, 3) == 0) { moduleName = [[[NSString stringWithUTF8String:moduleName] substringFromIndex:3] UTF8String]; } - TurboModuleHolder *moduleHolder = [self _getOrCreateTurboModuleHolder:moduleName]; + ModuleHolder *moduleHolder = [self _getOrCreateModuleHolder:moduleName]; if (!moduleHolder) { return nil; } TurboModulePerfLogger::moduleCreateStart(moduleName, moduleHolder->getModuleId()); - id module = [self _provideRCTTurboModule:moduleName moduleHolder:moduleHolder shouldPerfLog:YES]; + id module = [self _provideObjCModule:moduleName moduleHolder:moduleHolder shouldPerfLog:YES]; if (module) { TurboModulePerfLogger::moduleCreateEnd(moduleName, moduleHolder->getModuleId()); @@ -360,9 +366,9 @@ - (TurboModuleHolder *)_getOrCreateTurboModuleHolder:(const char *)moduleName return module; } -- (id)_provideRCTTurboModule:(const char *)moduleName - moduleHolder:(TurboModuleHolder *)moduleHolder - shouldPerfLog:(BOOL)shouldPerfLog +- (id)_provideObjCModule:(const char *)moduleName + moduleHolder:(ModuleHolder *)moduleHolder + shouldPerfLog:(BOOL)shouldPerfLog { bool shouldCreateModule = false; @@ -388,21 +394,18 @@ - (TurboModuleHolder *)_getOrCreateTurboModuleHolder:(const char *)moduleName /** * Step 2a: Resolve platform-specific class. */ - - if ([_delegate respondsToSelector:@selector(getModuleClassFromName:)]) { - if (RCTTurboModuleManagerDelegateLockingDisabled()) { - moduleClass = [_delegate getModuleClassFromName:moduleName]; - } else { - std::lock_guard delegateGuard(_turboModuleManagerDelegateMutex); - moduleClass = [_delegate getModuleClassFromName:moduleName]; - } + if (RCTTurboModuleManagerDelegateLockingDisabled()) { + moduleClass = [_delegate getModuleClassFromName:moduleName]; + } else { + std::lock_guard delegateGuard(_turboModuleManagerDelegateMutex); + moduleClass = [_delegate getModuleClassFromName:moduleName]; } if (!moduleClass) { moduleClass = getFallbackClassFromName(moduleName); } - __block id module = nil; + __block id module = nil; if ([moduleClass conformsToProtocol:@protocol(RCTTurboModule)]) { __weak __typeof(self) weakSelf = self; @@ -411,9 +414,9 @@ - (TurboModuleHolder *)_getOrCreateTurboModuleHolder:(const char *)moduleName if (!strongSelf) { return; } - module = [strongSelf _createAndSetUpRCTTurboModule:moduleClass - moduleName:moduleName - moduleId:moduleHolder->getModuleId()]; + module = [strongSelf _createAndSetUpObjCModule:moduleClass + moduleName:moduleName + moduleId:moduleHolder->getModuleId()]; }; if ([self _requiresMainQueueSetup:moduleClass]) { @@ -463,45 +466,31 @@ - (TurboModuleHolder *)_getOrCreateTurboModuleHolder:(const char *)moduleName } /** - * Given a TurboModule class, and its name, create and initialize it synchronously. + * Given a NativeModule class, and its name, create and initialize it synchronously. * * This method can be called synchronously from two different contexts: - * - The thread that calls provideRCTTurboModule: - * - The main thread (if the TurboModule requires main queue init), blocking the thread that calls - * provideRCTTurboModule:. + * - The thread that calls _provideObjCModule: + * - The main thread (if the NativeModule requires main queue init), blocking the thread that calls + * _provideObjCModule:. */ -- (id)_createAndSetUpRCTTurboModule:(Class)moduleClass - moduleName:(const char *)moduleName - moduleId:(int32_t)moduleId +- (id)_createAndSetUpObjCModule:(Class)moduleClass + moduleName:(const char *)moduleName + moduleId:(int32_t)moduleId { - id module = nil; + id module = nil; /** * Step 2b: Ask hosting application/delegate to instantiate this class */ TurboModulePerfLogger::moduleCreateConstructStart(moduleName, moduleId); - if ([_delegate respondsToSelector:@selector(getModuleInstanceFromClass:)]) { - if (RCTTurboModuleManagerDelegateLockingDisabled()) { - module = [_delegate getModuleInstanceFromClass:moduleClass]; - } else { - std::lock_guard delegateGuard(_turboModuleManagerDelegateMutex); - module = [_delegate getModuleInstanceFromClass:moduleClass]; - } - - /** - * If the application is unable to create the TurboModule object from its class: - * abort TurboModule creation, and early return nil. - */ - if (!module) { - RCTLogError( - @"TurboModuleManager delegate %@ returned nil TurboModule object for module with name=\"%s\" and class=%@", - NSStringFromClass([_delegate class]), - moduleName, - NSStringFromClass(moduleClass)); - return nil; - } + if (RCTTurboModuleManagerDelegateLockingDisabled()) { + module = (id)[_delegate getModuleInstanceFromClass:moduleClass]; } else { + std::lock_guard delegateGuard(_turboModuleManagerDelegateMutex); + module = (id)[_delegate getModuleInstanceFromClass:moduleClass]; + } + if (!module) { module = [moduleClass new]; } TurboModulePerfLogger::moduleCreateConstructEnd(moduleName, moduleId); @@ -589,24 +578,24 @@ - (TurboModuleHolder *)_getOrCreateTurboModuleHolder:(const char *)moduleName } /** - * Decorate TurboModules with bridgeless-compatible APIs that call into the bridge. + * Decorate NativeModules with bridgeless-compatible APIs that call into the bridge. */ if (_bridge) { - [_bridge attachBridgeAPIsToTurboModule:module]; + [_bridge attachBridgeAPIsToObjCModule:module]; } /** - * If the TurboModule conforms to RCTInitializing, invoke its initialize method. + * If the NativeModule conforms to RCTInitializing, invoke its initialize method. */ if ([module respondsToSelector:@selector(initialize)]) { [(id)module initialize]; } /** - * Attach method queue to id object. - * This is necessary because the id object can be eagerly created/initialized before the method - * queue is required. The method queue is required for an id for JS -> Native calls. So, we need it - * before we create the id's TurboModule jsi::HostObject in provideTurboModule:. + * Attach method queue to id object. + * This is necessary because the id object can be eagerly created/initialized before the method + * queue is required. The method queue is required for an id for JS -> Native calls. So, we need it + * before we create the id's TurboModule jsi::HostObject in provideTurboModule:. */ objc_setAssociatedObject(module, &kAssociatedMethodQueueKey, methodQueue, OBJC_ASSOCIATION_RETAIN); @@ -628,7 +617,7 @@ - (TurboModuleHolder *)_getOrCreateTurboModuleHolder:(const char *)moduleName } /** - * Broadcast that this TurboModule was created. + * Broadcast that this NativeModule was created. * * TODO(T41180176): Investigate whether we can delete this after TM * rollout. @@ -644,10 +633,10 @@ - (TurboModuleHolder *)_getOrCreateTurboModuleHolder:(const char *)moduleName } /** - * Should this TurboModule be created and initialized on the main queue? + * Should this NativeModule be created and initialized on the main queue? * - * For TurboModule ObjC classes that implement requiresMainQueueInit, return the result of this method. - * For TurboModule ObjC classes that don't. Return true if they have a custom init or constantsToExport method. + * For NativeModule ObjC classes that implement requiresMainQueueInit, return the result of this method. + * For NativeModule ObjC classes that don't. Return true if they have a custom init or constantsToExport method. */ - (BOOL)_requiresMainQueueSetup:(Class)moduleClass { @@ -685,7 +674,7 @@ - (BOOL)_requiresMainQueueSetup:(Class)moduleClass if (requiresMainQueueSetup) { RCTLogWarn( @"Module %@ requires main queue setup since it overrides `%s` but doesn't implement " - "`requiresMainQueueSetup`. In a future release React Native will default to initializing all native modules " + "`requiresMainQueueSetup`. In a future release React Native will default to initializing all NativeModules " "on a background thread unless explicitly opted-out of.", moduleClass, hasConstantsToExport ? "constantsToExport" @@ -760,7 +749,7 @@ - (id)moduleForName:(const char *)moduleName warnOnLookupFailure:(BOOL)warnOnLoo return nil; } - id module = [self provideRCTTurboModule:moduleName]; + id module = [self _provideObjCModule:moduleName]; if (warnOnLookupFailure && !module) { RCTLogError(@"Unable to find module for %@", [NSString stringWithUTF8String:moduleName]); @@ -771,8 +760,8 @@ - (id)moduleForName:(const char *)moduleName warnOnLookupFailure:(BOOL)warnOnLoo - (BOOL)moduleIsInitialized:(const char *)moduleName { - std::unique_lock guard(_turboModuleHoldersMutex); - return _turboModuleHolders.find(moduleName) != _turboModuleHolders.end(); + std::unique_lock guard(_moduleHoldersMutex); + return _moduleHolders.find(moduleName) != _moduleHolders.end(); } #pragma mark Invalidation logic @@ -805,8 +794,8 @@ - (void)invalidate - (void)_enterInvalidatingState { - // This should halt all insertions into _turboModuleHolders - std::lock_guard guard(_turboModuleHoldersMutex); + // This should halt all insertions into _moduleHolders + std::lock_guard guard(_moduleHoldersMutex); _invalidating = true; } @@ -815,25 +804,25 @@ - (void)_invalidateModules // Backward-compatibility: RCTInvalidating handling. dispatch_group_t moduleInvalidationGroup = dispatch_group_create(); - for (auto &pair : _turboModuleHolders) { + for (auto &pair : _moduleHolders) { std::string moduleName = pair.first; - TurboModuleHolder *moduleHolder = &pair.second; + ModuleHolder *moduleHolder = &pair.second; /** - * We could start tearing down ReactNative before a TurboModule is fully initialized. In this case, we should wait - * for TurboModule init to finish before calling invalidate on it. So, we call _provideRCTTurboModule:moduleHolder, - * because it's guaranteed to return a fully initialized NativeModule. + * We could start tearing down ReactNative before a NativeModule is fully initialized. In this case, we should wait + * for NativeModule init to finish before calling invalidate on it. So, we call + * _provideObjCModule:moduleHolder, because it's guaranteed to return a fully initialized NativeModule. */ - id module = [self _provideRCTTurboModule:moduleName.c_str() - moduleHolder:moduleHolder - shouldPerfLog:NO]; + id module = [self _provideObjCModule:moduleName.c_str() + moduleHolder:moduleHolder + shouldPerfLog:NO]; if ([module respondsToSelector:@selector(invalidate)]) { dispatch_queue_t methodQueue = (dispatch_queue_t)objc_getAssociatedObject(module, &kAssociatedMethodQueueKey); if (methodQueue == nil) { RCTLogError( - @"TurboModuleManager: Couldn't invalidate TurboModule \"%@\", because its method queue is nil.", + @"TurboModuleManager: Couldn't invalidate NativeModule \"%@\", because its method queue is nil.", [module class]); continue; } @@ -861,7 +850,7 @@ - (void)_invalidateModules RCTLogError(@"TurboModuleManager: Timed out waiting for modules to be invalidated"); } - _turboModuleHolders.clear(); + _moduleHolders.clear(); _turboModuleCache.clear(); } diff --git a/packages/react-native/ReactCommon/react/nativemodule/samples/ReactCommon-Samples.podspec b/packages/react-native/ReactCommon/react/nativemodule/samples/ReactCommon-Samples.podspec index 20bc81f09dd1df..ddccfded01041d 100644 --- a/packages/react-native/ReactCommon/react/nativemodule/samples/ReactCommon-Samples.podspec +++ b/packages/react-native/ReactCommon/react/nativemodule/samples/ReactCommon-Samples.podspec @@ -55,5 +55,7 @@ Pod::Spec.new do |s| if using_hermes s.dependency "hermes-engine" + else + s.dependency "React-jsi" end end diff --git a/packages/react-native/ReactCommon/react/renderer/componentregistry/ComponentDescriptorRegistry.cpp b/packages/react-native/ReactCommon/react/renderer/componentregistry/ComponentDescriptorRegistry.cpp index 2d85ec352734ba..892464bc9cc122 100644 --- a/packages/react-native/ReactCommon/react/renderer/componentregistry/ComponentDescriptorRegistry.cpp +++ b/packages/react-native/ReactCommon/react/renderer/componentregistry/ComponentDescriptorRegistry.cpp @@ -136,8 +136,7 @@ ShadowNode::Shared ComponentDescriptorRegistry::createNode( PropsParserContext{surfaceId, *contextContainer_.get()}, nullptr, RawProps(propsDynamic)); - auto const state = - componentDescriptor.createInitialState(ShadowNodeFragment{props}, family); + auto const state = componentDescriptor.createInitialState(props, family); return componentDescriptor.createShadowNode( { diff --git a/packages/react-native/ReactCommon/react/renderer/componentregistry/componentNameByReactViewName.cpp b/packages/react-native/ReactCommon/react/renderer/componentregistry/componentNameByReactViewName.cpp index f50a76ab01fa79..de9e32008760d8 100644 --- a/packages/react-native/ReactCommon/react/renderer/componentregistry/componentNameByReactViewName.cpp +++ b/packages/react-native/ReactCommon/react/renderer/componentregistry/componentNameByReactViewName.cpp @@ -6,6 +6,7 @@ */ #include "componentNameByReactViewName.h" +#include namespace facebook::react { diff --git a/packages/react-native/ReactCommon/react/renderer/componentregistry/native/NativeComponentRegistryBinding.cpp b/packages/react-native/ReactCommon/react/renderer/componentregistry/native/NativeComponentRegistryBinding.cpp index d3e071d0f2f71b..17c8a78ef0a512 100644 --- a/packages/react-native/ReactCommon/react/renderer/componentregistry/native/NativeComponentRegistryBinding.cpp +++ b/packages/react-native/ReactCommon/react/renderer/componentregistry/native/NativeComponentRegistryBinding.cpp @@ -7,60 +7,22 @@ #include "NativeComponentRegistryBinding.h" +#include #include #include -using namespace facebook; - namespace facebook::react { /** - * Public API to install the NativeComponentRegistryBinding. + * Public API to install the Native Component Registry bindings. */ -NativeComponentRegistryBinding::NativeComponentRegistryBinding( - const HasComponentProviderFunctionType &&hasComponentProvider) - : hasComponentProvider_(hasComponentProvider) {} - -void NativeComponentRegistryBinding::install( +void bindHasComponentProvider( jsi::Runtime &runtime, - const HasComponentProviderFunctionType &&hasComponentProvider) { + HasComponentProviderFunctionType &&provider) { runtime.global().setProperty( runtime, "__nativeComponentRegistry__hasComponent", - jsi::Function::createFromHostFunction( - runtime, - jsi::PropNameID::forAscii( - runtime, "__nativeComponentRegistry__hasComponent"), - 1, - [binding = std::make_shared( - std::move(hasComponentProvider))]( - jsi::Runtime &rt, - const jsi::Value &thisVal, - const jsi::Value *args, - size_t count) { - return binding->jsProxy(rt, thisVal, args, count); - })); -} - -bool NativeComponentRegistryBinding::hasComponent(const std::string &name) { - return hasComponentProvider_(name); -} - -jsi::Value NativeComponentRegistryBinding::jsProxy( - jsi::Runtime &runtime, - const jsi::Value & /*thisVal*/, - const jsi::Value *args, - size_t count) { - if (count != 1) { - throw std::invalid_argument( - "__nativeComponentRegistry__hasComponent must be called with 1 argument"); - } - std::string moduleName = args[0].getString(runtime).utf8(runtime); - jsi::Value nullSchema = jsi::Value::undefined(); - - bool result = hasComponent(moduleName); - - return {result}; + bridging::toJs(runtime, provider, {})); } } // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/componentregistry/native/NativeComponentRegistryBinding.h b/packages/react-native/ReactCommon/react/renderer/componentregistry/native/NativeComponentRegistryBinding.h index ce60ff514d57cd..de5ce1cd9c0c6b 100644 --- a/packages/react-native/ReactCommon/react/renderer/componentregistry/native/NativeComponentRegistryBinding.h +++ b/packages/react-native/ReactCommon/react/renderer/componentregistry/native/NativeComponentRegistryBinding.h @@ -20,40 +20,12 @@ namespace facebook::react { using HasComponentProviderFunctionType = std::function; -/** - * Represents the JavaScript binding for the HasComponent global function. +/* + * Installs HasComponentProviderFunction into JavaScript runtime. + * Thread synchronization must be enforced externally. */ -class NativeComponentRegistryBinding { - public: - /* - * Installs NativeComponentRegistryBinding into JavaScript runtime. - * Thread synchronization must be enforced externally. - */ - static void install( - jsi::Runtime &runtime, - const HasComponentProviderFunctionType &&provider); - - NativeComponentRegistryBinding( - const HasComponentProviderFunctionType &&provider); - - /** - * Returns if there's a component registered with the name received as a - * parameter - */ - bool hasComponent(const std::string &name); - - private: - /** - * A lookup function exposed to JS to determine if a component is registered - * in the native platform. - */ - jsi::Value jsProxy( - jsi::Runtime &runtime, - const jsi::Value &thisVal, - const jsi::Value *args, - size_t count); - - HasComponentProviderFunctionType hasComponentProvider_; -}; +void bindHasComponentProvider( + jsi::Runtime &runtime, + HasComponentProviderFunctionType &&provider); } // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/components/image/ImageShadowNode.h b/packages/react-native/ReactCommon/react/renderer/components/image/ImageShadowNode.h index 402fa5b93b2317..be233e807b1898 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/image/ImageShadowNode.h +++ b/packages/react-native/ReactCommon/react/renderer/components/image/ImageShadowNode.h @@ -41,7 +41,7 @@ class ImageShadowNode final : public ConcreteViewShadowNode< void setImageManager(const SharedImageManager &imageManager); static ImageState initialStateData( - ShadowNodeFragment const &fragment, + Props::Shared const &props, ShadowNodeFamilyFragment const &familyFragment, ComponentDescriptor const &componentDescriptor) { auto imageSource = ImageSource{ImageSource::Type::Invalid}; diff --git a/packages/react-native/ReactCommon/react/renderer/components/scrollview/ScrollViewShadowNode.cpp b/packages/react-native/ReactCommon/react/renderer/components/scrollview/ScrollViewShadowNode.cpp index f4d7a883b18393..7fe5a502133b0b 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/scrollview/ScrollViewShadowNode.cpp +++ b/packages/react-native/ReactCommon/react/renderer/components/scrollview/ScrollViewShadowNode.cpp @@ -48,6 +48,13 @@ void ScrollViewShadowNode::updateScrollContentOffsetIfNeeded() { #endif } +ScrollViewState ScrollViewShadowNode::initialStateData( + Props::Shared const &props, + const ShadowNodeFamilyFragment & /*familyFragment*/, + const ComponentDescriptor & /*componentDescriptor*/) { + return {static_cast(*props).contentOffset, {}, 0}; +} + #pragma mark - LayoutableShadowNode void ScrollViewShadowNode::layout(LayoutContext layoutContext) { diff --git a/packages/react-native/ReactCommon/react/renderer/components/scrollview/ScrollViewShadowNode.h b/packages/react-native/ReactCommon/react/renderer/components/scrollview/ScrollViewShadowNode.h index e4949ada81c3d9..3d2447fe3d9035 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/scrollview/ScrollViewShadowNode.h +++ b/packages/react-native/ReactCommon/react/renderer/components/scrollview/ScrollViewShadowNode.h @@ -28,6 +28,11 @@ class ScrollViewShadowNode final : public ConcreteViewShadowNode< public: using ConcreteViewShadowNode::ConcreteViewShadowNode; + static ScrollViewState initialStateData( + Props::Shared const &props, + ShadowNodeFamilyFragment const &familyFragment, + ComponentDescriptor const &componentDescriptor); + #pragma mark - LayoutableShadowNode void layout(LayoutContext layoutContext) override; diff --git a/packages/react-native/ReactCommon/react/renderer/components/scrollview/ScrollViewState.cpp b/packages/react-native/ReactCommon/react/renderer/components/scrollview/ScrollViewState.cpp index ac184051d68c4b..f775268873f64e 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/scrollview/ScrollViewState.cpp +++ b/packages/react-native/ReactCommon/react/renderer/components/scrollview/ScrollViewState.cpp @@ -9,6 +9,14 @@ namespace facebook::react { +ScrollViewState::ScrollViewState( + Point contentOffset, + Rect contentBoundingRect, + int scrollAwayPaddingTop) + : contentOffset(contentOffset), + contentBoundingRect(contentBoundingRect), + scrollAwayPaddingTop(scrollAwayPaddingTop) {} + Size ScrollViewState::getContentSize() const { return contentBoundingRect.size; } diff --git a/packages/react-native/ReactCommon/react/renderer/components/scrollview/ScrollViewState.h b/packages/react-native/ReactCommon/react/renderer/components/scrollview/ScrollViewState.h index 2692831f9ef3c4..b6216126ff04dd 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/scrollview/ScrollViewState.h +++ b/packages/react-native/ReactCommon/react/renderer/components/scrollview/ScrollViewState.h @@ -25,6 +25,12 @@ namespace facebook::react { */ class ScrollViewState final { public: + ScrollViewState( + Point contentOffset, + Rect contentBoundingRect, + int scrollAwayPaddingTop); + ScrollViewState() = default; + Point contentOffset; Rect contentBoundingRect; int scrollAwayPaddingTop; @@ -35,7 +41,6 @@ class ScrollViewState final { Size getContentSize() const; #ifdef ANDROID - ScrollViewState() = default; ScrollViewState(ScrollViewState const &previousState, folly::dynamic data) : contentOffset( {(Float)data["contentOffsetLeft"].getDouble(), diff --git a/packages/react-native/ReactCommon/react/renderer/components/scrollview/primitives.h b/packages/react-native/ReactCommon/react/renderer/components/scrollview/primitives.h index 80adadd8f07e50..5a5f8b1a0c3ccc 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/scrollview/primitives.h +++ b/packages/react-native/ReactCommon/react/renderer/components/scrollview/primitives.h @@ -8,6 +8,7 @@ #pragma once #include +#include namespace facebook::react { diff --git a/packages/react-native/ReactCommon/react/renderer/components/text/ParagraphLayoutManager.cpp b/packages/react-native/ReactCommon/react/renderer/components/text/ParagraphLayoutManager.cpp index 1f4cbc4a4974ee..c4a5e886c70d66 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/text/ParagraphLayoutManager.cpp +++ b/packages/react-native/ReactCommon/react/renderer/components/text/ParagraphLayoutManager.cpp @@ -15,40 +15,18 @@ TextMeasurement ParagraphLayoutManager::measure( AttributedString const &attributedString, ParagraphAttributes const ¶graphAttributes, LayoutConstraints layoutConstraints) const { - bool cacheLastTextMeasurement = CoreFeatures::cacheLastTextMeasurement; - if (cacheLastTextMeasurement && - (layoutConstraints.maximumSize.width == availableWidth_ || - layoutConstraints.maximumSize.width == - cachedTextMeasurement_.size.width)) { - /* Yoga has requested measurement for this size before. Let's use cached - * value. `TextLayoutManager` might not have cached this because it could be - * using different width to generate cache key. This happens because Yoga - * switches between available width and exact width but since we already - * know exact width, it is wasteful to calculate it again. - */ - return cachedTextMeasurement_; - } - if (CoreFeatures::cacheNSTextStorage) { - size_t newHash = folly::hash::hash_combine( - 0, - textAttributedStringHashLayoutWise(attributedString), - paragraphAttributes); + if (CoreFeatures::cacheLastTextMeasurement) { + bool shouldMeasure = shoudMeasureString( + attributedString, paragraphAttributes, layoutConstraints); - if (!hostTextStorage_ || newHash != hash_) { - hostTextStorage_ = textLayoutManager_->getHostTextStorage( - attributedString, paragraphAttributes, layoutConstraints); - hash_ = newHash; + if (shouldMeasure) { + cachedTextMeasurement_ = textLayoutManager_->measure( + AttributedStringBox(attributedString), + paragraphAttributes, + layoutConstraints, + hostTextStorage_); + lastAvailableWidth_ = layoutConstraints.maximumSize.width; } - } - - if (cacheLastTextMeasurement) { - cachedTextMeasurement_ = textLayoutManager_->measure( - AttributedStringBox(attributedString), - paragraphAttributes, - layoutConstraints, - hostTextStorage_); - - availableWidth_ = layoutConstraints.maximumSize.width; return cachedTextMeasurement_; } else { @@ -56,8 +34,41 @@ TextMeasurement ParagraphLayoutManager::measure( AttributedStringBox(attributedString), paragraphAttributes, layoutConstraints, - hostTextStorage_); + nullptr); + } +} + +bool ParagraphLayoutManager::shoudMeasureString( + AttributedString const &attributedString, + ParagraphAttributes const ¶graphAttributes, + LayoutConstraints layoutConstraints) const { + size_t newHash = folly::hash::hash_combine( + 0, + textAttributedStringHashLayoutWise(attributedString), + paragraphAttributes); + + if (newHash != paragraphInputHash_) { + // AttributedString or ParagraphAttributes have changed. + // Must create new host text storage and trigger measure. + hostTextStorage_ = textLayoutManager_->getHostTextStorage( + attributedString, paragraphAttributes, layoutConstraints); + paragraphInputHash_ = newHash; + return true; // Must measure again. + } + + bool hasMaximumSizeChanged = + layoutConstraints.maximumSize.width != lastAvailableWidth_; + Float threshold = 0.01; + bool doesMaximumSizeMatchLastMeasurement = + std::abs( + layoutConstraints.maximumSize.width - + cachedTextMeasurement_.size.width) < threshold; + if (hasMaximumSizeChanged && !doesMaximumSizeMatchLastMeasurement) { + hostTextStorage_ = textLayoutManager_->getHostTextStorage( + attributedString, paragraphAttributes, layoutConstraints); + return true; } + return false; } LinesMeasurements ParagraphLayoutManager::measureLines( diff --git a/packages/react-native/ReactCommon/react/renderer/components/text/ParagraphLayoutManager.h b/packages/react-native/ReactCommon/react/renderer/components/text/ParagraphLayoutManager.h index d262db62b8c9ee..9583aae501baeb 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/text/ParagraphLayoutManager.h +++ b/packages/react-native/ReactCommon/react/renderer/components/text/ParagraphLayoutManager.h @@ -52,20 +52,41 @@ class ParagraphLayoutManager { private: std::shared_ptr mutable textLayoutManager_{}; + + /* + * Stores opaque pointer to `NSTextStorage` on iOS. nullptr on Android. + * TODO: In the future, we may want to cache Android's text storage. + */ std::shared_ptr mutable hostTextStorage_{}; + /* + * Hash of AttributedString and ParagraphAttributes last used to + * measure. Result of that measure is stored in cachedTextMeasurement_. + * The available width defined for the measurement is stored in + * lastAvailableWidth_. + */ + size_t mutable paragraphInputHash_{}; + /* The width Yoga set as maximum width. - * Yoga sometimes calls measure twice with two - * different maximum width. One if available space. + * Yoga calls measure twice with two + * different maximum width. One of available space. * The other one is exact space needed for the string. * This happens when node is dirtied but its size is not affected. * To deal with this inefficiency, we cache `TextMeasurement` for each * `ParagraphShadowNode`. If Yoga tries to re-measure with available width * or exact width, we provide it with the cached value. */ - Float mutable availableWidth_{}; + Float mutable lastAvailableWidth_{}; TextMeasurement mutable cachedTextMeasurement_{}; - size_t mutable hash_{}; + /* + * Checks whether the inputs into text measurement meaningfully affect + * text measurement result. Returns true if inputs have changed and measure is + * needed. + */ + bool shoudMeasureString( + AttributedString const &attributedString, + ParagraphAttributes const ¶graphAttributes, + LayoutConstraints layoutConstraints) const; }; } // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/components/textinput/androidtextinput/react/renderer/components/androidtextinput/AndroidTextInputComponentDescriptor.h b/packages/react-native/ReactCommon/react/renderer/components/textinput/androidtextinput/react/renderer/components/androidtextinput/AndroidTextInputComponentDescriptor.h index 87b22b503bbd27..33f183d58e3738 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/textinput/androidtextinput/react/renderer/components/androidtextinput/AndroidTextInputComponentDescriptor.h +++ b/packages/react-native/ReactCommon/react/renderer/components/textinput/androidtextinput/react/renderer/components/androidtextinput/AndroidTextInputComponentDescriptor.h @@ -34,7 +34,7 @@ class AndroidTextInputComponentDescriptor final } virtual State::Shared createInitialState( - ShadowNodeFragment const &fragment, + Props::Shared const &props, ShadowNodeFamily::Shared const &family) const override { int surfaceId = family->getSurfaceId(); diff --git a/packages/react-native/ReactCommon/react/renderer/components/view/YogaLayoutableShadowNode.cpp b/packages/react-native/ReactCommon/react/renderer/components/view/YogaLayoutableShadowNode.cpp index 8e20136627a6a1..fb4e57deaff801 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/view/YogaLayoutableShadowNode.cpp +++ b/packages/react-native/ReactCommon/react/renderer/components/view/YogaLayoutableShadowNode.cpp @@ -103,10 +103,8 @@ YogaLayoutableShadowNode::YogaLayoutableShadowNode( ShadowNodeFragment const &fragment) : LayoutableShadowNode(sourceShadowNode, fragment), yogaConfig_(FabricDefaultYogaLog), - yogaNode_( - static_cast(sourceShadowNode) - .yogaNode_, - &initializeYogaConfig(yogaConfig_)) { + yogaNode_(static_cast(sourceShadowNode) + .yogaNode_) { // Note, cloned `YGNode` instance (copied using copy-constructor) inherits // dirty flag, measure function, and other properties being set originally in // the `YogaLayoutableShadowNode` constructor above. @@ -122,8 +120,13 @@ YogaLayoutableShadowNode::YogaLayoutableShadowNode( } } + YGConfigRef previousConfig = YGNodeGetConfig( + &static_cast(sourceShadowNode) + .yogaNode_); + yogaNode_.setContext(this); yogaNode_.setOwner(nullptr); + yogaNode_.setConfig(&initializeYogaConfig(yogaConfig_, previousConfig)); updateYogaChildrenOwnersIfNeeded(); // This is the only legit place where we can dirty cloned Yoga node. @@ -489,7 +492,7 @@ void YogaLayoutableShadowNode::layoutTree( * the only value in the config of the root node is taken into account * (and this is by design). */ - yogaConfig_.pointScaleFactor = layoutContext.pointScaleFactor; + YGConfigSetPointScaleFactor(&yogaConfig_, layoutContext.pointScaleFactor); auto minimumSize = layoutConstraints.minimumSize; auto maximumSize = layoutConstraints.maximumSize; @@ -743,12 +746,19 @@ YogaLayoutableShadowNode &YogaLayoutableShadowNode::shadowNodeFromContext( *static_cast(yogaNode->getContext())); } -YGConfig &YogaLayoutableShadowNode::initializeYogaConfig(YGConfig &config) { - config.setCloneNodeCallback( - YogaLayoutableShadowNode::yogaNodeCloneCallbackConnector); - config.useLegacyStretchBehaviour = true; +YGConfig &YogaLayoutableShadowNode::initializeYogaConfig( + YGConfig &config, + const YGConfigRef previousConfig) { + YGConfigSetCloneNodeFunc( + &config, YogaLayoutableShadowNode::yogaNodeCloneCallbackConnector); + YGConfigSetErrata(&config, YGErrataAll); + if (previousConfig != nullptr) { + YGConfigSetPointScaleFactor( + &config, YGConfigGetPointScaleFactor(previousConfig)); + } + #ifdef RN_DEBUG_YOGA_LOGGER - config.printTree = true; + YGConfigSetPrintTreeFlag(&config, true); #endif return config; } diff --git a/packages/react-native/ReactCommon/react/renderer/components/view/YogaLayoutableShadowNode.h b/packages/react-native/ReactCommon/react/renderer/components/view/YogaLayoutableShadowNode.h index 9ad7f28cf03312..9456b0ccc0b1a7 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/view/YogaLayoutableShadowNode.h +++ b/packages/react-native/ReactCommon/react/renderer/components/view/YogaLayoutableShadowNode.h @@ -132,7 +132,9 @@ class YogaLayoutableShadowNode : public LayoutableShadowNode { */ void adoptYogaChild(size_t index); - static YGConfig &initializeYogaConfig(YGConfig &config); + static YGConfig &initializeYogaConfig( + YGConfig &config, + YGConfigRef previousConfig = nullptr); static YGNode *yogaNodeCloneCallbackConnector( YGNode *oldYogaNode, YGNode *parentYogaNode, diff --git a/packages/react-native/ReactCommon/react/renderer/components/view/conversions.h b/packages/react-native/ReactCommon/react/renderer/components/view/conversions.h index c5dc7d638c033a..85191d843731df 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/view/conversions.h +++ b/packages/react-native/ReactCommon/react/renderer/components/view/conversions.h @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include @@ -408,19 +407,14 @@ inline void fromRawValue( const PropsParserContext &context, const RawValue &value, YGStyle::ValueRepr &result) { - // For bug compatibility, pass "auto" as YGValueUndefined - static bool treatAutoAsUndefined = - context.contextContainer - .at>("ReactNativeConfig") - ->getBool("react_fabric:treat_auto_as_undefined"); - if (value.hasType()) { result = yogaStyleValueFromFloat((Float)value); return; } else if (value.hasType()) { const auto stringValue = (std::string)value; if (stringValue == "auto") { - result = treatAutoAsUndefined ? YGValueUndefined : YGValueAuto; + result = context.treatAutoAsYGValueUndefined() ? YGValueUndefined + : YGValueAuto; return; } else { if (stringValue.back() == '%') { @@ -455,18 +449,8 @@ inline void fromRawValue( const PropsParserContext &context, const RawValue &value, YGFloatOptional &result) { - if (value.hasType()) { - result = YGFloatOptional((float)value); - return; - } else if (value.hasType()) { - const auto stringValue = (std::string)value; - if (stringValue == "auto") { - result = YGFloatOptional(); - return; - } - } - LOG(ERROR) << "Could not parse YGFloatOptional"; - react_native_expect(false); + result = value.hasType() ? YGFloatOptional((float)value) + : YGFloatOptional(); } inline Float toRadians( diff --git a/packages/react-native/ReactCommon/react/renderer/core/CMakeLists.txt b/packages/react-native/ReactCommon/react/renderer/core/CMakeLists.txt index d776881dda16b4..cbbaa6f1f3999e 100644 --- a/packages/react-native/ReactCommon/react/renderer/core/CMakeLists.txt +++ b/packages/react-native/ReactCommon/react/renderer/core/CMakeLists.txt @@ -23,6 +23,7 @@ target_link_libraries(react_render_core folly_runtime glog jsi + react_config react_debug react_render_debug react_render_graphics diff --git a/packages/react-native/ReactCommon/react/renderer/core/ComponentDescriptor.h b/packages/react-native/ReactCommon/react/renderer/core/ComponentDescriptor.h index a0d6f137a899d2..c7ced77e41b652 100644 --- a/packages/react-native/ReactCommon/react/renderer/core/ComponentDescriptor.h +++ b/packages/react-native/ReactCommon/react/renderer/core/ComponentDescriptor.h @@ -121,7 +121,7 @@ class ComponentDescriptor { * State's data which can be constructed based on initial Props. */ virtual State::Shared createInitialState( - ShadowNodeFragment const &fragment, + Props::Shared const &props, ShadowNodeFamily::Shared const &family) const = 0; /* diff --git a/packages/react-native/ReactCommon/react/renderer/core/ConcreteComponentDescriptor.h b/packages/react-native/ReactCommon/react/renderer/core/ConcreteComponentDescriptor.h index 7d4d690a6d9e04..6a063b6265016d 100644 --- a/packages/react-native/ReactCommon/react/renderer/core/ConcreteComponentDescriptor.h +++ b/packages/react-native/ReactCommon/react/renderer/core/ConcreteComponentDescriptor.h @@ -151,7 +151,7 @@ class ConcreteComponentDescriptor : public ComponentDescriptor { }; virtual State::Shared createInitialState( - ShadowNodeFragment const &fragment, + Props::Shared const &props, ShadowNodeFamily::Shared const &family) const override { if (std::is_same::value) { // Default case: Returning `null` for nodes that don't use `State`. @@ -161,7 +161,7 @@ class ConcreteComponentDescriptor : public ComponentDescriptor { return std::make_shared( std::make_shared( ConcreteShadowNode::initialStateData( - fragment, ShadowNodeFamilyFragment::build(*family), *this)), + props, ShadowNodeFamilyFragment::build(*family), *this)), family); } diff --git a/packages/react-native/ReactCommon/react/renderer/core/ConcreteShadowNode.h b/packages/react-native/ReactCommon/react/renderer/core/ConcreteShadowNode.h index f61677645dfdff..b55d30fc4b51c9 100644 --- a/packages/react-native/ReactCommon/react/renderer/core/ConcreteShadowNode.h +++ b/packages/react-native/ReactCommon/react/renderer/core/ConcreteShadowNode.h @@ -86,7 +86,7 @@ class ConcreteShadowNode : public BaseShadowNodeT { } static ConcreteStateData initialStateData( - ShadowNodeFragment const &fragment, + Props::Shared const & /*props*/, ShadowNodeFamilyFragment const &familyFragment, ComponentDescriptor const &componentDescriptor) { return {}; diff --git a/packages/react-native/ReactCommon/react/renderer/core/ConcreteState.h b/packages/react-native/ReactCommon/react/renderer/core/ConcreteState.h index 952437e43ef73b..9a0f627b70e342 100644 --- a/packages/react-native/ReactCommon/react/renderer/core/ConcreteState.h +++ b/packages/react-native/ReactCommon/react/renderer/core/ConcreteState.h @@ -43,7 +43,7 @@ class ConcreteState : public State { ShadowNodeFamily::Shared const &family) : State(data, family) {} - virtual ~ConcreteState() = default; + ~ConcreteState() override = default; /* * Returns stored data. diff --git a/packages/react-native/ReactCommon/react/renderer/core/CoreFeatures.cpp b/packages/react-native/ReactCommon/react/renderer/core/CoreFeatures.cpp index f095e117ec8110..937e40aa0bf5ae 100644 --- a/packages/react-native/ReactCommon/react/renderer/core/CoreFeatures.cpp +++ b/packages/react-native/ReactCommon/react/renderer/core/CoreFeatures.cpp @@ -13,7 +13,7 @@ bool CoreFeatures::enablePropIteratorSetter = false; bool CoreFeatures::enableMapBuffer = false; bool CoreFeatures::blockPaintForUseLayoutEffect = false; bool CoreFeatures::useNativeState = false; -bool CoreFeatures::cacheNSTextStorage = false; bool CoreFeatures::cacheLastTextMeasurement = false; +bool CoreFeatures::cancelImageDownloadsOnRecycle = false; } // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/core/CoreFeatures.h b/packages/react-native/ReactCommon/react/renderer/core/CoreFeatures.h index 69b7f87d3b5840..5c49928e226513 100644 --- a/packages/react-native/ReactCommon/react/renderer/core/CoreFeatures.h +++ b/packages/react-native/ReactCommon/react/renderer/core/CoreFeatures.h @@ -34,15 +34,15 @@ class CoreFeatures { // in simple data passing scenarios with JS static bool useNativeState; - // Creating NSTextStorage is relatively expensive operation and we were - // creating it twice. Once when measuring text and once when rendering it. - // This flag caches it inside ParagraphState. - static bool cacheNSTextStorage; - // Yoga might measure multiple times the same Text with the same constraints // This flag enables a caching mechanism to avoid subsequents measurements // of the same Text with the same constrainst. + // On iOS, we also cache NSTextStorage. static bool cacheLastTextMeasurement; + + // Fabric was not cancelling image downloads when was removed + // from view hierarchy. This feature flag enables this feature. + static bool cancelImageDownloadsOnRecycle; }; } // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/core/PropsParserContext.cpp b/packages/react-native/ReactCommon/react/renderer/core/PropsParserContext.cpp new file mode 100644 index 00000000000000..0ceb9fe39e8733 --- /dev/null +++ b/packages/react-native/ReactCommon/react/renderer/core/PropsParserContext.cpp @@ -0,0 +1,27 @@ +/* + * 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. + */ + +#include "PropsParserContext.h" + +#include + +namespace facebook::react { + +bool PropsParserContext::treatAutoAsYGValueUndefined() const { + if (treatAutoAsYGValueUndefined_ == std::nullopt) { + auto config = + contextContainer.find>( + "ReactNativeConfig"); + treatAutoAsYGValueUndefined_ = config && *config != nullptr + ? (*config)->getBool("react_fabric:treat_auto_as_undefined") + : false; + } + + return *treatAutoAsYGValueUndefined_; +} + +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/core/PropsParserContext.h b/packages/react-native/ReactCommon/react/renderer/core/PropsParserContext.h index 04ec16f72f19e0..f79bd86b01e8de 100644 --- a/packages/react-native/ReactCommon/react/renderer/core/PropsParserContext.h +++ b/packages/react-native/ReactCommon/react/renderer/core/PropsParserContext.h @@ -7,6 +7,8 @@ #pragma once +#include + #include #include @@ -16,12 +18,23 @@ namespace facebook::react { // It should be used as infrequently as possible - most props can and should // be parsed without any context. struct PropsParserContext { + PropsParserContext( + SurfaceId const surfaceId, + ContextContainer const &contextContainer) + : surfaceId(surfaceId), contextContainer(contextContainer) {} + // Non-copyable PropsParserContext(const PropsParserContext &) = delete; PropsParserContext &operator=(const PropsParserContext &) = delete; SurfaceId const surfaceId; ContextContainer const &contextContainer; + + // Temporary feature flags + bool treatAutoAsYGValueUndefined() const; + + private: + mutable std::optional treatAutoAsYGValueUndefined_; }; } // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/core/ShadowNode.h b/packages/react-native/ReactCommon/react/renderer/core/ShadowNode.h index 0710143e9bea03..265dc9a921e56c 100644 --- a/packages/react-native/ReactCommon/react/renderer/core/ShadowNode.h +++ b/packages/react-native/ReactCommon/react/renderer/core/ShadowNode.h @@ -9,6 +9,7 @@ #include #include +#include #include #include @@ -225,4 +226,8 @@ class ShadowNode : public Sealable, ShadowNodeTraits traits_; }; +static_assert( + std::has_virtual_destructor::value, + "ShadowNode must have a virtual destructor"); + } // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/element/ComponentBuilder.cpp b/packages/react-native/ReactCommon/react/renderer/element/ComponentBuilder.cpp index d588b8737735fd..35973c49a2b3b2 100644 --- a/packages/react-native/ReactCommon/react/renderer/element/ComponentBuilder.cpp +++ b/packages/react-native/ReactCommon/react/renderer/element/ComponentBuilder.cpp @@ -31,19 +31,19 @@ ShadowNode::Unshared ComponentBuilder::build( elementFragment.tag, elementFragment.surfaceId, nullptr}, nullptr); - auto state = componentDescriptor.createInitialState( - ShadowNodeFragment{elementFragment.props}, family); + auto initialState = + componentDescriptor.createInitialState(elementFragment.props, family); auto constShadowNode = componentDescriptor.createShadowNode( ShadowNodeFragment{ elementFragment.props, std::make_shared(children), - state}, + initialState}, family); if (elementFragment.stateCallback) { auto newState = componentDescriptor.createState( - *family, elementFragment.stateCallback()); + *family, elementFragment.stateCallback(initialState)); constShadowNode = componentDescriptor.cloneShadowNode( *constShadowNode, ShadowNodeFragment{ diff --git a/packages/react-native/ReactCommon/react/renderer/element/Element.h b/packages/react-native/ReactCommon/react/renderer/element/Element.h index 57cd4119d7878a..dee0354d484b1c 100644 --- a/packages/react-native/ReactCommon/react/renderer/element/Element.h +++ b/packages/react-native/ReactCommon/react/renderer/element/Element.h @@ -92,9 +92,11 @@ class Element final { * Sets `state` using callback. */ Element &stateData(std::function callback) { - fragment_.stateCallback = [callback = - std::move(callback)]() -> StateData::Shared { - auto stateData = ConcreteStateData(); + fragment_.stateCallback = + [callback = std::move(callback)]( + State::Shared const &state) -> StateData::Shared { + auto stateData = + static_cast(state.get())->getData(); callback(stateData); return std::make_shared(stateData); }; diff --git a/packages/react-native/ReactCommon/react/renderer/element/ElementFragment.h b/packages/react-native/ReactCommon/react/renderer/element/ElementFragment.h index 5e9dfbc1322cbe..9623f9d84f1bf1 100644 --- a/packages/react-native/ReactCommon/react/renderer/element/ElementFragment.h +++ b/packages/react-native/ReactCommon/react/renderer/element/ElementFragment.h @@ -29,7 +29,8 @@ class ElementFragment final { using ReferenceCallback = std::function; using FinalizeCallback = std::function; - using StateCallback = std::function; + using StateCallback = + std::function; /* * ComponentDescriptor part (describes the type) diff --git a/packages/react-native/ReactCommon/react/renderer/imagemanager/ImageRequest.h b/packages/react-native/ReactCommon/react/renderer/imagemanager/ImageRequest.h index eaf4b1f6bf302c..78c1b4c8112704 100644 --- a/packages/react-native/ReactCommon/react/renderer/imagemanager/ImageRequest.h +++ b/packages/react-native/ReactCommon/react/renderer/imagemanager/ImageRequest.h @@ -34,20 +34,24 @@ class ImageRequest final { /* * The move constructor. */ - ImageRequest(ImageRequest &&other) noexcept; + ImageRequest(ImageRequest &&other) noexcept = default; /* * `ImageRequest` does not support copying by design. */ ImageRequest(const ImageRequest &other) = delete; - ~ImageRequest(); - /** * Set cancelation function. */ void setCancelationFunction(std::function cancelationFunction); + /* + * Calls cancel function if one is defined. Should be when downloading + * image isn't needed anymore. E.g. was removed. + */ + void cancel() const; + /* * Returns the Image Source associated with the request. */ diff --git a/packages/react-native/ReactCommon/react/renderer/imagemanager/platform/cxx/react/renderer/imagemanager/ImageRequest.cpp b/packages/react-native/ReactCommon/react/renderer/imagemanager/platform/cxx/react/renderer/imagemanager/ImageRequest.cpp index ce53a1b65cab3a..a502f65d9c305c 100644 --- a/packages/react-native/ReactCommon/react/renderer/imagemanager/platform/cxx/react/renderer/imagemanager/ImageRequest.cpp +++ b/packages/react-native/ReactCommon/react/renderer/imagemanager/platform/cxx/react/renderer/imagemanager/ImageRequest.cpp @@ -18,17 +18,6 @@ ImageRequest::ImageRequest( // Not implemented. } -ImageRequest::ImageRequest(ImageRequest &&other) noexcept - : imageSource_(std::move(other.imageSource_)), - telemetry_(std::move(other.telemetry_)), - coordinator_(std::move(other.coordinator_)) { - // Not implemented. -} - -ImageRequest::~ImageRequest() { - // Not implemented. -} - const ImageResponseObserverCoordinator &ImageRequest::getObserverCoordinator() const { // Not implemented diff --git a/packages/react-native/ReactCommon/react/renderer/imagemanager/platform/ios/React-ImageManager.podspec b/packages/react-native/ReactCommon/react/renderer/imagemanager/platform/ios/React-ImageManager.podspec index d6fbd78c6d0348..0ef251588cc351 100644 --- a/packages/react-native/ReactCommon/react/renderer/imagemanager/platform/ios/React-ImageManager.podspec +++ b/packages/react-native/ReactCommon/react/renderer/imagemanager/platform/ios/React-ImageManager.podspec @@ -61,4 +61,5 @@ Pod::Spec.new do |s| s.dependency "React-Fabric" s.dependency "React-Core/Default" s.dependency "React-RCTImage" + s.dependency "glog" end diff --git a/packages/react-native/ReactCommon/react/renderer/imagemanager/platform/ios/react/renderer/imagemanager/ImageRequest.cpp b/packages/react-native/ReactCommon/react/renderer/imagemanager/platform/ios/react/renderer/imagemanager/ImageRequest.cpp index e073cc6dfff469..cca7918e2d6d2c 100644 --- a/packages/react-native/ReactCommon/react/renderer/imagemanager/platform/ios/react/renderer/imagemanager/ImageRequest.cpp +++ b/packages/react-native/ReactCommon/react/renderer/imagemanager/platform/ios/react/renderer/imagemanager/ImageRequest.cpp @@ -16,27 +16,17 @@ ImageRequest::ImageRequest( coordinator_ = std::make_shared(); } -ImageRequest::ImageRequest(ImageRequest &&other) noexcept - : imageSource_(std::move(other.imageSource_)), - telemetry_(std::move(other.telemetry_)), - coordinator_(std::move(other.coordinator_)) { - other.coordinator_ = nullptr; - other.cancelRequest_ = nullptr; - other.telemetry_ = nullptr; - other.imageSource_ = {}; +void ImageRequest::setCancelationFunction( + std::function cancelationFunction) { + cancelRequest_ = cancelationFunction; } -ImageRequest::~ImageRequest() { +void ImageRequest::cancel() const { if (cancelRequest_) { cancelRequest_(); } } -void ImageRequest::setCancelationFunction( - std::function cancelationFunction) { - cancelRequest_ = cancelationFunction; -} - const ImageSource &ImageRequest::getImageSource() const { return imageSource_; } diff --git a/packages/react-native/ReactCommon/react/renderer/mounting/MountingCoordinator.h b/packages/react-native/ReactCommon/react/renderer/mounting/MountingCoordinator.h index a3523065d7dcb9..83e432a66b46a6 100644 --- a/packages/react-native/ReactCommon/react/renderer/mounting/MountingCoordinator.h +++ b/packages/react-native/ReactCommon/react/renderer/mounting/MountingCoordinator.h @@ -8,6 +8,7 @@ #pragma once #include +#include #include #include diff --git a/packages/react-native/ReactCommon/react/renderer/mounting/tests/MountingTest.cpp b/packages/react-native/ReactCommon/react/renderer/mounting/tests/MountingTest.cpp index c3dae1de96e6af..75945738a5af8a 100644 --- a/packages/react-native/ReactCommon/react/renderer/mounting/tests/MountingTest.cpp +++ b/packages/react-native/ReactCommon/react/renderer/mounting/tests/MountingTest.cpp @@ -31,7 +31,10 @@ static SharedViewProps nonFlattenedDefaultProps( dynamic["nativeId"] = "NativeId"; dynamic["accessible"] = true; - ContextContainer contextContainer{}; + ContextContainer contextContainer; + contextContainer.insert( + "ReactNativeConfig", std::make_shared()); + PropsParserContext parserContext{-1, contextContainer}; return std::static_pointer_cast( @@ -64,7 +67,11 @@ static ShadowNode::Shared makeNode( */ TEST(MountingTest, testReorderingInstructionGeneration) { auto eventDispatcher = EventDispatcher::Shared{}; + auto contextContainer = std::make_shared(); + contextContainer->insert( + "ReactNativeConfig", std::make_shared()); + auto componentDescriptorParameters = ComponentDescriptorParameters{eventDispatcher, contextContainer, nullptr}; auto viewComponentDescriptor = @@ -373,6 +380,9 @@ TEST(MountingTest, testReorderingInstructionGeneration) { TEST(MountingTest, testViewReparentingInstructionGeneration) { auto eventDispatcher = EventDispatcher::Shared{}; auto contextContainer = std::make_shared(); + contextContainer->insert( + "ReactNativeConfig", std::make_shared()); + auto componentDescriptorParameters = ComponentDescriptorParameters{eventDispatcher, contextContainer, nullptr}; auto viewComponentDescriptor = diff --git a/packages/react-native/ReactCommon/react/renderer/mounting/tests/ShadowTreeLifeCycleTest.cpp b/packages/react-native/ReactCommon/react/renderer/mounting/tests/ShadowTreeLifeCycleTest.cpp index 3837509311fff5..0e53a7ad9b70d8 100644 --- a/packages/react-native/ReactCommon/react/renderer/mounting/tests/ShadowTreeLifeCycleTest.cpp +++ b/packages/react-native/ReactCommon/react/renderer/mounting/tests/ShadowTreeLifeCycleTest.cpp @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -185,6 +186,9 @@ static void testShadowNodeTreeLifeCycleExtensiveFlatteningUnflattening( auto eventDispatcher = EventDispatcher::Shared{}; auto contextContainer = std::make_shared(); + contextContainer->insert( + "ReactNativeConfig", std::make_shared()); + auto componentDescriptorParameters = ComponentDescriptorParameters{eventDispatcher, contextContainer, nullptr}; auto viewComponentDescriptor = diff --git a/packages/react-native/ReactCommon/react/renderer/mounting/tests/StackingContextTest.cpp b/packages/react-native/ReactCommon/react/renderer/mounting/tests/StackingContextTest.cpp index f097523103697f..d3a3f8d129b3ca 100644 --- a/packages/react-native/ReactCommon/react/renderer/mounting/tests/StackingContextTest.cpp +++ b/packages/react-native/ReactCommon/react/renderer/mounting/tests/StackingContextTest.cpp @@ -769,16 +769,16 @@ TEST_F(StackingContextTest, zIndexAndFlattenedNodes) { testViewTree_([](StubViewTree const &viewTree) { // 5 views in total. - EXPECT_EQ(viewTree.size(), 8); + EXPECT_EQ(viewTree.size(), 5); // The root view has all 5 subviews. - EXPECT_EQ(viewTree.getRootStubView().children.size(), 5); + EXPECT_EQ(viewTree.getRootStubView().children.size(), 4); // The root view subviews are [6, 10, 9, 5]. - EXPECT_EQ(viewTree.getRootStubView().children.at(0)->tag, 6); - EXPECT_EQ(viewTree.getRootStubView().children.at(1)->tag, 10); - EXPECT_EQ(viewTree.getRootStubView().children.at(2)->tag, 9); - EXPECT_EQ(viewTree.getRootStubView().children.at(3)->tag, 5); + EXPECT_EQ(viewTree.getRootStubView().children.at(0)->tag, 10); + EXPECT_EQ(viewTree.getRootStubView().children.at(1)->tag, 9); + EXPECT_EQ(viewTree.getRootStubView().children.at(2)->tag, 5); + EXPECT_EQ(viewTree.getRootStubView().children.at(3)->tag, 3); }); } diff --git a/packages/react-native/ReactCommon/react/renderer/scheduler/Scheduler.cpp b/packages/react-native/ReactCommon/react/renderer/scheduler/Scheduler.cpp index 90d558985b9567..f800ed581a678c 100644 --- a/packages/react-native/ReactCommon/react/renderer/scheduler/Scheduler.cpp +++ b/packages/react-native/ReactCommon/react/renderer/scheduler/Scheduler.cpp @@ -131,6 +131,9 @@ Scheduler::Scheduler( CoreFeatures::blockPaintForUseLayoutEffect = reactNativeConfig_->getBool( "react_fabric:block_paint_for_use_layout_effect"); + CoreFeatures::cacheLastTextMeasurement = + reactNativeConfig_->getBool("react_fabric:enable_text_measure_cache"); + if (animationDelegate != nullptr) { animationDelegate->setComponentDescriptorRegistry( componentDescriptorRegistry_); diff --git a/packages/react-native/ReactCommon/react/renderer/scheduler/SurfaceHandler.cpp b/packages/react-native/ReactCommon/react/renderer/scheduler/SurfaceHandler.cpp index b1c4426a59b1bb..19f5e4476d9687 100644 --- a/packages/react-native/ReactCommon/react/renderer/scheduler/SurfaceHandler.cpp +++ b/packages/react-native/ReactCommon/react/renderer/scheduler/SurfaceHandler.cpp @@ -112,6 +112,7 @@ void SurfaceHandler::stop() const noexcept { } void SurfaceHandler::setDisplayMode(DisplayMode displayMode) const noexcept { + auto parameters = Parameters{}; { std::unique_lock lock(parametersMutex_); if (parameters_.displayMode == displayMode) { @@ -119,6 +120,7 @@ void SurfaceHandler::setDisplayMode(DisplayMode displayMode) const noexcept { } parameters_.displayMode = displayMode; + parameters = parameters_; } { @@ -129,10 +131,10 @@ void SurfaceHandler::setDisplayMode(DisplayMode displayMode) const noexcept { } link_.uiManager->setSurfaceProps( - parameters_.surfaceId, - parameters_.moduleName, - parameters_.props, - parameters_.displayMode); + parameters.surfaceId, + parameters.moduleName, + parameters.props, + parameters.displayMode); applyDisplayMode(displayMode); } @@ -162,8 +164,25 @@ std::string SurfaceHandler::getModuleName() const noexcept { void SurfaceHandler::setProps(folly::dynamic const &props) const noexcept { SystraceSection s("SurfaceHandler::setProps"); - std::unique_lock lock(parametersMutex_); - parameters_.props = props; + auto parameters = Parameters{}; + { + std::unique_lock lock(parametersMutex_); + + parameters_.props = props; + parameters = parameters_; + } + + { + std::shared_lock lock(linkMutex_); + + if (link_.status == Status::Running) { + link_.uiManager->setSurfaceProps( + parameters.surfaceId, + parameters.moduleName, + parameters.props, + parameters.displayMode); + } + } } folly::dynamic SurfaceHandler::getProps() const noexcept { diff --git a/packages/react-native/ReactCommon/react/renderer/uimanager/UIManager.cpp b/packages/react-native/ReactCommon/react/renderer/uimanager/UIManager.cpp index 6434457b9a10d8..2063d246c2cebd 100644 --- a/packages/react-native/ReactCommon/react/renderer/uimanager/UIManager.cpp +++ b/packages/react-native/ReactCommon/react/renderer/uimanager/UIManager.cpp @@ -80,8 +80,7 @@ ShadowNode::Shared UIManager::createNode( componentDescriptor.createFamily(fragment, std::move(eventTarget)); auto const props = componentDescriptor.cloneProps(propsParserContext, nullptr, rawProps); - auto const state = - componentDescriptor.createInitialState(ShadowNodeFragment{props}, family); + auto const state = componentDescriptor.createInitialState(props, family); auto shadowNode = componentDescriptor.createShadowNode( ShadowNodeFragment{ diff --git a/packages/react-native/ReactCommon/react/test_utils/shadowTreeGeneration.h b/packages/react-native/ReactCommon/react/test_utils/shadowTreeGeneration.h index 79ac907c909199..65307403d8e649 100644 --- a/packages/react-native/ReactCommon/react/test_utils/shadowTreeGeneration.h +++ b/packages/react-native/ReactCommon/react/test_utils/shadowTreeGeneration.h @@ -14,6 +14,7 @@ #include #include +#include #include #include #include @@ -237,7 +238,10 @@ static inline ShadowNode::Unshared messWithYogaStyles( } } - ContextContainer contextContainer{}; + ContextContainer contextContainer; + contextContainer.insert( + "ReactNativeConfig", std::make_shared()); + PropsParserContext parserContext{-1, contextContainer}; auto oldProps = shadowNode.getProps(); diff --git a/packages/react-native/ReactCommon/reactperflogger/reactperflogger/BridgeNativeModulePerfLogger.cpp b/packages/react-native/ReactCommon/reactperflogger/reactperflogger/BridgeNativeModulePerfLogger.cpp index 7c0da26878a1ff..616df655e099ad 100644 --- a/packages/react-native/ReactCommon/reactperflogger/reactperflogger/BridgeNativeModulePerfLogger.cpp +++ b/packages/react-native/ReactCommon/reactperflogger/reactperflogger/BridgeNativeModulePerfLogger.cpp @@ -7,8 +7,7 @@ #include "BridgeNativeModulePerfLogger.h" -namespace facebook { -namespace react { +namespace facebook::react { namespace BridgeNativeModulePerfLogger { std::unique_ptr g_perfLogger = nullptr; @@ -327,5 +326,4 @@ void asyncMethodCallExecutionFail( } } // namespace BridgeNativeModulePerfLogger -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/reactperflogger/reactperflogger/BridgeNativeModulePerfLogger.h b/packages/react-native/ReactCommon/reactperflogger/reactperflogger/BridgeNativeModulePerfLogger.h index c9593ec86f39c9..e1ed6d1cef8d25 100644 --- a/packages/react-native/ReactCommon/reactperflogger/reactperflogger/BridgeNativeModulePerfLogger.h +++ b/packages/react-native/ReactCommon/reactperflogger/reactperflogger/BridgeNativeModulePerfLogger.h @@ -9,8 +9,7 @@ #include #include "NativeModulePerfLogger.h" -namespace facebook { -namespace react { +namespace facebook::react { namespace BridgeNativeModulePerfLogger { void enableLogging(std::unique_ptr &&logger); @@ -109,5 +108,4 @@ void asyncMethodCallExecutionFail( } // namespace BridgeNativeModulePerfLogger -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/reactperflogger/reactperflogger/NativeModulePerfLogger.h b/packages/react-native/ReactCommon/reactperflogger/reactperflogger/NativeModulePerfLogger.h index 2cb386b48afb56..864ddfc1d32ebd 100644 --- a/packages/react-native/ReactCommon/reactperflogger/reactperflogger/NativeModulePerfLogger.h +++ b/packages/react-native/ReactCommon/reactperflogger/reactperflogger/NativeModulePerfLogger.h @@ -8,8 +8,7 @@ #pragma once #include -namespace facebook { -namespace react { +namespace facebook::react { /** * A platform-agnostic interface to do performance logging on NativeModules and @@ -160,5 +159,4 @@ class NativeModulePerfLogger { int32_t id) = 0; }; -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/runtimeexecutor/ReactCommon/RuntimeExecutor.h b/packages/react-native/ReactCommon/runtimeexecutor/ReactCommon/RuntimeExecutor.h index 1c5180918d6431..94f2b5d55f3293 100644 --- a/packages/react-native/ReactCommon/runtimeexecutor/ReactCommon/RuntimeExecutor.h +++ b/packages/react-native/ReactCommon/runtimeexecutor/ReactCommon/RuntimeExecutor.h @@ -12,8 +12,7 @@ #include -namespace facebook { -namespace react { +namespace facebook::react { /* * Takes a function and calls it with a reference to a Runtime. The function @@ -125,5 +124,4 @@ inline static DataT executeSynchronouslyOnSameThread_CAN_DEADLOCK( return data; } -} // namespace react -} // namespace facebook +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/yoga/CMakeLists.txt b/packages/react-native/ReactCommon/yoga/CMakeLists.txt index ff370aa76ebd05..644c6cb1b132e0 100644 --- a/packages/react-native/ReactCommon/yoga/CMakeLists.txt +++ b/packages/react-native/ReactCommon/yoga/CMakeLists.txt @@ -6,17 +6,9 @@ cmake_minimum_required(VERSION 3.13) set(CMAKE_VERBOSE_MAKEFILE on) -add_compile_options( - -fexceptions - -frtti - -O3 - -Wall - -Wpedantic - -Wno-gnu-zero-variadic-macro-arguments) +# Yoga by default does not enable optimizations in debug builds. Enable -O2 +# for all builds in RN for faster debug app performance (at the cost of not +# being able to debug inside Yoga) +set(CMAKE_BUILD_TYPE Release) -file(GLOB_RECURSE yogacore_SRC CONFIGURE_DEPENDS yoga/*.cpp) -add_library(yogacore STATIC ${yogacore_SRC}) - -target_include_directories(yogacore PUBLIC .) - -target_link_libraries(yogacore android log) +add_subdirectory(yoga) diff --git a/packages/react-native/ReactCommon/yoga/Yoga.podspec b/packages/react-native/ReactCommon/yoga/Yoga.podspec index e86ce76b356a89..7e68f6dc4fa5c4 100644 --- a/packages/react-native/ReactCommon/yoga/Yoga.podspec +++ b/packages/react-native/ReactCommon/yoga/Yoga.podspec @@ -51,7 +51,12 @@ Pod::Spec.new do |spec| source_files = File.join('ReactCommon/yoga', source_files) if ENV['INSTALL_YOGA_WITHOUT_PATH_OPTION'] spec.source_files = source_files - header_files = 'yoga/*.h' - header_files = File.join('ReactCommon/yoga', header_files) if ENV['INSTALL_YOGA_WITHOUT_PATH_OPTION'] - spec.public_header_files = header_files + public_header_files = 'yoga/{Yoga,YGEnums,YGMacros,YGValue}.h' + public_header_files = File.join('ReactCommon/yoga', public_header_files) if ENV['INSTALL_YOGA_WITHOUT_PATH_OPTION'] + spec.public_header_files = public_header_files + + # Fabric must be able to access private headers (which should not be included in the umbrella header) + all_header_files = 'yoga/**/*.h' + all_header_files = File.join('ReactCommon/yoga', all_header_files) if ENV['INSTALL_YOGA_WITHOUT_PATH_OPTION'] + spec.private_header_files = Dir.glob(all_header_files) - Dir.glob(public_header_files) end diff --git a/packages/react-native/ReactCommon/yoga/cmake/project-defaults.cmake b/packages/react-native/ReactCommon/yoga/cmake/project-defaults.cmake new file mode 100644 index 00000000000000..87f0e6b791a614 --- /dev/null +++ b/packages/react-native/ReactCommon/yoga/cmake/project-defaults.cmake @@ -0,0 +1,50 @@ +# 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. + +set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_VISIBILITY_PRESET hidden) +set(CMAKE_POSITION_INDEPENDENT_CODE ON) + +add_compile_definitions($<$:DEBUG>) + +if(MSVC) + +add_compile_options( + # Don't omit frame pointers (e.g. for crash dumps) + /Oy- + # "Standard C++ exception handling" (C++ stack unwinding including extern c) + /EHsc + # Enable warnings and warnings as errors + /W3 + /WX + # Disable RTTI + $<$:/GR-> + # Use /O2 (Maximize Speed) + $<$:/O2>) + +else() + +add_compile_options( + # Don't omit frame pointers (e.g. for crash dumps) + -fno-omit-frame-pointer + # Enable exception handling + -fexceptions + # Enable warnings and warnings as errors + -Wall + -Werror + # Disable RTTI + $<$:-fno-rtti> + # Use -O2 (prioritize speed) + $<$:-O2> + # Enable separate sections per function/data item + $<$:-ffunction-sections> + $<$:-fdata-sections>) + +add_link_options( + # Discard unused sections + $<$:$<$:-Wl,--gc-sections>> + $<$:$<$:-Wl,-dead_strip>>) + +endif() diff --git a/packages/react-native/ReactCommon/yoga/cmake/yoga-config.cmake.in b/packages/react-native/ReactCommon/yoga/cmake/yoga-config.cmake.in new file mode 100644 index 00000000000000..80b2dc51c838f1 --- /dev/null +++ b/packages/react-native/ReactCommon/yoga/cmake/yoga-config.cmake.in @@ -0,0 +1,10 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +@PACKAGE_INIT@ + +include("${CMAKE_CURRENT_LIST_DIR}/yogaTargets.cmake") + +check_required_components(yoga) \ No newline at end of file diff --git a/packages/react-native/ReactCommon/yoga/yoga/BitUtils.h b/packages/react-native/ReactCommon/yoga/yoga/BitUtils.h index a60ea7609cada3..e544defae72248 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/BitUtils.h +++ b/packages/react-native/ReactCommon/yoga/yoga/BitUtils.h @@ -7,17 +7,21 @@ #pragma once -#ifdef __cplusplus - +#include #include #include -#include "YGEnums.h" + +#include namespace facebook { namespace yoga { namespace detail { +// std::bitset with one bit for each option defined in YG_ENUM_SEQ_DECL +template +using EnumBitset = std::bitset()>; + constexpr size_t log2ceilFn(size_t n) { return n < 1 ? 0 : (1 + log2ceilFn(n / 2)); } @@ -67,5 +71,3 @@ inline void setBooleanData(uint8_t& flags, size_t index, bool value) { } // namespace detail } // namespace yoga } // namespace facebook - -#endif diff --git a/packages/react-native/ReactCommon/yoga/yoga/CompactValue.h b/packages/react-native/ReactCommon/yoga/yoga/CompactValue.h index e489fbb614d4dc..20462ce35d4fcc 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/CompactValue.h +++ b/packages/react-native/ReactCommon/yoga/yoga/CompactValue.h @@ -7,7 +7,12 @@ #pragma once -#ifdef __cplusplus +#include +#include +#include + +#include +#include #if defined(__has_include) && __has_include() // needed to be able to evaluate defined(__cpp_lib_bit_cast) @@ -22,11 +27,6 @@ #else #include #endif -#include "YGValue.h" -#include "YGMacros.h" -#include -#include -#include static_assert( std::numeric_limits::is_iec559, @@ -212,5 +212,3 @@ constexpr bool operator!=(CompactValue a, CompactValue b) noexcept { } // namespace detail } // namespace yoga } // namespace facebook - -#endif diff --git a/packages/react-native/ReactCommon/yoga/yoga/Utils.h b/packages/react-native/ReactCommon/yoga/yoga/Utils.h index 82867a5774a8bd..376c4fb55c7e7e 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/Utils.h +++ b/packages/react-native/ReactCommon/yoga/yoga/Utils.h @@ -7,8 +7,6 @@ #pragma once -#ifdef __cplusplus - #include "YGNode.h" #include "Yoga-internal.h" #include "CompactValue.h" @@ -146,5 +144,3 @@ inline YGFloatOptional YGResolveValueMargin( const float ownerSize) { return value.isAuto() ? YGFloatOptional{0} : YGResolveValue(value, ownerSize); } - -#endif diff --git a/packages/react-native/ReactCommon/yoga/yoga/YGConfig.cpp b/packages/react-native/ReactCommon/yoga/yoga/YGConfig.cpp index 915da52af77ac0..5bf85f4a1b82df 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/YGConfig.cpp +++ b/packages/react-native/ReactCommon/yoga/yoga/YGConfig.cpp @@ -7,9 +7,102 @@ #include "YGConfig.h" +using namespace facebook::yoga; + +namespace facebook { +namespace yoga { +bool configUpdateInvalidatesLayout(YGConfigRef a, YGConfigRef b) { + return a->getErrata() != b->getErrata() || + a->getEnabledExperiments() != b->getEnabledExperiments() || + a->getPointScaleFactor() != b->getPointScaleFactor() || + a->useWebDefaults() != b->useWebDefaults(); +} +} // namespace yoga +} // namespace facebook + YGConfig::YGConfig(YGLogger logger) : cloneNodeCallback_{nullptr} { + setLogger(logger); +} + +void YGConfig::setUseWebDefaults(bool useWebDefaults) { + flags_.useWebDefaults = useWebDefaults; +} + +bool YGConfig::useWebDefaults() const { + return flags_.useWebDefaults; +} + +void YGConfig::setShouldPrintTree(bool printTree) { + flags_.printTree = printTree; +} + +bool YGConfig::shouldPrintTree() const { + return flags_.printTree; +} + +void YGConfig::setExperimentalFeatureEnabled( + YGExperimentalFeature feature, + bool enabled) { + experimentalFeatures_.set(feature, enabled); +} + +bool YGConfig::isExperimentalFeatureEnabled( + YGExperimentalFeature feature) const { + return experimentalFeatures_.test(feature); +} + +ExperimentalFeatureSet YGConfig::getEnabledExperiments() const { + return experimentalFeatures_; +} + +void YGConfig::setErrata(YGErrata errata) { + errata_ = errata; +} + +void YGConfig::addErrata(YGErrata errata) { + errata_ |= errata; +} + +void YGConfig::removeErrata(YGErrata errata) { + errata_ &= (~errata); +} + +YGErrata YGConfig::getErrata() const { + return errata_; +} + +bool YGConfig::hasErrata(YGErrata errata) const { + return (errata_ & errata) != YGErrataNone; +} + +void YGConfig::setPointScaleFactor(float pointScaleFactor) { + pointScaleFactor_ = pointScaleFactor; +} + +float YGConfig::getPointScaleFactor() const { + return pointScaleFactor_; +} + +void YGConfig::setContext(void* context) { + context_ = context; +} + +void* YGConfig::getContext() const { + return context_; +} + +void YGConfig::setLogger(YGLogger logger) { logger_.noContext = logger; - loggerUsesContext_ = false; + flags_.loggerUsesContext = false; +} + +void YGConfig::setLogger(LogWithContextFn logger) { + logger_.withContext = logger; + flags_.loggerUsesContext = true; +} + +void YGConfig::setLogger(std::nullptr_t) { + setLogger(YGLogger{nullptr}); } void YGConfig::log( @@ -18,22 +111,36 @@ void YGConfig::log( YGLogLevel logLevel, void* logContext, const char* format, - va_list args) { - if (loggerUsesContext_) { + va_list args) const { + if (flags_.loggerUsesContext) { logger_.withContext(config, node, logLevel, logContext, format, args); } else { logger_.noContext(config, node, logLevel, format, args); } } +void YGConfig::setCloneNodeCallback(YGCloneNodeFunc cloneNode) { + cloneNodeCallback_.noContext = cloneNode; + flags_.cloneNodeUsesContext = false; +} + +void YGConfig::setCloneNodeCallback(CloneWithContextFn cloneNode) { + cloneNodeCallback_.withContext = cloneNode; + flags_.cloneNodeUsesContext = true; +} + +void YGConfig::setCloneNodeCallback(std::nullptr_t) { + setCloneNodeCallback(YGCloneNodeFunc{nullptr}); +} + YGNodeRef YGConfig::cloneNode( YGNodeRef node, YGNodeRef owner, int childIndex, - void* cloneContext) { + void* cloneContext) const { YGNodeRef clone = nullptr; if (cloneNodeCallback_.noContext != nullptr) { - clone = cloneNodeUsesContext_ + clone = flags_.cloneNodeUsesContext ? cloneNodeCallback_.withContext(node, owner, childIndex, cloneContext) : cloneNodeCallback_.noContext(node, owner, childIndex); } diff --git a/packages/react-native/ReactCommon/yoga/yoga/YGConfig.h b/packages/react-native/ReactCommon/yoga/yoga/YGConfig.h index e15cc1225334e0..d7c7f49fde979f 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/YGConfig.h +++ b/packages/react-native/ReactCommon/yoga/yoga/YGConfig.h @@ -7,75 +7,104 @@ #pragma once -#ifdef __cplusplus +#include +#include "BitUtils.h" #include "Yoga-internal.h" -#include "Yoga.h" + +namespace facebook { +namespace yoga { + +// Whether moving a node from config "a" to config "b" should dirty previously +// calculated layout results. +bool configUpdateInvalidatesLayout(YGConfigRef a, YGConfigRef b); + +// Internal variants of log functions, currently used only by JNI bindings. +// TODO: Reconcile this with the public API +using LogWithContextFn = int (*)( + YGConfigRef config, + YGNodeRef node, + YGLogLevel level, + void* context, + const char* format, + va_list args); +using CloneWithContextFn = YGNodeRef (*)( + YGNodeRef node, + YGNodeRef owner, + int childIndex, + void* cloneContext); + +using ExperimentalFeatureSet = + facebook::yoga::detail::EnumBitset; + +#pragma pack(push) +#pragma pack(1) +// Packed structure of <32-bit options to miminize size per node. +struct YGConfigFlags { + bool useWebDefaults : 1; + bool printTree : 1; + bool cloneNodeUsesContext : 1; + bool loggerUsesContext : 1; +}; +#pragma pack(pop) + +} // namespace yoga +} // namespace facebook struct YOGA_EXPORT YGConfig { - using LogWithContextFn = int (*)( - YGConfigRef config, - YGNodeRef node, - YGLogLevel level, - void* context, - const char* format, - va_list args); - using CloneWithContextFn = YGNodeRef (*)( + YGConfig(YGLogger logger); + + void setUseWebDefaults(bool useWebDefaults); + bool useWebDefaults() const; + + void setShouldPrintTree(bool printTree); + bool shouldPrintTree() const; + + void setExperimentalFeatureEnabled( + YGExperimentalFeature feature, + bool enabled); + bool isExperimentalFeatureEnabled(YGExperimentalFeature feature) const; + facebook::yoga::ExperimentalFeatureSet getEnabledExperiments() const; + + void setErrata(YGErrata errata); + void addErrata(YGErrata errata); + void removeErrata(YGErrata errata); + YGErrata getErrata() const; + bool hasErrata(YGErrata errata) const; + + void setPointScaleFactor(float pointScaleFactor); + float getPointScaleFactor() const; + + void setContext(void* context); + void* getContext() const; + + void setLogger(YGLogger logger); + void setLogger(facebook::yoga::LogWithContextFn logger); + void setLogger(std::nullptr_t); + void log(YGConfig*, YGNode*, YGLogLevel, void*, const char*, va_list) const; + + void setCloneNodeCallback(YGCloneNodeFunc cloneNode); + void setCloneNodeCallback(facebook::yoga::CloneWithContextFn cloneNode); + void setCloneNodeCallback(std::nullptr_t); + YGNodeRef cloneNode( YGNodeRef node, YGNodeRef owner, int childIndex, - void* cloneContext); + void* cloneContext) const; private: union { - CloneWithContextFn withContext; + facebook::yoga::CloneWithContextFn withContext; YGCloneNodeFunc noContext; } cloneNodeCallback_; union { - LogWithContextFn withContext; + facebook::yoga::LogWithContextFn withContext; YGLogger noContext; } logger_; - bool cloneNodeUsesContext_; - bool loggerUsesContext_; - -public: - bool useWebDefaults = false; - bool useLegacyStretchBehaviour = false; - bool shouldDiffLayoutWithoutLegacyStretchBehaviour = false; - bool printTree = false; - float pointScaleFactor = 1.0f; - std::array()> - experimentalFeatures = {}; - void* context = nullptr; - - YGConfig(YGLogger logger); - void log(YGConfig*, YGNode*, YGLogLevel, void*, const char*, va_list); - void setLogger(YGLogger logger) { - logger_.noContext = logger; - loggerUsesContext_ = false; - } - void setLogger(LogWithContextFn logger) { - logger_.withContext = logger; - loggerUsesContext_ = true; - } - void setLogger(std::nullptr_t) { setLogger(YGLogger{nullptr}); } - YGNodeRef cloneNode( - YGNodeRef node, - YGNodeRef owner, - int childIndex, - void* cloneContext); - void setCloneNodeCallback(YGCloneNodeFunc cloneNode) { - cloneNodeCallback_.noContext = cloneNode; - cloneNodeUsesContext_ = false; - } - void setCloneNodeCallback(CloneWithContextFn cloneNode) { - cloneNodeCallback_.withContext = cloneNode; - cloneNodeUsesContext_ = true; - } - void setCloneNodeCallback(std::nullptr_t) { - setCloneNodeCallback(YGCloneNodeFunc{nullptr}); - } + facebook::yoga::YGConfigFlags flags_{}; + facebook::yoga::ExperimentalFeatureSet experimentalFeatures_{}; + YGErrata errata_ = YGErrataNone; + float pointScaleFactor_ = 1.0f; + void* context_ = nullptr; }; - -#endif diff --git a/packages/react-native/ReactCommon/yoga/yoga/YGEnums.cpp b/packages/react-native/ReactCommon/yoga/yoga/YGEnums.cpp index acb1bd072a8a06..96b424a3bfd6e9 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/YGEnums.cpp +++ b/packages/react-native/ReactCommon/yoga/yoga/YGEnums.cpp @@ -7,7 +7,7 @@ // @generated by enums.py -#include "YGEnums.h" +#include const char* YGAlignToString(const YGAlign value) { switch (value) { @@ -87,6 +87,20 @@ const char* YGEdgeToString(const YGEdge value) { return "unknown"; } +const char* YGErrataToString(const YGErrata value) { + switch (value) { + case YGErrataNone: + return "none"; + case YGErrataStretchFlexBasis: + return "stretch-flex-basis"; + case YGErrataAll: + return "all"; + case YGErrataClassic: + return "classic"; + } + return "unknown"; +} + const char* YGExperimentalFeatureToString(const YGExperimentalFeature value) { switch (value) { case YGExperimentalFeatureWebFlexBasis: diff --git a/packages/react-native/ReactCommon/yoga/yoga/YGEnums.h b/packages/react-native/ReactCommon/yoga/yoga/YGEnums.h index 834e5f669ca6d8..72146fe279867e 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/YGEnums.h +++ b/packages/react-native/ReactCommon/yoga/yoga/YGEnums.h @@ -8,7 +8,7 @@ // @generated by enums.py #pragma once -#include "YGMacros.h" +#include // clang-format off @@ -54,6 +54,14 @@ YG_ENUM_SEQ_DECL( YGEdgeVertical, YGEdgeAll) +YG_ENUM_DECL( + YGErrata, + YGErrataNone = 0, + YGErrataStretchFlexBasis = 1, + YGErrataAll = 2147483647, + YGErrataClassic = 2147483646) +YG_DEFINE_ENUM_FLAG_OPERATORS(YGErrata) + YG_ENUM_SEQ_DECL( YGExperimentalFeature, YGExperimentalFeatureWebFlexBasis, @@ -119,6 +127,7 @@ YG_ENUM_DECL( YGPrintOptionsLayout = 1, YGPrintOptionsStyle = 2, YGPrintOptionsChildren = 4) +YG_DEFINE_ENUM_FLAG_OPERATORS(YGPrintOptions) YG_ENUM_SEQ_DECL( YGUnit, diff --git a/packages/react-native/ReactCommon/yoga/yoga/YGFloatOptional.h b/packages/react-native/ReactCommon/yoga/yoga/YGFloatOptional.h index 6af7bbafbfbdcb..4aa9e76e2993fb 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/YGFloatOptional.h +++ b/packages/react-native/ReactCommon/yoga/yoga/YGFloatOptional.h @@ -7,8 +7,6 @@ #pragma once -#ifdef __cplusplus - #include #include #include "Yoga-internal.h" @@ -70,5 +68,3 @@ inline bool operator>=(YGFloatOptional lhs, YGFloatOptional rhs) { inline bool operator<=(YGFloatOptional lhs, YGFloatOptional rhs) { return lhs < rhs || lhs == rhs; } - -#endif diff --git a/packages/react-native/ReactCommon/yoga/yoga/YGLayout.h b/packages/react-native/ReactCommon/yoga/yoga/YGLayout.h index e95efbcc2446cd..166eabb64d9106 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/YGLayout.h +++ b/packages/react-native/ReactCommon/yoga/yoga/YGLayout.h @@ -7,8 +7,6 @@ #pragma once -#ifdef __cplusplus - #include "BitUtils.h" #include "YGFloatOptional.h" #include "Yoga-internal.h" @@ -63,5 +61,3 @@ struct YGLayout { bool operator==(YGLayout layout) const; bool operator!=(YGLayout layout) const { return !(*this == layout); } }; - -#endif diff --git a/packages/react-native/ReactCommon/yoga/yoga/YGMacros.h b/packages/react-native/ReactCommon/yoga/yoga/YGMacros.h index a73f2e73808841..cd137117d27d52 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/YGMacros.h +++ b/packages/react-native/ReactCommon/yoga/yoga/YGMacros.h @@ -7,6 +7,10 @@ #pragma once +#ifdef __cplusplus +#include +#endif + #ifdef __cplusplus #define YG_EXTERN_C_BEGIN extern "C" { #define YG_EXTERN_C_END } @@ -15,6 +19,14 @@ #define YG_EXTERN_C_END #endif +#if defined(__cplusplus) +#define YG_DEPRECATED(message) [[deprecated(message)]] +#elif defined(_MSC_VER) +#define YG_DEPRECATED(message) __declspec(deprecated(message)) +#else +#define YG_DEPRECATED(message) __attribute__((deprecated(message))) +#endif + #ifdef _WINDLL #define WIN_EXPORT __declspec(dllexport) #else @@ -40,6 +52,48 @@ #define YG_ENUM_END(name) name #endif +#ifdef __cplusplus +#define YG_DEFINE_ENUM_FLAG_OPERATORS(name) \ + extern "C++" { \ + constexpr inline name operator~(name a) { \ + return static_cast( \ + ~static_cast::type>(a)); \ + } \ + constexpr inline name operator|(name a, name b) { \ + return static_cast( \ + static_cast::type>(a) | \ + static_cast::type>(b)); \ + } \ + constexpr inline name operator&(name a, name b) { \ + return static_cast( \ + static_cast::type>(a) & \ + static_cast::type>(b)); \ + } \ + constexpr inline name operator^(name a, name b) { \ + return static_cast( \ + static_cast::type>(a) ^ \ + static_cast::type>(b)); \ + } \ + inline name& operator|=(name& a, name b) { \ + return reinterpret_cast( \ + reinterpret_cast::type&>(a) |= \ + static_cast::type>(b)); \ + } \ + inline name& operator&=(name& a, name b) { \ + return reinterpret_cast( \ + reinterpret_cast::type&>(a) &= \ + static_cast::type>(b)); \ + } \ + inline name& operator^=(name& a, name b) { \ + return reinterpret_cast( \ + reinterpret_cast::type&>(a) ^= \ + static_cast::type>(b)); \ + } \ + } +#else +#define YG_DEFINE_ENUM_FLAG_OPERATORS(name) +#endif + #ifdef __cplusplus namespace facebook { namespace yoga { @@ -82,15 +136,3 @@ constexpr int n() { #else #define YG_ENUM_SEQ_DECL YG_ENUM_DECL #endif - -#ifdef __GNUC__ -#define YG_DEPRECATED __attribute__((deprecated)) -#elif defined(_MSC_VER) -#define YG_DEPRECATED __declspec(deprecated) -#elif __cplusplus >= 201402L -#if defined(__has_cpp_attribute) -#if __has_cpp_attribute(deprecated) -#define YG_DEPRECATED [[deprecated]] -#endif -#endif -#endif diff --git a/packages/react-native/ReactCommon/yoga/yoga/YGNode.cpp b/packages/react-native/ReactCommon/yoga/yoga/YGNode.cpp index b4dbf2ed98d457..4c572e8f33ceeb 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/YGNode.cpp +++ b/packages/react-native/ReactCommon/yoga/yoga/YGNode.cpp @@ -8,15 +8,24 @@ #include "YGNode.h" #include #include -#include "CompactValue.h" #include "Utils.h" using namespace facebook; using facebook::yoga::detail::CompactValue; +YGNode::YGNode(const YGConfigRef config) : config_{config} { + YGAssert( + config != nullptr, "Attempting to construct YGNode with null config"); + + flags_.hasNewLayout = true; + if (config->useWebDefaults()) { + useWebDefaults(); + } +}; + YGNode::YGNode(YGNode&& node) { context_ = node.context_; - flags = node.flags; + flags_ = node.flags_; measure_ = node.measure_; baseline_ = node.baseline_; print_ = node.print_; @@ -33,16 +42,9 @@ YGNode::YGNode(YGNode&& node) { } } -YGNode::YGNode(const YGNode& node, YGConfigRef config) : YGNode{node} { - config_ = config; - if (config->useWebDefaults) { - useWebDefaults(); - } -} - void YGNode::print(void* printContext) { if (print_.noContext != nullptr) { - if (facebook::yoga::detail::getBooleanData(flags, printUsesContext_)) { + if (flags_.printUsesContext) { print_.withContext(this, printContext); } else { print_.noContext(this); @@ -202,14 +204,14 @@ YGSize YGNode::measure( float height, YGMeasureMode heightMode, void* layoutContext) { - return facebook::yoga::detail::getBooleanData(flags, measureUsesContext_) + return flags_.measureUsesContext ? measure_.withContext( this, width, widthMode, height, heightMode, layoutContext) : measure_.noContext(this, width, widthMode, height, heightMode); } float YGNode::baseline(float width, float height, void* layoutContext) { - return facebook::yoga::detail::getBooleanData(flags, baselineUsesContext_) + return flags_.baselineUsesContext ? baseline_.withContext(this, width, height, layoutContext) : baseline_.noContext(this, width, height); } @@ -236,14 +238,14 @@ void YGNode::setMeasureFunc(decltype(YGNode::measure_) measureFunc) { } void YGNode::setMeasureFunc(YGMeasureFunc measureFunc) { - facebook::yoga::detail::setBooleanData(flags, measureUsesContext_, false); + flags_.measureUsesContext = false; decltype(YGNode::measure_) m; m.noContext = measureFunc; setMeasureFunc(m); } YOGA_EXPORT void YGNode::setMeasureFunc(MeasureWithContextFn measureFunc) { - facebook::yoga::detail::setBooleanData(flags, measureUsesContext_, true); + flags_.measureUsesContext = true; decltype(YGNode::measure_) m; m.withContext = measureFunc; setMeasureFunc(m); @@ -261,11 +263,25 @@ void YGNode::insertChild(YGNodeRef child, uint32_t index) { children_.insert(children_.begin() + index, child); } +void YGNode::setConfig(YGConfigRef config) { + YGAssert(config != nullptr, "Attempting to set a null config on a YGNode"); + YGAssertWithConfig( + config, + config->useWebDefaults() == config_->useWebDefaults(), + "UseWebDefaults may not be changed after constructing a YGNode"); + + if (yoga::configUpdateInvalidatesLayout(config_, config)) { + markDirtyAndPropagate(); + } + + config_ = config; +} + void YGNode::setDirty(bool isDirty) { - if (isDirty == facebook::yoga::detail::getBooleanData(flags, isDirty_)) { + if (isDirty == flags_.isDirty) { return; } - facebook::yoga::detail::setBooleanData(flags, isDirty_, isDirty); + flags_.isDirty = isDirty; if (isDirty && dirtied_) { dirtied_(this); } @@ -408,9 +424,7 @@ YGValue YGNode::resolveFlexBasisPtr() const { return flexBasis; } if (!style_.flex().isUndefined() && style_.flex().unwrap() > 0.0f) { - return facebook::yoga::detail::getBooleanData(flags, useWebDefaults_) - ? YGValueAuto - : YGValueZero; + return config_->useWebDefaults() ? YGValueAuto : YGValueZero; } return YGValueAuto; } @@ -449,7 +463,7 @@ void YGNode::cloneChildrenIfNeeded(void* cloneContext) { } void YGNode::markDirtyAndPropagate() { - if (!facebook::yoga::detail::getBooleanData(flags, isDirty_)) { + if (!flags_.isDirty) { setDirty(true); setLayoutComputedFlexBasis(YGFloatOptional()); if (owner_) { @@ -459,7 +473,7 @@ void YGNode::markDirtyAndPropagate() { } void YGNode::markDirtyAndPropagateDownwards() { - facebook::yoga::detail::setBooleanData(flags, isDirty_, true); + flags_.isDirty = true; for_each(children_.begin(), children_.end(), [](YGNodeRef childNode) { childNode->markDirtyAndPropagateDownwards(); }); @@ -486,13 +500,11 @@ float YGNode::resolveFlexShrink() const { if (!style_.flexShrink().isUndefined()) { return style_.flexShrink().unwrap(); } - if (!facebook::yoga::detail::getBooleanData(flags, useWebDefaults_) && - !style_.flex().isUndefined() && style_.flex().unwrap() < 0.0f) { + if (!config_->useWebDefaults() && !style_.flex().isUndefined() && + style_.flex().unwrap() < 0.0f) { return -style_.flex().unwrap(); } - return facebook::yoga::detail::getBooleanData(flags, useWebDefaults_) - ? kWebDefaultFlexShrink - : kDefaultFlexShrink; + return config_->useWebDefaults() ? kWebDefaultFlexShrink : kDefaultFlexShrink; } bool YGNode::isNodeFlexible() { @@ -568,12 +580,5 @@ void YGNode::reset() { YGAssertWithNode( this, owner_ == nullptr, "Cannot reset a node still attached to a owner"); - clearChildren(); - - auto webDefaults = - facebook::yoga::detail::getBooleanData(flags, useWebDefaults_); *this = YGNode{getConfig()}; - if (webDefaults) { - useWebDefaults(); - } } diff --git a/packages/react-native/ReactCommon/yoga/yoga/YGNode.h b/packages/react-native/ReactCommon/yoga/yoga/YGNode.h index 3ed2ecdd20347a..e3c202f2b9f684 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/YGNode.h +++ b/packages/react-native/ReactCommon/yoga/yoga/YGNode.h @@ -7,20 +7,29 @@ #pragma once -#ifdef __cplusplus - #include #include -#include "BitUtils.h" #include "CompactValue.h" #include "YGConfig.h" #include "YGLayout.h" #include "YGStyle.h" -#include "YGMacros.h" #include "Yoga-internal.h" YGConfigRef YGConfigGetDefault(); +#pragma pack(push) +#pragma pack(1) +struct YGNodeFlags { + bool hasNewLayout : 1; + bool isReferenceBaseline : 1; + bool isDirty : 1; + uint8_t nodeType : 1; + bool measureUsesContext : 1; + bool baselineUsesContext : 1; + bool printUsesContext : 1; +}; +#pragma pack(pop) + struct YOGA_EXPORT YGNode { using MeasureWithContextFn = YGSize (*)(YGNode*, float, YGMeasureMode, float, YGMeasureMode, void*); @@ -28,18 +37,8 @@ struct YOGA_EXPORT YGNode { using PrintWithContextFn = void (*)(YGNode*, void*); private: - static constexpr size_t hasNewLayout_ = 0; - static constexpr size_t isReferenceBaseline_ = 1; - static constexpr size_t isDirty_ = 2; - static constexpr size_t nodeType_ = 3; - static constexpr size_t measureUsesContext_ = 4; - static constexpr size_t baselineUsesContext_ = 5; - static constexpr size_t printUsesContext_ = 6; - static constexpr size_t useWebDefaults_ = 7; - void* context_ = nullptr; - uint8_t flags = 1; - uint8_t reserved_ = 0; + YGNodeFlags flags_ = {}; union { YGMeasureFunc noContext; MeasureWithContextFn withContext; @@ -70,7 +69,6 @@ struct YOGA_EXPORT YGNode { void setBaselineFunc(decltype(baseline_)); void useWebDefaults() { - facebook::yoga::detail::setBooleanData(flags, useWebDefaults_, true); style_.flexDirection() = YGFlexDirectionRow; style_.alignContent() = YGAlignStretch; } @@ -85,12 +83,8 @@ struct YOGA_EXPORT YGNode { using CompactValue = facebook::yoga::detail::CompactValue; public: - YGNode() : YGNode{YGConfigGetDefault()} {} - explicit YGNode(const YGConfigRef config) : config_{config} { - if (config->useWebDefaults) { - useWebDefaults(); - } - }; + YGNode() : YGNode{YGConfigGetDefault()} { flags_.hasNewLayout = true; } + explicit YGNode(const YGConfigRef config); ~YGNode() = default; // cleanup of owner/children relationships in YGNodeFree YGNode(YGNode&&); @@ -99,9 +93,6 @@ struct YOGA_EXPORT YGNode { // Should we remove this? YGNode(const YGNode& node) = default; - // for RB fabric - YGNode(const YGNode& node, YGConfigRef config); - // assignment means potential leaks of existing children, or alternatively // freeing unowned memory, double free, or freeing stack memory. YGNode& operator=(const YGNode&) = delete; @@ -109,17 +100,12 @@ struct YOGA_EXPORT YGNode { // Getters void* getContext() const { return context_; } - uint8_t& reserved() { return reserved_; } - uint8_t reserved() const { return reserved_; } - void print(void*); - bool getHasNewLayout() const { - return facebook::yoga::detail::getBooleanData(flags, hasNewLayout_); - } + bool getHasNewLayout() const { return flags_.hasNewLayout; } YGNodeType getNodeType() const { - return facebook::yoga::detail::getEnumData(flags, nodeType_); + return static_cast(flags_.nodeType); } bool hasMeasureFunc() const noexcept { return measure_.noContext != nullptr; } @@ -132,6 +118,8 @@ struct YOGA_EXPORT YGNode { float baseline(float width, float height, void* layoutContext); + bool hasErrata(YGErrata errata) const { return config_->hasErrata(errata); } + YGDirtiedFunc getDirtied() const { return dirtied_; } // For Performance reasons passing as reference. @@ -146,9 +134,7 @@ struct YOGA_EXPORT YGNode { uint32_t getLineIndex() const { return lineIndex_; } - bool isReferenceBaseline() { - return facebook::yoga::detail::getBooleanData(flags, isReferenceBaseline_); - } + bool isReferenceBaseline() { return flags_.isReferenceBaseline; } // returns the YGNodeRef that owns this YGNode. An owner is used to identify // the YogaTree that a YGNode belongs to. This method will return the parent @@ -181,9 +167,7 @@ struct YOGA_EXPORT YGNode { YGConfigRef getConfig() const { return config_; } - bool isDirty() const { - return facebook::yoga::detail::getBooleanData(flags, isDirty_); - } + bool isDirty() const { return flags_.isDirty; } std::array getResolvedDimensions() const { return resolvedDimensions_; @@ -253,21 +237,20 @@ struct YOGA_EXPORT YGNode { void setPrintFunc(YGPrintFunc printFunc) { print_.noContext = printFunc; - facebook::yoga::detail::setBooleanData(flags, printUsesContext_, false); + flags_.printUsesContext = false; } void setPrintFunc(PrintWithContextFn printFunc) { print_.withContext = printFunc; - facebook::yoga::detail::setBooleanData(flags, printUsesContext_, true); + flags_.printUsesContext = true; } void setPrintFunc(std::nullptr_t) { setPrintFunc(YGPrintFunc{nullptr}); } void setHasNewLayout(bool hasNewLayout) { - facebook::yoga::detail::setBooleanData(flags, hasNewLayout_, hasNewLayout); + flags_.hasNewLayout = hasNewLayout; } void setNodeType(YGNodeType nodeType) { - return facebook::yoga::detail::setEnumData( - flags, nodeType_, nodeType); + flags_.nodeType = static_cast(nodeType); } void setMeasureFunc(YGMeasureFunc measureFunc); @@ -277,11 +260,11 @@ struct YOGA_EXPORT YGNode { } void setBaselineFunc(YGBaselineFunc baseLineFunc) { - facebook::yoga::detail::setBooleanData(flags, baselineUsesContext_, false); + flags_.baselineUsesContext = false; baseline_.noContext = baseLineFunc; } void setBaselineFunc(BaselineWithContextFn baseLineFunc) { - facebook::yoga::detail::setBooleanData(flags, baselineUsesContext_, true); + flags_.baselineUsesContext = true; baseline_.withContext = baseLineFunc; } void setBaselineFunc(std::nullptr_t) { @@ -297,8 +280,7 @@ struct YOGA_EXPORT YGNode { void setLineIndex(uint32_t lineIndex) { lineIndex_ = lineIndex; } void setIsReferenceBaseline(bool isReferenceBaseline) { - facebook::yoga::detail::setBooleanData( - flags, isReferenceBaseline_, isReferenceBaseline); + flags_.isReferenceBaseline = isReferenceBaseline; } void setOwner(YGNodeRef owner) { owner_ = owner; } @@ -307,7 +289,7 @@ struct YOGA_EXPORT YGNode { // TODO: rvalue override for setChildren - YG_DEPRECATED void setConfig(YGConfigRef config) { config_ = config; } + void setConfig(YGConfigRef config); void setDirty(bool isDirty); void setLayoutLastOwnerDirection(YGDirection direction); @@ -351,5 +333,3 @@ struct YOGA_EXPORT YGNode { bool isNodeFlexible(); void reset(); }; - -#endif diff --git a/packages/react-native/ReactCommon/yoga/yoga/YGNodePrint.cpp b/packages/react-native/ReactCommon/yoga/yoga/YGNodePrint.cpp index 7e53549c26a83c..d4d3499a3f8ae5 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/YGNodePrint.cpp +++ b/packages/react-native/ReactCommon/yoga/yoga/YGNodePrint.cpp @@ -6,9 +6,12 @@ */ #ifdef DEBUG -#include "YGNodePrint.h" + #include -#include "YGEnums.h" + +#include + +#include "YGNodePrint.h" #include "YGNode.h" #include "Yoga-internal.h" #include "Utils.h" diff --git a/packages/react-native/ReactCommon/yoga/yoga/YGNodePrint.h b/packages/react-native/ReactCommon/yoga/yoga/YGNodePrint.h index 83b3f860e4b5b5..ac550e9611c295 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/YGNodePrint.h +++ b/packages/react-native/ReactCommon/yoga/yoga/YGNodePrint.h @@ -9,11 +9,9 @@ #pragma once -#ifdef __cplusplus - #include -#include "Yoga.h" +#include namespace facebook { namespace yoga { @@ -28,5 +26,3 @@ void YGNodeToString( } // namespace facebook #endif - -#endif diff --git a/packages/react-native/ReactCommon/yoga/yoga/YGStyle.h b/packages/react-native/ReactCommon/yoga/yoga/YGStyle.h index 858b7cd1b4ab63..4f182d0691ec3f 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/YGStyle.h +++ b/packages/react-native/ReactCommon/yoga/yoga/YGStyle.h @@ -7,17 +7,16 @@ #pragma once -#ifdef __cplusplus - #include #include #include #include + +#include + #include "CompactValue.h" -#include "YGEnums.h" #include "YGFloatOptional.h" #include "Yoga-internal.h" -#include "Yoga.h" #include "BitUtils.h" class YOGA_EXPORT YGStyle { @@ -237,5 +236,3 @@ YOGA_EXPORT bool operator==(const YGStyle& lhs, const YGStyle& rhs); YOGA_EXPORT inline bool operator!=(const YGStyle& lhs, const YGStyle& rhs) { return !(lhs == rhs); } - -#endif diff --git a/packages/react-native/ReactCommon/yoga/yoga/YGValue.cpp b/packages/react-native/ReactCommon/yoga/yoga/YGValue.cpp index 89ff41bab117c1..194d22caa87882 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/YGValue.cpp +++ b/packages/react-native/ReactCommon/yoga/yoga/YGValue.cpp @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -#include "YGValue.h" +#include const YGValue YGValueZero = {0, YGUnitPoint}; const YGValue YGValueUndefined = {YGUndefined, YGUnitUndefined}; diff --git a/packages/react-native/ReactCommon/yoga/yoga/YGValue.h b/packages/react-native/ReactCommon/yoga/yoga/YGValue.h index 11beb3ec8b74ac..59f6f5e46196f1 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/YGValue.h +++ b/packages/react-native/ReactCommon/yoga/yoga/YGValue.h @@ -7,28 +7,11 @@ #pragma once -#include -#include "YGEnums.h" -#include "YGMacros.h" +#include +#include -#if defined(_MSC_VER) && defined(__clang__) -#define COMPILING_WITH_CLANG_ON_WINDOWS -#endif -#if defined(COMPILING_WITH_CLANG_ON_WINDOWS) -#include -constexpr float YGUndefined = std::numeric_limits::quiet_NaN(); -#else YG_EXTERN_C_BEGIN -// Not defined in MSVC++ -#ifndef NAN -static const uint32_t __nan = 0x7fc00000; -#define NAN (*(const float*) __nan) -#endif - -#define YGUndefined NAN -#endif - typedef struct YGValue { float value; YGUnit unit; @@ -38,13 +21,17 @@ YOGA_EXPORT extern const YGValue YGValueAuto; YOGA_EXPORT extern const YGValue YGValueUndefined; YOGA_EXPORT extern const YGValue YGValueZero; -#if !defined(COMPILING_WITH_CLANG_ON_WINDOWS) YG_EXTERN_C_END -#endif -#undef COMPILING_WITH_CLANG_ON_WINDOWS #ifdef __cplusplus +#include +constexpr float YGUndefined = std::numeric_limits::quiet_NaN(); +#else +#include +#define YGUndefined NAN +#endif +#ifdef __cplusplus inline bool operator==(const YGValue& lhs, const YGValue& rhs) { if (lhs.unit != rhs.unit) { return false; @@ -69,27 +56,4 @@ inline bool operator!=(const YGValue& lhs, const YGValue& rhs) { inline YGValue operator-(const YGValue& value) { return {-value.value, value.unit}; } - -namespace facebook { -namespace yoga { -namespace literals { - -inline YGValue operator"" _pt(long double value) { - return YGValue{static_cast(value), YGUnitPoint}; -} -inline YGValue operator"" _pt(unsigned long long value) { - return operator"" _pt(static_cast(value)); -} - -inline YGValue operator"" _percent(long double value) { - return YGValue{static_cast(value), YGUnitPercent}; -} -inline YGValue operator"" _percent(unsigned long long value) { - return operator"" _percent(static_cast(value)); -} - -} // namespace literals -} // namespace yoga -} // namespace facebook - #endif diff --git a/packages/react-native/ReactCommon/yoga/yoga/Yoga-internal.h b/packages/react-native/ReactCommon/yoga/yoga/Yoga-internal.h index 9444bb5d1db768..5c5f11c77b0672 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/Yoga-internal.h +++ b/packages/react-native/ReactCommon/yoga/yoga/Yoga-internal.h @@ -7,14 +7,14 @@ #pragma once -#ifdef __cplusplus - #include #include #include #include + +#include + #include "CompactValue.h" -#include "Yoga.h" using YGVector = std::vector; @@ -27,6 +27,10 @@ void YGNodeCalculateLayoutWithContext( YGDirection ownerDirection, void* layoutContext); +// Deallocates a Yoga Node. Unlike YGNodeFree, does not remove the node from +// its parent or children. +void YGNodeDeallocate(YGNodeRef node); + YG_EXTERN_C_END namespace facebook { @@ -154,5 +158,3 @@ static const float kDefaultFlexShrink = 0.0f; static const float kWebDefaultFlexShrink = 1.0f; extern bool YGFloatsEqual(const float a, const float b); - -#endif diff --git a/packages/react-native/ReactCommon/yoga/yoga/Yoga.cpp b/packages/react-native/ReactCommon/yoga/yoga/Yoga.cpp index 9989ade0dbf1cd..98fa7adbf0af31 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/Yoga.cpp +++ b/packages/react-native/ReactCommon/yoga/yoga/Yoga.cpp @@ -5,28 +5,20 @@ * LICENSE file in the root directory of this source tree. */ -#include "Yoga.h" -#include "log.h" #include #include #include #include #include + +#include + +#include "log.h" #include "Utils.h" #include "YGNode.h" #include "YGNodePrint.h" #include "Yoga-internal.h" #include "event/event.h" -#ifdef _MSC_VER -#include - -/* define fmaxf if < VC12 */ -#if _MSC_VER < 1800 -__forceinline const float fmaxf(const float a, const float b) { - return (a > b) ? a : b; -} -#endif -#endif using namespace facebook::yoga; using detail::Log; @@ -50,8 +42,8 @@ static int YGDefaultLog( #ifdef ANDROID #include static int YGAndroidLog( - const YGConfigRef config, - const YGNodeRef node, + const YGConfigRef /*config*/, + const YGNodeRef /*node*/, YGLogLevel level, const char* format, va_list args) { @@ -122,6 +114,14 @@ YOGA_EXPORT void YGNodeSetContext(YGNodeRef node, void* context) { return node->setContext(context); } +YOGA_EXPORT YGConfigRef YGNodeGetConfig(YGNodeRef node) { + return node->getConfig(); +} + +YOGA_EXPORT void YGNodeSetConfig(YGNodeRef node, YGConfigRef config) { + node->setConfig(config); +} + YOGA_EXPORT bool YGNodeHasMeasureFunc(YGNodeRef node) { return node->hasMeasureFunc(); } @@ -161,7 +161,7 @@ YOGA_EXPORT bool YGNodeGetHasNewLayout(YGNodeRef node) { } YOGA_EXPORT void YGConfigSetPrintTreeFlag(YGConfigRef config, bool enabled) { - config->printTree = enabled; + config->setShouldPrintTree(enabled); } YOGA_EXPORT void YGNodeSetHasNewLayout(YGNodeRef node, bool hasNewLayout) { @@ -230,6 +230,10 @@ YOGA_EXPORT void YGNodeFree(const YGNodeRef node) { } node->clearChildren(); + YGNodeDeallocate(node); +} + +YOGA_EXPORT void YGNodeDeallocate(const YGNodeRef node) { Event::publish(node, {node->getConfig()}); delete node; } @@ -371,13 +375,16 @@ YOGA_EXPORT void YGNodeRemoveAllChildren(const YGNodeRef owner) { owner->markDirtyAndPropagate(); } -static void YGNodeSetChildrenInternal( - YGNodeRef const owner, - const std::vector& children) { +YOGA_EXPORT void YGNodeSetChildren( + const YGNodeRef owner, + const YGNodeRef* children, + const uint32_t count) { if (!owner) { return; } - if (children.size() == 0) { + + const YGVector childrenVector = {children, children + count}; + if (childrenVector.size() == 0) { if (YGNodeGetChildCount(owner) > 0) { for (YGNodeRef const child : owner->getChildren()) { child->setLayout(YGLayout()); @@ -391,35 +398,21 @@ static void YGNodeSetChildrenInternal( for (YGNodeRef const oldChild : owner->getChildren()) { // Our new children may have nodes in common with the old children. We // don't reset these common nodes. - if (std::find(children.begin(), children.end(), oldChild) == - children.end()) { + if (std::find(childrenVector.begin(), childrenVector.end(), oldChild) == + childrenVector.end()) { oldChild->setLayout(YGLayout()); oldChild->setOwner(nullptr); } } } - owner->setChildren(children); - for (YGNodeRef child : children) { + owner->setChildren(childrenVector); + for (YGNodeRef child : childrenVector) { child->setOwner(owner); } owner->markDirtyAndPropagate(); } } -YOGA_EXPORT void YGNodeSetChildren( - const YGNodeRef owner, - const YGNodeRef c[], - const uint32_t count) { - const YGVector children = {c, c + count}; - YGNodeSetChildrenInternal(owner, children); -} - -YOGA_EXPORT void YGNodeSetChildren( - YGNodeRef const owner, - const std::vector& children) { - YGNodeSetChildrenInternal(owner, children); -} - YOGA_EXPORT YGNodeRef YGNodeGetChild(const YGNodeRef node, const uint32_t index) { if (index < node->getChildren().size()) { @@ -467,8 +460,8 @@ YOGA_EXPORT float YGNodeStyleGetFlexGrow(const YGNodeConstRef node) { YOGA_EXPORT float YGNodeStyleGetFlexShrink(const YGNodeConstRef node) { return node->getStyle().flexShrink().isUndefined() - ? (node->getConfig()->useWebDefaults ? kWebDefaultFlexShrink - : kDefaultFlexShrink) + ? (node->getConfig()->useWebDefaults() ? kWebDefaultFlexShrink + : kDefaultFlexShrink) : node->getStyle().flexShrink().unwrap(); } @@ -1243,8 +1236,8 @@ static void YGNodeComputeFlexBasisForChild( if (!resolvedFlexBasis.isUndefined() && !YGFloatIsUndefined(mainAxisSize)) { if (child->getLayout().computedFlexBasis.isUndefined() || - (YGConfigIsExperimentalFeatureEnabled( - child->getConfig(), YGExperimentalFeatureWebFlexBasis) && + (child->getConfig()->isExperimentalFeatureEnabled( + YGExperimentalFeatureWebFlexBasis) && child->getLayout().computedFlexBasisGeneration != generationCount)) { const YGFloatOptional paddingAndBorder = YGFloatOptional( YGNodePaddingAndBorderForAxis(child, mainAxis, ownerWidth)); @@ -1551,8 +1544,7 @@ static void YGNodeAbsoluteLayoutChild( generationCount); auto trailingMarginOuterSize = - YGConfigIsExperimentalFeatureEnabled( - node->getConfig(), + node->getConfig()->isExperimentalFeatureEnabled( YGExperimentalFeatureFixAbsoluteTrailingColumnMargin) ? isMainAxisRow ? height : width : width; @@ -1584,8 +1576,7 @@ static void YGNodeAbsoluteLayoutChild( child->getLayout().measuredDimensions[dim[mainAxis]]), leading[mainAxis]); } else if ( - YGConfigIsExperimentalFeatureEnabled( - node->getConfig(), + node->getConfig()->isExperimentalFeatureEnabled( YGExperimentalFeatureAbsolutePercentageAgainstPaddingEdge) && child->isLeadingPositionDefined(mainAxis)) { child->setLayoutPosition( @@ -1631,8 +1622,7 @@ static void YGNodeAbsoluteLayoutChild( child->getLayout().measuredDimensions[dim[crossAxis]]), leading[crossAxis]); } else if ( - YGConfigIsExperimentalFeatureEnabled( - node->getConfig(), + node->getConfig()->isExperimentalFeatureEnabled( YGExperimentalFeatureAbsolutePercentageAgainstPaddingEdge) && child->isLeadingPositionDefined(crossAxis)) { child->setLayoutPosition( @@ -2993,7 +2983,10 @@ static void YGNodelayoutImpl( maxInnerMainDim) { availableInnerMainDim = maxInnerMainDim; } else { - if (!node->getConfig()->useLegacyStretchBehaviour && + bool useLegacyStretchBehaviour = + node->hasErrata(YGErrataStretchFlexBasis); + + if (!useLegacyStretchBehaviour && ((!YGFloatIsUndefined( collectedFlexItemsValues.totalFlexGrowFactors) && collectedFlexItemsValues.totalFlexGrowFactors == 0) || @@ -3006,7 +2999,7 @@ static void YGNodelayoutImpl( collectedFlexItemsValues.sizeConsumedOnCurrentLine; } - sizeBasedOnContent = !node->getConfig()->useLegacyStretchBehaviour; + sizeBasedOnContent = !useLegacyStretchBehaviour; } } @@ -3560,18 +3553,18 @@ static void YGNodelayoutImpl( child->getStyle().positionType() != YGPositionTypeAbsolute) { continue; } + const bool absolutePercentageAgainstPaddingEdge = + node->getConfig()->isExperimentalFeatureEnabled( + YGExperimentalFeatureAbsolutePercentageAgainstPaddingEdge); + YGNodeAbsoluteLayoutChild( node, child, - YGConfigIsExperimentalFeatureEnabled( - node->getConfig(), - YGExperimentalFeatureAbsolutePercentageAgainstPaddingEdge) + absolutePercentageAgainstPaddingEdge ? node->getLayout().measuredDimensions[YGDimensionWidth] : availableInnerWidth, isMainAxisRow ? measureModeMainDim : measureModeCrossDim, - YGConfigIsExperimentalFeatureEnabled( - node->getConfig(), - YGExperimentalFeatureAbsolutePercentageAgainstPaddingEdge) + absolutePercentageAgainstPaddingEdge ? node->getLayout().measuredDimensions[YGDimensionHeight] : availableInnerHeight, direction, @@ -3738,20 +3731,22 @@ YOGA_EXPORT bool YGNodeCanUseCachedMeasurement( return false; } bool useRoundedComparison = - config != nullptr && config->pointScaleFactor != 0; + config != nullptr && config->getPointScaleFactor() != 0; const float effectiveWidth = useRoundedComparison - ? YGRoundValueToPixelGrid(width, config->pointScaleFactor, false, false) + ? YGRoundValueToPixelGrid( + width, config->getPointScaleFactor(), false, false) : width; const float effectiveHeight = useRoundedComparison - ? YGRoundValueToPixelGrid(height, config->pointScaleFactor, false, false) + ? YGRoundValueToPixelGrid( + height, config->getPointScaleFactor(), false, false) : height; const float effectiveLastWidth = useRoundedComparison ? YGRoundValueToPixelGrid( - lastWidth, config->pointScaleFactor, false, false) + lastWidth, config->getPointScaleFactor(), false, false) : lastWidth; const float effectiveLastHeight = useRoundedComparison ? YGRoundValueToPixelGrid( - lastHeight, config->pointScaleFactor, false, false) + lastHeight, config->getPointScaleFactor(), false, false) : lastHeight; const bool hasSameWidthSpec = lastWidthMode == widthMode && @@ -4078,12 +4073,16 @@ YOGA_EXPORT void YGConfigSetPointScaleFactor( // We store points for Pixel as we will use it for rounding if (pixelsInPoint == 0.0f) { // Zero is used to skip rounding - config->pointScaleFactor = 0.0f; + config->setPointScaleFactor(0.0f); } else { - config->pointScaleFactor = pixelsInPoint; + config->setPointScaleFactor(pixelsInPoint); } } +YOGA_EXPORT float YGConfigGetPointScaleFactor(const YGConfigRef config) { + return config->getPointScaleFactor(); +} + static void YGRoundToPixelGrid( const YGNodeRef node, const double pointScaleFactor, @@ -4230,10 +4229,11 @@ YOGA_EXPORT void YGNodeCalculateLayoutWithContext( gCurrentGenerationCount.load(std::memory_order_relaxed))) { node->setPosition( node->getLayout().direction(), ownerWidth, ownerHeight, ownerWidth); - YGRoundToPixelGrid(node, node->getConfig()->pointScaleFactor, 0.0f, 0.0f); + YGRoundToPixelGrid( + node, node->getConfig()->getPointScaleFactor(), 0.0f, 0.0f); #ifdef DEBUG - if (node->getConfig()->printTree) { + if (node->getConfig()->shouldPrintTree()) { YGNodePrint( node, (YGPrintOptions) (YGPrintOptionsLayout | YGPrintOptionsChildren | YGPrintOptionsStyle)); @@ -4296,65 +4296,58 @@ YOGA_EXPORT void YGConfigSetExperimentalFeatureEnabled( const YGConfigRef config, const YGExperimentalFeature feature, const bool enabled) { - config->experimentalFeatures[feature] = enabled; + config->setExperimentalFeatureEnabled(feature, enabled); } YOGA_EXPORT bool YGConfigIsExperimentalFeatureEnabled( const YGConfigRef config, const YGExperimentalFeature feature) { - return config->experimentalFeatures[feature]; + return config->isExperimentalFeatureEnabled(feature); } YOGA_EXPORT void YGConfigSetUseWebDefaults( const YGConfigRef config, const bool enabled) { - config->useWebDefaults = enabled; + config->setUseWebDefaults(enabled); } YOGA_EXPORT bool YGConfigGetUseLegacyStretchBehaviour( const YGConfigRef config) { - return config->useLegacyStretchBehaviour; + return config->hasErrata(YGErrataStretchFlexBasis); } YOGA_EXPORT void YGConfigSetUseLegacyStretchBehaviour( const YGConfigRef config, const bool useLegacyStretchBehaviour) { - config->useLegacyStretchBehaviour = useLegacyStretchBehaviour; + if (useLegacyStretchBehaviour) { + config->addErrata(YGErrataStretchFlexBasis); + } else { + config->removeErrata(YGErrataStretchFlexBasis); + } } bool YGConfigGetUseWebDefaults(const YGConfigRef config) { - return config->useWebDefaults; + return config->useWebDefaults(); } YOGA_EXPORT void YGConfigSetContext(const YGConfigRef config, void* context) { - config->context = context; + config->setContext(context); } YOGA_EXPORT void* YGConfigGetContext(const YGConfigRef config) { - return config->context; + return config->getContext(); } -YOGA_EXPORT void YGConfigSetCloneNodeFunc( - const YGConfigRef config, - const YGCloneNodeFunc callback) { - config->setCloneNodeCallback(callback); +YOGA_EXPORT void YGConfigSetErrata(YGConfigRef config, YGErrata errata) { + config->setErrata(errata); } -static void YGTraverseChildrenPreOrder( - const YGVector& children, - const std::function& f) { - for (YGNodeRef node : children) { - f(node); - YGTraverseChildrenPreOrder(node->getChildren(), f); - } +YOGA_EXPORT YGErrata YGConfigGetErrata(YGConfigRef config) { + return config->getErrata(); } -void YGTraversePreOrder( - YGNodeRef const node, - std::function&& f) { - if (!node) { - return; - } - f(node); - YGTraverseChildrenPreOrder(node->getChildren(), f); +YOGA_EXPORT void YGConfigSetCloneNodeFunc( + const YGConfigRef config, + const YGCloneNodeFunc callback) { + config->setCloneNodeCallback(callback); } diff --git a/packages/react-native/ReactCommon/yoga/yoga/Yoga.h b/packages/react-native/ReactCommon/yoga/yoga/Yoga.h index d52ea3386b72d0..de07aeac8b712a 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/Yoga.h +++ b/packages/react-native/ReactCommon/yoga/yoga/Yoga.h @@ -18,9 +18,9 @@ #include #endif -#include "YGEnums.h" -#include "YGMacros.h" -#include "YGValue.h" +#include +#include +#include YG_EXTERN_C_BEGIN @@ -82,7 +82,7 @@ WIN_EXPORT YGNodeRef YGNodeGetParent(YGNodeRef node); WIN_EXPORT uint32_t YGNodeGetChildCount(YGNodeRef node); WIN_EXPORT void YGNodeSetChildren( YGNodeRef owner, - const YGNodeRef children[], + const YGNodeRef* children, uint32_t count); WIN_EXPORT void YGNodeSetIsReferenceBaseline( @@ -134,6 +134,10 @@ WIN_EXPORT void YGNodeCopyStyle(YGNodeRef dstNode, YGNodeRef srcNode); WIN_EXPORT void* YGNodeGetContext(YGNodeRef node); WIN_EXPORT void YGNodeSetContext(YGNodeRef node, void* context); + +WIN_EXPORT YGConfigRef YGNodeGetConfig(YGNodeRef node); +WIN_EXPORT void YGNodeSetConfig(YGNodeRef node, YGConfigRef config); + void YGConfigSetPrintTreeFlag(YGConfigRef config, bool enabled); bool YGNodeHasMeasureFunc(YGNodeRef node); WIN_EXPORT void YGNodeSetMeasureFunc(YGNodeRef node, YGMeasureFunc measureFunc); @@ -313,14 +317,26 @@ WIN_EXPORT void YGAssertWithConfig( WIN_EXPORT void YGConfigSetPointScaleFactor( YGConfigRef config, float pixelsInPoint); +WIN_EXPORT float YGConfigGetPointScaleFactor(YGConfigRef config); // Yoga previously had an error where containers would take the maximum space // possible instead of the minimum like they are supposed to. In practice this // resulted in implicit behaviour similar to align-self: stretch; Because this // was such a long-standing bug we must allow legacy users to switch back to // this behaviour. -WIN_EXPORT bool YGConfigGetUseLegacyStretchBehaviour(YGConfigRef config); -WIN_EXPORT void YGConfigSetUseLegacyStretchBehaviour( +WIN_EXPORT YG_DEPRECATED( + "Please use " + "\"YGConfigGetErrata()\"") bool YGConfigGetUseLegacyStretchBehaviour(YGConfigRef + config); +WIN_EXPORT +YG_DEPRECATED( + "\"YGConfigSetUseLegacyStretchBehaviour\" will be removed in the next " + "release. Usage should be replaced with \"YGConfigSetErrata(YGErrataAll)\" " + "to opt out of all future breaking conformance fixes, or " + "\"YGConfigSetErrata(YGErrataStretchFlexBasis)\" to opt out of the " + "specific conformance fix previously disabled by " + "\"UseLegacyStretchBehaviour\".") +void YGConfigSetUseLegacyStretchBehaviour( YGConfigRef config, bool useLegacyStretchBehaviour); @@ -353,6 +369,9 @@ WIN_EXPORT YGConfigRef YGConfigGetDefault(void); WIN_EXPORT void YGConfigSetContext(YGConfigRef config, void* context); WIN_EXPORT void* YGConfigGetContext(YGConfigRef config); +WIN_EXPORT void YGConfigSetErrata(YGConfigRef config, YGErrata errata); +WIN_EXPORT YGErrata YGConfigGetErrata(YGConfigRef config); + WIN_EXPORT float YGRoundValueToPixelGrid( double value, double pointScaleFactor, @@ -360,17 +379,3 @@ WIN_EXPORT float YGRoundValueToPixelGrid( bool forceFloor); YG_EXTERN_C_END - -#ifdef __cplusplus - -#include -#include - -// Calls f on each node in the tree including the given node argument. -void YGTraversePreOrder( - YGNodeRef node, - std::function&& f); - -void YGNodeSetChildren(YGNodeRef owner, const std::vector& children); - -#endif diff --git a/packages/react-native/ReactCommon/yoga/yoga/log.cpp b/packages/react-native/ReactCommon/yoga/yoga/log.cpp index dbf7b4376e669c..6cdd3f69f478b3 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/log.cpp +++ b/packages/react-native/ReactCommon/yoga/yoga/log.cpp @@ -5,9 +5,9 @@ * LICENSE file in the root directory of this source tree. */ -#include "log.h" +#include -#include "Yoga.h" +#include "log.h" #include "YGConfig.h" #include "YGNode.h" diff --git a/packages/react-native/ReactCommon/yoga/yoga/log.h b/packages/react-native/ReactCommon/yoga/yoga/log.h index b9bfea4f390f7e..419724e22338e3 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/log.h +++ b/packages/react-native/ReactCommon/yoga/yoga/log.h @@ -7,9 +7,7 @@ #pragma once -#ifdef __cplusplus - -#include "YGEnums.h" +#include struct YGNode; struct YGConfig; @@ -38,5 +36,3 @@ struct Log { } // namespace detail } // namespace yoga } // namespace facebook - -#endif diff --git a/packages/react-native/build.gradle.kts b/packages/react-native/build.gradle.kts index 217bf9379b9543..6ac661e1d42c6f 100644 --- a/packages/react-native/build.gradle.kts +++ b/packages/react-native/build.gradle.kts @@ -14,5 +14,5 @@ plugins { id("com.android.library") version "7.4.2" apply false id("com.android.application") version "7.4.2" apply false id("de.undercouch.download") version "5.0.1" apply false - kotlin("android") version "1.7.22" apply false + kotlin("android") version "1.8.0" apply false } diff --git a/packages/react-native/jest/__tests__/setup-test.js b/packages/react-native/jest/__tests__/setup-test.js new file mode 100644 index 00000000000000..cc06b3dcf6d33f --- /dev/null +++ b/packages/react-native/jest/__tests__/setup-test.js @@ -0,0 +1,18 @@ +/** + * 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 + * @format + * @oncall react_native + */ + +import NativeExceptionsManager from '../../Libraries/Core/NativeExceptionsManager'; + +test('NativeExceptionsManager is a mock', () => { + expect(jest.isMockFunction(NativeExceptionsManager.reportException)).toBe( + true, + ); +}); diff --git a/packages/react-native/jest/setup.js b/packages/react-native/jest/setup.js index a1984cde517cd9..c542ef38f8bee8 100644 --- a/packages/react-native/jest/setup.js +++ b/packages/react-native/jest/setup.js @@ -15,36 +15,50 @@ const mockComponent = jest.requireActual('./mockComponent'); jest.requireActual('@react-native/js-polyfills/Object.es8'); jest.requireActual('@react-native/js-polyfills/error-guard'); -global.__DEV__ = true; - -global.performance = { - now: jest.fn(Date.now), -}; - -global.regeneratorRuntime = jest.requireActual('regenerator-runtime/runtime'); -global.window = global; - -global.requestAnimationFrame = function (callback) { - return setTimeout(() => callback(jest.now()), 0); -}; -global.cancelAnimationFrame = function (id) { - clearTimeout(id); -}; - -// there's a __mock__ for it. -jest.setMock( - '../Libraries/vendor/core/ErrorUtils', - require('../Libraries/vendor/core/ErrorUtils'), -); +Object.defineProperties(global, { + __DEV__: { + configurable: true, + enumerable: true, + value: true, + writable: true, + }, + cancelAnimationFrame: { + configurable: true, + enumerable: true, + value: id => clearTimeout(id), + writable: true, + }, + performance: { + configurable: true, + enumerable: true, + value: { + now: jest.fn(Date.now), + }, + writable: true, + }, + regeneratorRuntime: { + configurable: true, + enumerable: true, + value: jest.requireActual('regenerator-runtime/runtime'), + writable: true, + }, + requestAnimationFrame: { + configurable: true, + enumerable: true, + value: callback => setTimeout(() => callback(jest.now()), 0), + writable: true, + }, + window: { + configurable: true, + enumerable: true, + value: global, + writable: true, + }, +}); jest .mock('../Libraries/Core/InitializeCore', () => {}) - .mock('../Libraries/Core/NativeExceptionsManager', () => ({ - __esModule: true, - default: { - reportException: jest.fn(), - }, - })) + .mock('../Libraries/Core/NativeExceptionsManager') .mock('../Libraries/ReactNative/UIManager', () => ({ AndroidViewPager: { Commands: { @@ -95,9 +109,17 @@ jest Constants: {}, }, })) - .mock('../Libraries/Image/Image', () => - mockComponent('../Libraries/Image/Image'), - ) + .mock('../Libraries/Image/Image', () => { + const Image = mockComponent('../Libraries/Image/Image'); + Image.getSize = jest.fn(); + Image.getSizeWithHeaders = jest.fn(); + Image.prefetch = jest.fn(); + Image.prefetchWithMetadata = jest.fn(); + Image.queryCache = jest.fn(); + Image.resolveAssetSource = jest.fn(); + + return Image; + }) .mock('../Libraries/Text/Text', () => mockComponent('../Libraries/Text/Text', MockNativeMethods), ) diff --git a/packages/react-native/package.json b/packages/react-native/package.json index 7f6be6a35c2102..31ff4085f1175b 100644 --- a/packages/react-native/package.json +++ b/packages/react-native/package.json @@ -1,13 +1,29 @@ { "name": "react-native", "version": "1000.0.0", - "bin": "./cli.js", "description": "A framework for building native apps using React", "license": "MIT", - "repository": "github:facebook/react-native", + "repository": { + "type": "git", + "url": "https://github.com/facebook/react-native.git", + "directory": "packages/react-native" + }, + "homepage": "https://reactnative.dev/", + "keywords": [ + "react", + "react-native", + "android", + "ios", + "mobile", + "cross-platform", + "app-framework", + "mobile-development" + ], + "bugs": "https://github.com/facebook/react-native/issues", "engines": { "node": ">=16" }, + "bin": "./cli.js", "types": "types", "jest-junit": { "outputDirectory": "reports/junit", @@ -90,10 +106,10 @@ "@react-native/virtualized-lists": "^0.73.0", "abort-controller": "^3.0.0", "anser": "^1.4.9", - "base64-js": "^1.1.2", - "deprecated-react-native-prop-types": "^4.0.0", + "base64-js": "^1.5.1", + "deprecated-react-native-prop-types": "4.1.0", "event-target-shim": "^5.0.1", - "flow-enums-runtime": "^0.0.5", + "flow-enums-runtime": "^0.0.6", "invariant": "^2.2.4", "jest-environment-node": "^29.2.1", "jsc-android": "^250231.0.0", @@ -104,11 +120,11 @@ "nullthrows": "^1.1.1", "pretty-format": "^26.5.2", "promise": "^8.3.0", - "react-devtools-core": "^4.27.2", + "react-devtools-core": "^4.27.7", "react-refresh": "^0.4.0", "react-shallow-renderer": "^16.15.0", "regenerator-runtime": "^0.13.2", - "scheduler": "^0.23.0", + "scheduler": "0.24.0-canary-efb381bbf-20230505", "stacktrace-parser": "^0.1.10", "whatwg-fetch": "^3.0.0", "ws": "^6.2.2", diff --git a/packages/react-native/scripts/cocoapods/__tests__/codegen_utils-test.rb b/packages/react-native/scripts/cocoapods/__tests__/codegen_utils-test.rb index c4e08a399a9357..da138e23b86950 100644 --- a/packages/react-native/scripts/cocoapods/__tests__/codegen_utils-test.rb +++ b/packages/react-native/scripts/cocoapods/__tests__/codegen_utils-test.rb @@ -544,12 +544,15 @@ def get_podspec_no_fabric_no_script [ "\"$(PODS_ROOT)/boost\"", "\"$(PODS_ROOT)/RCT-Folly\"", + "\"$(PODS_ROOT)/DoubleConversion\"", "\"${PODS_ROOT}/Headers/Public/React-Codegen/react/renderer/components\"", "\"$(PODS_ROOT)/Headers/Private/React-Fabric\"", "\"$(PODS_ROOT)/Headers/Private/React-RCTFabric\"", + "\"$(PODS_ROOT)/Headers/Private/Yoga\"", ].join(' ') }, 'dependencies': { + "DoubleConversion": [], "FBReactNativeSpec": [], "RCT-Folly": [], "RCTRequired": [], @@ -561,7 +564,8 @@ def get_podspec_no_fabric_no_script "ReactCommon/turbomodule/bridging": [], "ReactCommon/turbomodule/core": [], "hermes-engine": [], - 'React-NativeModulesApple': [], + "React-NativeModulesApple": [], + "glog": [], } } end @@ -585,7 +589,7 @@ def get_podspec_when_use_frameworks specs = get_podspec_no_fabric_no_script() specs["pod_target_xcconfig"]["FRAMEWORK_SEARCH_PATHS"].concat([]) - specs["pod_target_xcconfig"]["HEADER_SEARCH_PATHS"].concat(" \"$(PODS_ROOT)/DoubleConversion\" \"$(PODS_TARGET_SRCROOT)\" \"$(PODS_CONFIGURATION_BUILD_DIR)/React-Fabric/React_Fabric.framework/Headers\" \"$(PODS_CONFIGURATION_BUILD_DIR)/React-graphics/React_graphics.framework/Headers\" \"$(PODS_CONFIGURATION_BUILD_DIR)/React-graphics/React_graphics.framework/Headers/react/renderer/graphics/platform/ios\" \"$(PODS_CONFIGURATION_BUILD_DIR)/ReactCommon/ReactCommon.framework/Headers\" \"$(PODS_CONFIGURATION_BUILD_DIR)/ReactCommon/ReactCommon.framework/Headers/react/nativemodule/core\" \"$(PODS_CONFIGURATION_BUILD_DIR)/React-NativeModulesApple/React_NativeModulesApple.framework/Headers\" \"$(PODS_CONFIGURATION_BUILD_DIR)/React-RCTFabric/RCTFabric.framework/Headers\"") + specs["pod_target_xcconfig"]["HEADER_SEARCH_PATHS"].concat(" \"$(PODS_ROOT)/DoubleConversion\" \"$(PODS_TARGET_SRCROOT)\" \"$(PODS_CONFIGURATION_BUILD_DIR)/React-Fabric/React_Fabric.framework/Headers\" \"$(PODS_CONFIGURATION_BUILD_DIR)/React-FabricImage/React_FabricImage.framework/Headers\" \"$(PODS_CONFIGURATION_BUILD_DIR)/React-graphics/React_graphics.framework/Headers\" \"$(PODS_CONFIGURATION_BUILD_DIR)/React-graphics/React_graphics.framework/Headers/react/renderer/graphics/platform/ios\" \"$(PODS_CONFIGURATION_BUILD_DIR)/ReactCommon/ReactCommon.framework/Headers\" \"$(PODS_CONFIGURATION_BUILD_DIR)/ReactCommon/ReactCommon.framework/Headers/react/nativemodule/core\" \"$(PODS_CONFIGURATION_BUILD_DIR)/React-NativeModulesApple/React_NativeModulesApple.framework/Headers\" \"$(PODS_CONFIGURATION_BUILD_DIR)/React-RCTFabric/RCTFabric.framework/Headers\"") specs[:dependencies].merge!({ 'React-graphics': [], diff --git a/packages/react-native/scripts/cocoapods/__tests__/fabric-test.rb b/packages/react-native/scripts/cocoapods/__tests__/fabric-test.rb index 0b47cd891d0b4c..6e91c455f3f379 100644 --- a/packages/react-native/scripts/cocoapods/__tests__/fabric-test.rb +++ b/packages/react-native/scripts/cocoapods/__tests__/fabric-test.rb @@ -46,9 +46,10 @@ def test_setupFabric_whenNewArchEnabled_installPods end def check_installed_pods(prefix) - assert_equal($podInvocationCount, 5) + assert_equal(6, $podInvocationCount) check_pod("React-Fabric", :path => "#{prefix}/ReactCommon") + check_pod("React-FabricImage", :path => "#{prefix}/ReactCommon") check_pod("React-graphics", :path => "#{prefix}/ReactCommon/react/renderer/graphics") check_pod("React-RCTFabric", :path => "#{prefix}/React", :modular_headers => true) check_pod("RCT-Folly/Fabric", :podspec => "#{prefix}/third-party-podspecs/RCT-Folly.podspec") diff --git a/packages/react-native/scripts/cocoapods/__tests__/flipper-test.rb b/packages/react-native/scripts/cocoapods/__tests__/flipper-test.rb index d30b5bc7d98771..2c0659ecc4cd13 100644 --- a/packages/react-native/scripts/cocoapods/__tests__/flipper-test.rb +++ b/packages/react-native/scripts/cocoapods/__tests__/flipper-test.rb @@ -82,7 +82,7 @@ def test_postInstall_updatesThePodCorrectly assert_equal(config.build_settings['SWIFT_VERSION'], '4.1') end - reactCore_target = installer.target_with_name("React-Core") + reactCore_target = installer.target_with_name("React-RCTAppDelegate") reactCore_target.build_configurations.each do |config| if config.name == 'Debug' || config.name == 'CustomConfig' then assert_equal(config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'], ['$(inherited)', 'FB_SONARKIT_ENABLED=1']) @@ -144,6 +144,14 @@ def prepare_mocked_installer BuildConfigurationMock.new("Release", is_debug: false), BuildConfigurationMock.new("CustomConfig", is_debug: true), ] + ), + TargetMock.new( + "React-RCTAppDelegate", + [ + BuildConfigurationMock.new("Debug", is_debug: true), + BuildConfigurationMock.new("Release", is_debug: false), + BuildConfigurationMock.new("CustomConfig", is_debug: true), + ] ) ] ) diff --git a/packages/react-native/scripts/cocoapods/__tests__/jsengine-test.rb b/packages/react-native/scripts/cocoapods/__tests__/jsengine-test.rb index d604176dfe26b0..84ef4a6c346279 100644 --- a/packages/react-native/scripts/cocoapods/__tests__/jsengine-test.rb +++ b/packages/react-native/scripts/cocoapods/__tests__/jsengine-test.rb @@ -105,7 +105,9 @@ def test_setupHermes_whenHermesScriptSucceeds_installsPods assert_equal($podInvocation["React-jsi"][:path], "../../ReactCommon/jsi") assert_equal($podInvocation["React-hermes"][:path], "../../ReactCommon/hermes") assert_equal($podInvocation["libevent"][:version], "~> 2.1.12") - assert_equal($podInvocation["hermes-engine"][:podspec], "../../sdks/hermes/hermes-engine.podspec") + hermes_engine_pod_invocation = $podInvocation["hermes-engine"] + assert_equal(hermes_engine_pod_invocation[:podspec], "../../sdks/hermes-engine/hermes-engine.podspec") + assert_equal(hermes_engine_pod_invocation[:tag], "") end def test_setupHermes_installsPods_installsFabricSubspecWhenFabricEnabled @@ -118,7 +120,9 @@ def test_setupHermes_installsPods_installsFabricSubspecWhenFabricEnabled # Assert assert_equal($podInvocationCount, 4) assert_equal($podInvocation["React-jsi"][:path], "../../ReactCommon/jsi") - assert_equal($podInvocation["hermes-engine"][:podspec], "../../sdks/hermes/hermes-engine.podspec") + hermes_engine_pod_invocation = $podInvocation["hermes-engine"] + assert_equal(hermes_engine_pod_invocation[:podspec], "../../sdks/hermes-engine/hermes-engine.podspec") + assert_equal(hermes_engine_pod_invocation[:tag], "") assert_equal($podInvocation["React-hermes"][:path], "../../ReactCommon/hermes") assert_equal($podInvocation["libevent"][:version], "~> 2.1.12") end diff --git a/packages/react-native/scripts/cocoapods/__tests__/new_architecture-test.rb b/packages/react-native/scripts/cocoapods/__tests__/new_architecture-test.rb index e007e440b071c3..c97349ed15df31 100644 --- a/packages/react-native/scripts/cocoapods/__tests__/new_architecture-test.rb +++ b/packages/react-native/scripts/cocoapods/__tests__/new_architecture-test.rb @@ -129,7 +129,7 @@ def test_installModulesDependencies_whenNewArchEnabledAndNewArchAndNoSearchPaths # Assert assert_equal(spec.compiler_flags, NewArchitectureHelper.folly_compiler_flags) - assert_equal(spec.pod_target_xcconfig["HEADER_SEARCH_PATHS"], "\"$(PODS_ROOT)/boost\" \"$(PODS_ROOT)/DoubleConversion\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-graphics/React_graphics.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-graphics/React_graphics.framework/Headers/react/renderer/graphics/platform/ios\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-Fabric/React_Fabric.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon/ReactCommon.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon/ReactCommon.framework/Headers/react/nativemodule/core\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-RCTFabric/RCTFabric.framework/Headers\"") + assert_equal(spec.pod_target_xcconfig["HEADER_SEARCH_PATHS"], "\"$(PODS_ROOT)/boost\" \"$(PODS_ROOT)/Headers/Private/Yoga\" \"$(PODS_ROOT)/DoubleConversion\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-graphics/React_graphics.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-graphics/React_graphics.framework/Headers/react/renderer/graphics/platform/ios\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-Fabric/React_Fabric.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-FabricImage/React_FabricImage.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon/ReactCommon.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon/ReactCommon.framework/Headers/react/nativemodule/core\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-RCTFabric/RCTFabric.framework/Headers\"") assert_equal(spec.pod_target_xcconfig["CLANG_CXX_LANGUAGE_STANDARD"], "c++17") assert_equal(spec.pod_target_xcconfig["OTHER_CPLUSPLUSFLAGS"], "$(inherited) -DRCT_NEW_ARCH_ENABLED=1 -DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1") assert_equal( @@ -137,13 +137,18 @@ def test_installModulesDependencies_whenNewArchEnabledAndNewArchAndNoSearchPaths [ { :dependency_name => "React-Core" }, { :dependency_name => "RCT-Folly", "version"=>"2021.07.22.00" }, + { :dependency_name => "glog" }, { :dependency_name => "React-RCTFabric" }, { :dependency_name => "React-Codegen" }, { :dependency_name => "RCTRequired" }, { :dependency_name => "RCTTypeSafety" }, { :dependency_name => "ReactCommon/turbomodule/bridging" }, { :dependency_name => "ReactCommon/turbomodule/core" }, - { :dependency_name => "React-NativeModulesApple" } + { :dependency_name => "React-NativeModulesApple" }, + { :dependency_name => "Yoga" }, + { :dependency_name => "React-Fabric" }, + { :dependency_name => "React-graphics" }, + { :dependency_name => "hermes-engine" } ]) end @@ -161,13 +166,14 @@ def test_installModulesDependencies_whenNewArchDisabledAndSearchPathsAndCompiler # Assert assert_equal(spec.compiler_flags, "-Wno-nullability-completeness #{NewArchitectureHelper.folly_compiler_flags}") - assert_equal(spec.pod_target_xcconfig["HEADER_SEARCH_PATHS"], "#{other_flags} \"$(PODS_ROOT)/boost\" \"$(PODS_ROOT)/DoubleConversion\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-graphics/React_graphics.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-graphics/React_graphics.framework/Headers/react/renderer/graphics/platform/ios\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-Fabric/React_Fabric.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon/ReactCommon.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon/ReactCommon.framework/Headers/react/nativemodule/core\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-RCTFabric/RCTFabric.framework/Headers\"") + assert_equal(spec.pod_target_xcconfig["HEADER_SEARCH_PATHS"], "#{other_flags} \"$(PODS_ROOT)/boost\" \"$(PODS_ROOT)/Headers/Private/Yoga\" \"$(PODS_ROOT)/DoubleConversion\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-graphics/React_graphics.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-graphics/React_graphics.framework/Headers/react/renderer/graphics/platform/ios\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-Fabric/React_Fabric.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-FabricImage/React_FabricImage.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon/ReactCommon.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon/ReactCommon.framework/Headers/react/nativemodule/core\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-RCTFabric/RCTFabric.framework/Headers\"") assert_equal(spec.pod_target_xcconfig["CLANG_CXX_LANGUAGE_STANDARD"], "c++17") assert_equal( spec.dependencies, [ { :dependency_name => "React-Core" }, { :dependency_name => "RCT-Folly", "version"=>"2021.07.22.00" }, + { :dependency_name => "glog" } ] ) end diff --git a/packages/react-native/scripts/cocoapods/__tests__/test_utils/podSpy.rb b/packages/react-native/scripts/cocoapods/__tests__/test_utils/podSpy.rb index 76da694cf85f73..0c777f83fdcb19 100644 --- a/packages/react-native/scripts/cocoapods/__tests__/test_utils/podSpy.rb +++ b/packages/react-native/scripts/cocoapods/__tests__/test_utils/podSpy.rb @@ -26,7 +26,7 @@ def podSpy_cleanUp $podInvocationCount = 0 end -def pod(name, version = nil, path: nil, configurations: nil, modular_headers: nil, podspec: nil) +def pod(name, version = nil, path: nil, configurations: nil, modular_headers: nil, podspec: nil, tag: nil) $podInvocationCount += 1 params = {} if version != nil then params[:version] = version end @@ -34,5 +34,6 @@ def pod(name, version = nil, path: nil, configurations: nil, modular_headers: ni if configurations != nil then params[:configurations] = configurations end if modular_headers != nil then params[:modular_headers] = modular_headers end if podspec != nil then params[:podspec] = podspec end + if tag != nil then params[:tag] = tag end $podInvocation[name] = params end diff --git a/packages/react-native/scripts/cocoapods/__tests__/utils-test.rb b/packages/react-native/scripts/cocoapods/__tests__/utils-test.rb index 510c4032825a0c..954630097e25a0 100644 --- a/packages/react-native/scripts/cocoapods/__tests__/utils-test.rb +++ b/packages/react-native/scripts/cocoapods/__tests__/utils-test.rb @@ -577,7 +577,7 @@ def test_updateSearchPaths_whenUseFrameworks_addsSearchPaths if pod_name == "SecondTarget" target_installation_result.native_target.build_configurations.each do |config| received_search_path = config.build_settings["HEADER_SEARCH_PATHS"] - expected_Search_path = "$(inherited) \"$(PODS_ROOT)/RCT-Folly\" \"$(PODS_ROOT)/DoubleConversion\" \"$(PODS_ROOT)/boost\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-Codegen/React_Codegen.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon/ReactCommon.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon/ReactCommon.framework/Headers/react/nativemodule/core\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-RCTFabric/RCTFabric.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-Fabric/React_Fabric.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-Graphics/React_graphics.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-Graphics/React_graphics.framework/Headers/react/renderer/graphics/platform/ios\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-Fabric/React_Fabric.framework/Headers/react/renderer/imagemanager/platform/ios\"" + expected_Search_path = "$(inherited) \"$(PODS_ROOT)/RCT-Folly\" \"$(PODS_ROOT)/DoubleConversion\" \"$(PODS_ROOT)/boost\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-Codegen/React_Codegen.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon/ReactCommon.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon/ReactCommon.framework/Headers/react/nativemodule/core\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-RCTFabric/RCTFabric.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-Fabric/React_Fabric.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-FabricImage/React_FabricImage.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-Graphics/React_graphics.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-Graphics/React_graphics.framework/Headers/react/renderer/graphics/platform/ios\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-Fabric/React_Fabric.framework/Headers/react/renderer/imagemanager/platform/ios\"" assert_equal(received_search_path, expected_Search_path) end else @@ -677,74 +677,6 @@ def test_applyFlagsForFabric_whenFabricDisabled_doNothing assert_equal(config.build_settings["OTHER_CFLAGS"], "$(inherited)") end end - - # ============================= # - # Test - Enable Hermes Profiler # - # ============================= # - - def test_enableHermesProfiler_whenEnableHermesProfileIsTrue_setsFlagsInRelease - # Arrange - first_target = prepare_target("FirstTarget") - second_target = prepare_target("SecondTarget") - third_target = prepare_target("ThirdTarget", "com.apple.product-type.bundle") - user_project_mock = UserProjectMock.new("a/path", [ - prepare_config("Debug"), - prepare_config("Release"), - ], - :native_targets => [ - first_target, - second_target - ] - ) - pods_projects_mock = PodsProjectMock.new([third_target], {"hermes-engine" => {}}) - installer = InstallerMock.new(pods_projects_mock, [ - AggregatedProjectMock.new(user_project_mock) - ]) - - # Act - ReactNativePodsUtils.enable_hermes_profiler(installer, enable_hermes_profiler: true) - - # Assert - installer.target_installation_results.pod_target_installation_results.each do |pod_name, target_installation_result| - target_installation_result.native_target.build_configurations.each do |config| - if config.name != "Release" - assert_nil(config.build_settings["OTHER_CFLAGS"]) - else - assert_equal(config.build_settings["OTHER_CFLAGS"], "$(inherited) -DRCT_REMOTE_PROFILE=1") - end - end - end - end - - def test_enableHermesProfiler_whenEnableHermesProfileIsFalse_doesNothing - # Arrange - first_target = prepare_target("FirstTarget") - second_target = prepare_target("SecondTarget") - third_target = prepare_target("ThirdTarget", "com.apple.product-type.bundle") - user_project_mock = UserProjectMock.new("a/path", [ - prepare_config("Debug"), - prepare_config("Release"), - ], - :native_targets => [ - first_target, - second_target - ] - ) - pods_projects_mock = PodsProjectMock.new([third_target], {"hermes-engine" => {}}) - installer = InstallerMock.new(pods_projects_mock, [ - AggregatedProjectMock.new(user_project_mock) - ]) - - # Act - ReactNativePodsUtils.enable_hermes_profiler(installer) - - # Assert - installer.target_installation_results.pod_target_installation_results.each do |pod_name, target_installation_result| - target_installation_result.native_target.build_configurations.each do |config| - assert_nil(config.build_settings["OTHER_CFLAGS"]) - end - end - end end # ===== # diff --git a/packages/react-native/scripts/cocoapods/codegen_utils.rb b/packages/react-native/scripts/cocoapods/codegen_utils.rb index a90acc21553b6f..c980f05762de45 100644 --- a/packages/react-native/scripts/cocoapods/codegen_utils.rb +++ b/packages/react-native/scripts/cocoapods/codegen_utils.rb @@ -80,9 +80,11 @@ def get_react_codegen_spec(package_json_file, folly_version: '2021.07.22.00', fa header_search_paths = [ "\"$(PODS_ROOT)/boost\"", "\"$(PODS_ROOT)/RCT-Folly\"", + "\"$(PODS_ROOT)/DoubleConversion\"", "\"${PODS_ROOT}/Headers/Public/React-Codegen/react/renderer/components\"", "\"$(PODS_ROOT)/Headers/Private/React-Fabric\"", "\"$(PODS_ROOT)/Headers/Private/React-RCTFabric\"", + "\"$(PODS_ROOT)/Headers/Private/Yoga\"", ] framework_search_paths = [] @@ -91,6 +93,7 @@ def get_react_codegen_spec(package_json_file, folly_version: '2021.07.22.00', fa "\"$(PODS_ROOT)/DoubleConversion\"", "\"$(PODS_TARGET_SRCROOT)\"", "\"$(PODS_CONFIGURATION_BUILD_DIR)/React-Fabric/React_Fabric.framework/Headers\"", + "\"$(PODS_CONFIGURATION_BUILD_DIR)/React-FabricImage/React_FabricImage.framework/Headers\"", "\"$(PODS_CONFIGURATION_BUILD_DIR)/React-graphics/React_graphics.framework/Headers\"", "\"$(PODS_CONFIGURATION_BUILD_DIR)/React-graphics/React_graphics.framework/Headers/react/renderer/graphics/platform/ios\"", "\"$(PODS_CONFIGURATION_BUILD_DIR)/ReactCommon/ReactCommon.framework/Headers\"", @@ -127,7 +130,9 @@ def get_react_codegen_spec(package_json_file, folly_version: '2021.07.22.00', fa "React-jsi": [], "ReactCommon/turbomodule/bridging": [], "ReactCommon/turbomodule/core": [], - "React-NativeModulesApple": [], + "React-NativeModulesApple": [], + "glog": [], + "DoubleConversion": [], } } diff --git a/packages/react-native/scripts/cocoapods/fabric.rb b/packages/react-native/scripts/cocoapods/fabric.rb index 1bd3cb2fb9db9b..3e186dc6c428d5 100644 --- a/packages/react-native/scripts/cocoapods/fabric.rb +++ b/packages/react-native/scripts/cocoapods/fabric.rb @@ -13,4 +13,5 @@ def setup_fabric!(react_native_path: "../node_modules/react-native", new_arch_en pod 'React-RCTFabric', :path => "#{react_native_path}/React", :modular_headers => true pod 'React-ImageManager', :path => "#{react_native_path}/ReactCommon/react/renderer/imagemanager/platform/ios" pod 'RCT-Folly/Fabric', :podspec => "#{react_native_path}/third-party-podspecs/RCT-Folly.podspec" + pod 'React-FabricImage', :path => "#{react_native_path}/ReactCommon" end diff --git a/packages/react-native/scripts/cocoapods/flipper.rb b/packages/react-native/scripts/cocoapods/flipper.rb index 2465a5be891f0f..73371c1df603b1 100644 --- a/packages/react-native/scripts/cocoapods/flipper.rb +++ b/packages/react-native/scripts/cocoapods/flipper.rb @@ -77,8 +77,8 @@ def flipper_post_install(installer) end end - # Enable flipper for React-Core Debug configuration - if target.name == 'React-Core' + # Enable flipper for React-RCTAppDelegate Debug configuration + if target.name == 'React-RCTAppDelegate' target.build_configurations.each do |config| if config.debug? config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] = ['$(inherited)', 'FB_SONARKIT_ENABLED=1'] diff --git a/packages/react-native/scripts/cocoapods/jsengine.rb b/packages/react-native/scripts/cocoapods/jsengine.rb index 25ed410bb4c9d3..e4b2dd4e315284 100644 --- a/packages/react-native/scripts/cocoapods/jsengine.rb +++ b/packages/react-native/scripts/cocoapods/jsengine.rb @@ -30,7 +30,11 @@ def setup_hermes!(react_native_path: "../node_modules/react-native", fabric_enab abort unless prep_status == 0 pod 'React-jsi', :path => "#{react_native_path}/ReactCommon/jsi" - pod 'hermes-engine', :podspec => "#{react_native_path}/sdks/hermes/hermes-engine.podspec" + # This `:tag => hermestag` below is only to tell CocoaPods to update hermes-engine when React Native version changes. + # We have custom logic to compute the source for hermes-engine. See sdks/hermes-engine/* + hermestag_file = File.join(react_native_path, "sdks", ".hermesversion") + hermestag = File.exist?(hermestag_file) ? File.read(hermestag_file).strip : '' + pod 'hermes-engine', :podspec => "#{react_native_path}/sdks/hermes-engine/hermes-engine.podspec", :tag => hermestag pod 'React-hermes', :path => "#{react_native_path}/ReactCommon/hermes" pod 'libevent', '~> 2.1.12' end diff --git a/packages/react-native/scripts/cocoapods/new_architecture.rb b/packages/react-native/scripts/cocoapods/new_architecture.rb index 2081333c7bc300..66aea069815917 100644 --- a/packages/react-native/scripts/cocoapods/new_architecture.rb +++ b/packages/react-native/scripts/cocoapods/new_architecture.rb @@ -87,12 +87,13 @@ def self.install_modules_dependencies(spec, new_arch_enabled, folly_version) current_config = hash["pod_target_xcconfig"] != nil ? hash["pod_target_xcconfig"] : {} current_headers = current_config["HEADER_SEARCH_PATHS"] != nil ? current_config["HEADER_SEARCH_PATHS"] : "" - header_search_paths = ["\"$(PODS_ROOT)/boost\""] + header_search_paths = ["\"$(PODS_ROOT)/boost\" \"$(PODS_ROOT)/Headers/Private/Yoga\""] if ENV['USE_FRAMEWORKS'] header_search_paths << "\"$(PODS_ROOT)/DoubleConversion\"" header_search_paths << "\"${PODS_CONFIGURATION_BUILD_DIR}/React-graphics/React_graphics.framework/Headers\"" header_search_paths << "\"${PODS_CONFIGURATION_BUILD_DIR}/React-graphics/React_graphics.framework/Headers/react/renderer/graphics/platform/ios\"" header_search_paths << "\"${PODS_CONFIGURATION_BUILD_DIR}/React-Fabric/React_Fabric.framework/Headers\"" + header_search_paths << "\"${PODS_CONFIGURATION_BUILD_DIR}/React-FabricImage/React_FabricImage.framework/Headers\"" header_search_paths << "\"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon/ReactCommon.framework/Headers\"" header_search_paths << "\"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon/ReactCommon.framework/Headers/react/nativemodule/core\"" header_search_paths << "\"${PODS_CONFIGURATION_BUILD_DIR}/React-RCTFabric/RCTFabric.framework/Headers\"" @@ -107,6 +108,7 @@ def self.install_modules_dependencies(spec, new_arch_enabled, folly_version) spec.dependency "React-Core" spec.dependency "RCT-Folly", '2021.07.22.00' + spec.dependency "glog" if new_arch_enabled current_config["OTHER_CPLUSPLUSFLAGS"] = @@new_arch_cpp_flags @@ -118,6 +120,15 @@ def self.install_modules_dependencies(spec, new_arch_enabled, folly_version) spec.dependency "ReactCommon/turbomodule/bridging" spec.dependency "ReactCommon/turbomodule/core" spec.dependency "React-NativeModulesApple" + spec.dependency "Yoga" + spec.dependency "React-Fabric" + spec.dependency "React-graphics" + + if ENV["USE_HERMES"] == nil || ENV["USE_HERMES"] == "1" + spec.dependency "hermes-engine" + else + spec.dependency "React-jsi" + end end spec.pod_target_xcconfig = current_config diff --git a/packages/react-native/scripts/cocoapods/utils.rb b/packages/react-native/scripts/cocoapods/utils.rb index 92a621d994d049..2bed5260603e25 100644 --- a/packages/react-native/scripts/cocoapods/utils.rb +++ b/packages/react-native/scripts/cocoapods/utils.rb @@ -220,13 +220,6 @@ def self.update_search_paths(installer) end end - def self.enable_hermes_profiler(installer, enable_hermes_profiler: false) - return if !enable_hermes_profiler - - Pod::UI.puts "[Hermes Profiler] Enable Hermes Sample profiler" - self.add_compiler_flag_to_pods(installer, "-DRCT_REMOTE_PROFILE=1", configuration: "Release") - end - # ========= # # Utilities # # ========= # @@ -361,6 +354,7 @@ def self.set_rctfabric_search_paths(target_installation_result) ReactNativePodsUtils.update_header_paths_if_depends_on(target_installation_result, "React-RCTFabric", [ "\"${PODS_CONFIGURATION_BUILD_DIR}/React-RCTFabric/RCTFabric.framework/Headers\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/React-Fabric/React_Fabric.framework/Headers\"", + "\"${PODS_CONFIGURATION_BUILD_DIR}/React-FabricImage/React_FabricImage.framework/Headers\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/React-Graphics/React_graphics.framework/Headers\"", "\"${PODS_CONFIGURATION_BUILD_DIR}/React-Graphics/React_graphics.framework/Headers/react/renderer/graphics/platform/ios\"", ]) @@ -384,6 +378,7 @@ def self.react_native_pods "React-Core", "React-CoreModules", "React-Fabric", + "React-FabricImage", "React-ImageManager", "React-RCTActionSheet", "React-RCTAnimation", diff --git a/packages/react-native/scripts/react_native_pods.rb b/packages/react-native/scripts/react_native_pods.rb index 0437407b2f4cee..8b786505cbff8b 100644 --- a/packages/react-native/scripts/react_native_pods.rb +++ b/packages/react-native/scripts/react_native_pods.rb @@ -222,11 +222,10 @@ def use_flipper!(versions = {}, configurations: ['Debug']) # - mac_catalyst_enabled: whether we are running the Pod on a Mac Catalyst project or not. # - enable_hermes_profiler: whether the hermes profiler should be turned on in Release mode def react_native_post_install( - installer, react_native_path = "../node_modules/react-native", - mac_catalyst_enabled: false, - enable_hermes_profiler: false + installer, + react_native_path = "../node_modules/react-native", + mac_catalyst_enabled: false ) - enable_hermes_profiler = enable_hermes_profiler || ENV["ENABLE_HERMES_PROFILER"] == "1" ReactNativePodsUtils.turn_off_resource_bundle_react_core(installer) ReactNativePodsUtils.apply_mac_catalyst_patches(installer) if mac_catalyst_enabled @@ -242,13 +241,11 @@ def react_native_post_install( ReactNativePodsUtils.update_search_paths(installer) ReactNativePodsUtils.set_node_modules_user_settings(installer, react_native_path) ReactNativePodsUtils.apply_flags_for_fabric(installer, fabric_enabled: fabric_enabled) - ReactNativePodsUtils.enable_hermes_profiler(installer, enable_hermes_profiler: enable_hermes_profiler) NewArchitectureHelper.set_clang_cxx_language_standard_if_needed(installer) is_new_arch_enabled = ENV['RCT_NEW_ARCH_ENABLED'] == "1" NewArchitectureHelper.modify_flags_for_new_architecture(installer, is_new_arch_enabled) - Pod::UI.puts "Pod install took #{Time.now.to_i - $START_TIME} [s] to run".green end diff --git a/packages/react-native/template/android/app/build.gradle b/packages/react-native/template/android/app/build.gradle index 5b1826b4127e0b..eb8f4efa97a841 100644 --- a/packages/react-native/template/android/app/build.gradle +++ b/packages/react-native/template/android/app/build.gradle @@ -1,3 +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. + */ + apply plugin: "com.android.application" apply plugin: "org.jetbrains.kotlin.android" apply plugin: "com.facebook.react" @@ -108,8 +115,6 @@ dependencies { // The version of react-native is set by the React Native Gradle Plugin implementation("com.facebook.react:react-android") - implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.0.0") - debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") { exclude group:'com.squareup.okhttp3', module:'okhttp' diff --git a/packages/react-native/template/android/build.gradle b/packages/react-native/template/android/build.gradle index cdbc9026f3552a..4b2e41b3b30e1c 100644 --- a/packages/react-native/template/android/build.gradle +++ b/packages/react-native/template/android/build.gradle @@ -9,7 +9,7 @@ buildscript { // We use NDK 23 which has both M1 support and is the side-by-side NDK version from AGP. ndkVersion = "23.1.7779620" - kotlinVersion = "1.7.22" + kotlinVersion = "1.8.0" } repositories { google() @@ -18,6 +18,6 @@ buildscript { dependencies { classpath("com.android.tools.build:gradle") classpath("com.facebook.react:react-native-gradle-plugin") - classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion") + classpath("org.jetbrains.kotlin:kotlin-gradle-plugin") } } diff --git a/packages/react-native/template/android/gradle/wrapper/gradle-wrapper.jar b/packages/react-native/template/android/gradle/wrapper/gradle-wrapper.jar index 943f0cbfa75457..c1962a79e29d3e 100644 Binary files a/packages/react-native/template/android/gradle/wrapper/gradle-wrapper.jar and b/packages/react-native/template/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/packages/react-native/template/android/gradle/wrapper/gradle-wrapper.properties b/packages/react-native/template/android/gradle/wrapper/gradle-wrapper.properties index 6ec1567a0f8831..a21c6ebe28b660 100644 --- a/packages/react-native/template/android/gradle/wrapper/gradle-wrapper.properties +++ b/packages/react-native/template/android/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.1-all.zip networkTimeout=10000 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/packages/react-native/template/android/gradlew b/packages/react-native/template/android/gradlew index 65dcd68d65c82f..aeb74cbb43e393 100755 --- a/packages/react-native/template/android/gradlew +++ b/packages/react-native/template/android/gradlew @@ -85,9 +85,6 @@ done APP_BASE_NAME=${0##*/} APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -144,7 +141,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac @@ -152,7 +149,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -197,6 +194,10 @@ if "$cygwin" || "$msys" ; then done fi + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + # Collect all arguments for the java command; # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of # shell script including quotes and variable substitutions, so put them in diff --git a/packages/react-native/template/package.json b/packages/react-native/template/package.json index 06f0f4e2a9bad6..858aba4e8f1728 100644 --- a/packages/react-native/template/package.json +++ b/packages/react-native/template/package.json @@ -19,7 +19,7 @@ "@babel/runtime": "^7.12.5", "@react-native/eslint-config": "^0.73.0", "@react-native/metro-config": "^0.73.0", - "@tsconfig/react-native": "^3.0.0", + "@react-native/typescript-config": "^0.73.0", "@types/react": "^18.0.24", "@types/react-test-renderer": "^18.0.0", "babel-jest": "^29.2.1", @@ -28,7 +28,7 @@ "metro-react-native-babel-preset": "0.76.2", "prettier": "^2.4.1", "react-test-renderer": "18.2.0", - "typescript": "4.8.4" + "typescript": "5.0.4" }, "engines": { "node": ">=16" diff --git a/packages/react-native/template/tsconfig.json b/packages/react-native/template/tsconfig.json index 45a6c707223871..304ab4e2d83d02 100644 --- a/packages/react-native/template/tsconfig.json +++ b/packages/react-native/template/tsconfig.json @@ -1,3 +1,3 @@ { - "extends": "@tsconfig/react-native/tsconfig.json" + "extends": "@react-native/typescript-config/tsconfig.json" } diff --git a/packages/react-native/types/experimental.d.ts b/packages/react-native/types/experimental.d.ts new file mode 100644 index 00000000000000..c58c9ffa10ac00 --- /dev/null +++ b/packages/react-native/types/experimental.d.ts @@ -0,0 +1,136 @@ +/** + * 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 + */ + +/** + * These are types for things that are present for New Architecture enabled apps + * which is currently considered experimental. + * + * To load the types declared here in an actual project, there are three ways. + * + * 1. If your `tsconfig.json` already has a `"types"` array in the `"compilerOptions"` section, + * is to add `"react-native/types/experimental"` to the `"types"` array. + * + * 2. Alternatively, a specific import syntax can to be used from a typescript file. + * This module does not exist in reality, which is why the {} is important: + * + * ```ts + * import {} from 'react-native/types/experimental' + * ``` + * + * 3. It is also possible to include it through a triple-slash reference: + * + * ```ts + * /// + * ``` + * + * Either the import or the reference only needs to appear once, anywhere in the project. + */ + +import {DimensionValue} from 'react-native/Libraries/StyleSheet/StyleSheetTypes'; + +export {}; + +declare module '.' { + export interface FlexStyle { + /** + * Equivalent to `top`, `bottom`, `right` and `left` + */ + inset?: DimensionValue | undefined; + + /** + * Equivalent to `top`, `bottom` + */ + insetBlock?: DimensionValue | undefined; + + /** + * Equivalent to `bottom` + */ + insetBlockEnd?: DimensionValue | undefined; + + /** + * Equivalent to `top` + */ + insetBlockStart?: DimensionValue | undefined; + + /** + * Equivalent to `right` and `left` + */ + insetInline?: DimensionValue | undefined; + + /** + * Equivalent to `right` or `left` + */ + insetInlineEnd?: DimensionValue | undefined; + + /** + * Equivalent to `right` or `left` + */ + insetInlineStart?: DimensionValue | undefined; + + /** + * Equivalent to `marginVertical` + */ + marginBlock?: DimensionValue | undefined; + + /** + * Equivalent to `marginBottom` + */ + marginBlockEnd?: DimensionValue | undefined; + + /** + * Equivalent to `marginTop` + */ + marginBlockStart?: DimensionValue | undefined; + + /** + * Equivalent to `marginHorizontal` + */ + marginInline?: DimensionValue | undefined; + + /** + * Equivalent to `marginEnd` + */ + marginInlineEnd?: DimensionValue | undefined; + + /** + * Equivalent to `marginStart` + */ + marginInlineStart?: DimensionValue | undefined; + + /** + * Equivalent to `paddingVertical` + */ + paddingBlock?: DimensionValue | undefined; + + /** + * Equivalent to `paddingBottom` + */ + paddingBlockEnd?: DimensionValue | undefined; + + /** + * Equivalent to `paddingTop` + */ + paddingBlockStart?: DimensionValue | undefined; + + /** + * Equivalent to `paddingHorizontal` + */ + paddingInline?: DimensionValue | undefined; + + /** + * Equivalent to `paddingEnd` + */ + paddingInlineEnd?: DimensionValue | undefined; + + /** + * Equivalent to `paddingStart` + */ + paddingInlineStart?: DimensionValue | undefined; + } +} diff --git a/packages/react-native/types/index.d.ts b/packages/react-native/types/index.d.ts index 5177707cc0f7b4..b01002dbc6dc1d 100644 --- a/packages/react-native/types/index.d.ts +++ b/packages/react-native/types/index.d.ts @@ -103,6 +103,7 @@ export * from '../Libraries/Components/View/View'; export * from '../Libraries/Components/View/ViewAccessibility'; export * from '../Libraries/Components/View/ViewPropTypes'; export * from '../Libraries/Components/Button'; +export * from '../Libraries/DevToolsSettings/DevToolsSettingsManager'; export * from '../Libraries/EventEmitter/NativeEventEmitter'; export * from '../Libraries/EventEmitter/RCTDeviceEventEmitter'; export * from '../Libraries/EventEmitter/RCTNativeAppEventEmitter'; diff --git a/packages/rn-tester/NativeComponentExample/ios/RNTMyNativeViewComponentView.h b/packages/rn-tester/NativeComponentExample/ios/RNTMyNativeViewComponentView.h index 6d7adce1eabb5b..60f930debdfbed 100644 --- a/packages/rn-tester/NativeComponentExample/ios/RNTMyNativeViewComponentView.h +++ b/packages/rn-tester/NativeComponentExample/ios/RNTMyNativeViewComponentView.h @@ -5,6 +5,7 @@ * LICENSE file in the root directory of this source tree. */ +#import #import #import @@ -12,6 +13,8 @@ NS_ASSUME_NONNULL_BEGIN @interface RNTMyNativeViewComponentView : RCTViewComponentView +@property (nonatomic, copy) RCTBubblingEventBlock onIntArrayChanged; + - (UIColor *)UIColorFromHexString:(const std::string)hexString; @end diff --git a/packages/rn-tester/NativeComponentExample/ios/RNTMyNativeViewComponentView.mm b/packages/rn-tester/NativeComponentExample/ios/RNTMyNativeViewComponentView.mm index 7fe66d4050d776..33e7a7f2e8b263 100644 --- a/packages/rn-tester/NativeComponentExample/ios/RNTMyNativeViewComponentView.mm +++ b/packages/rn-tester/NativeComponentExample/ios/RNTMyNativeViewComponentView.mm @@ -58,6 +58,44 @@ - (UIColor *)UIColorFromHexString:(const std::string)hexString - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps { + const auto &oldViewProps = *std::static_pointer_cast(_props); + const auto &newViewProps = *std::static_pointer_cast(props); + + if (oldViewProps.values != newViewProps.values) { + if (_eventEmitter) { + std::vector newVector = {}; + std::vector newBoolVector = {}; + std::vector newFloatVector = {}; + std::vector newDoubleVector = {}; + std::vector newYesNoVector = {}; + std::vector newStringVector = {}; + std::vector newLatLonVector = {}; + std::vector> newIntVectorVector = {}; + for (auto val : newViewProps.values) { + newVector.push_back(val * 2); + newBoolVector.push_back(val % 2 ? true : false); + newFloatVector.push_back(val * 3.14); + newDoubleVector.push_back(val / 3.14); + newYesNoVector.push_back( + val % 2 ? RNTMyNativeViewEventEmitter::OnIntArrayChangedYesNos::Yep + : RNTMyNativeViewEventEmitter::OnIntArrayChangedYesNos::Nope); + newStringVector.push_back(std::to_string(val)); + newLatLonVector.push_back({-1.0 * val, 2.0 * val}); + newIntVectorVector.push_back({val, val, val}); + } + RNTMyNativeViewEventEmitter::OnIntArrayChanged value = { + newVector, + newBoolVector, + newFloatVector, + newDoubleVector, + newYesNoVector, + newStringVector, + newLatLonVector, + newIntVectorVector}; + std::static_pointer_cast(_eventEmitter)->onIntArrayChanged(value); + } + } + [super updateProps:props oldProps:oldProps]; } diff --git a/packages/rn-tester/NativeComponentExample/ios/RNTMyNativeViewManager.mm b/packages/rn-tester/NativeComponentExample/ios/RNTMyNativeViewManager.mm index 83d8f231d4259d..6729d8f12cb071 100644 --- a/packages/rn-tester/NativeComponentExample/ios/RNTMyNativeViewManager.mm +++ b/packages/rn-tester/NativeComponentExample/ios/RNTMyNativeViewManager.mm @@ -18,6 +18,10 @@ @implementation RNTMyNativeViewManager RCT_EXPORT_VIEW_PROPERTY(backgroundColor, UIColor) +RCT_EXPORT_VIEW_PROPERTY(onIntArrayChanged, RCTBubblingEventBlock) + +RCT_EXPORT_VIEW_PROPERTY(values, NSArray *) + RCT_EXPORT_METHOD(callNativeMethodToChangeBackgroundColor : (nonnull NSNumber *)reactTag color : (NSString *)color) { [self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, NSDictionary *viewRegistry) { diff --git a/packages/rn-tester/NativeComponentExample/js/MyNativeView.js b/packages/rn-tester/NativeComponentExample/js/MyNativeView.js index 51a31ae468b3f8..c74c0f084e7648 100644 --- a/packages/rn-tester/NativeComponentExample/js/MyNativeView.js +++ b/packages/rn-tester/NativeComponentExample/js/MyNativeView.js @@ -98,7 +98,22 @@ export default function MyNativeView(props: {}): React.Node { return ( Fabric View - + { + console.log(event.nativeEvent.values); + console.log(event.nativeEvent.boolValues); + console.log(event.nativeEvent.floats); + console.log(event.nativeEvent.doubles); + console.log(event.nativeEvent.yesNos); + console.log(event.nativeEvent.strings); + console.log(event.nativeEvent.latLons); + console.log(event.nativeEvent.multiArrays); + }} + /> Legacy View , + boolValues: $ReadOnlyArray, + floats: $ReadOnlyArray, + doubles: $ReadOnlyArray, + yesNos: $ReadOnlyArray<'yep' | 'nope'>, + strings: $ReadOnlyArray, + latLons: $ReadOnlyArray<{|lat: Double, lon: Double|}>, + multiArrays: $ReadOnlyArray<$ReadOnlyArray>, +}>; + type NativeProps = $ReadOnly<{| ...ViewProps, opacity?: Float, + values: $ReadOnlyArray, + + // Events + onIntArrayChanged?: ?BubblingEventHandler, |}>; export type MyNativeViewType = HostComponent; diff --git a/packages/rn-tester/README.md b/packages/rn-tester/README.md index 688b061cbe8f9f..07eb33e3d2afc9 100644 --- a/packages/rn-tester/README.md +++ b/packages/rn-tester/README.md @@ -5,10 +5,11 @@ The RNTester showcases React Native views and modules. ## Running this app Before running the app, make sure you ran: - - git clone https://github.com/facebook/react-native.git - cd react-native - yarn install +```sh +git clone https://github.com/facebook/react-native.git +cd react-native +yarn install +``` ### Running on iOS @@ -29,11 +30,12 @@ If you are still having a problem after doing the clean up (which can happen if Both macOS and Xcode are required. 1. `cd packages/rn-tester` -1. Install [Bundler](https://bundler.io/): `gem install bundler`. We use bundler to install the right version of [CocoaPods](https://cocoapods.org/) locally. -1. Install Bundler and CocoaPods dependencies: `bundle install && bundle exec pod install` or `yarn setup-ios-hermes`. In order to use JSC instead of Hermes engine, run: `USE_HERMES=0 bundle exec pod install` or `yarn setup-ios-jsc` instead. -1. Open the generated `RNTesterPods.xcworkspace`. This is not checked in, as it is generated by CocoaPods. Do not open `RNTesterPods.xcodeproj` directly. +2. Install [Bundler](https://bundler.io/): `gem install bundler`. We use bundler to install the right version of [CocoaPods](https://cocoapods.org/) locally. +3. Install Bundler and CocoaPods dependencies: `bundle install && bundle exec pod install` or `yarn setup-ios-hermes`. In order to use JSC instead of Hermes engine, run: `USE_HERMES=0 bundle exec pod install` or `yarn setup-ios-jsc` instead. +4. Open the generated `RNTesterPods.xcworkspace`. This is not checked in, as it is generated by CocoaPods. Do not open `RNTesterPods.xcodeproj` directly. #### Note for M1 users + If you own a Mac M1 laptop, you need to run some different commands to install and run cocoapods. - `sudo arch -x86_64 gem install ffi`: this installs the `ffi` package to load dynamically-linked libraries. @@ -44,7 +46,6 @@ If you own a Mac M1 laptop, you need to run some different commands to install a You'll need to have all the [prerequisites](https://reactnative.dev/contributing/how-to-build-from-source#prerequisites) (SDK, NDK) for Building React Native installed. Start an Android emulator. - ```sh cd packages/rn-tester # In order to use Hermes engine, run `yarn install-android-hermes` instead. @@ -65,11 +66,12 @@ Follow the same setup as running with gradle. Install Buck from [here](https://buckbuild.com/setup/install.html). Run the following commands from the react-native folder: - - ./gradlew :ReactAndroid:packageReactNdkLibsForBuck - buck fetch rntester - buck install -r rntester - ./scripts/packager.sh +```sh +./gradlew :ReactAndroid:packageReactNdkLibsForBuck +buck fetch rntester +buck install -r rntester +./scripts/packager.sh +``` _Note: The native libs are still built using gradle. Full build with buck is coming soon(tm)._ diff --git a/packages/rn-tester/RNTester/AppDelegate.mm b/packages/rn-tester/RNTester/AppDelegate.mm index 3720538a3c37ba..d3f3f355f948f6 100644 --- a/packages/rn-tester/RNTester/AppDelegate.mm +++ b/packages/rn-tester/RNTester/AppDelegate.mm @@ -82,8 +82,6 @@ @interface AppDelegate () facebook::react::ContextContainer::Shared _contextContainer; std::shared_ptr _runtimeScheduler; #endif - - RCTTurboModuleManager *_turboModuleManager; } @end @@ -207,15 +205,18 @@ - (void)loadSourceForBridge:(RCTBridge *)bridge _contextContainer->insert("RuntimeScheduler", _runtimeScheduler); callInvoker = std::make_shared(_runtimeScheduler); #endif - _turboModuleManager = [[RCTTurboModuleManager alloc] initWithBridge:bridge delegate:self jsInvoker:callInvoker]; - [bridge setRCTTurboModuleRegistry:_turboModuleManager]; + + RCTTurboModuleManager *turboModuleManager = [[RCTTurboModuleManager alloc] initWithBridge:bridge + delegate:self + jsInvoker:callInvoker]; + [bridge setRCTTurboModuleRegistry:turboModuleManager]; #if RCT_DEV /** * Eagerly initialize RCTDevMenu so CMD + d, CMD + i, and CMD + r work. * This is a stop gap until we have a system to eagerly init Turbo Modules. */ - [_turboModuleManager moduleForName:"RCTDevMenu"]; + [turboModuleManager moduleForName:"RCTDevMenu"]; #endif __weak __typeof(self) weakSelf = self; @@ -225,25 +226,26 @@ - (void)loadSourceForBridge:(RCTBridge *)bridge #else return std::make_unique( #endif - facebook::react::RCTJSIExecutorRuntimeInstaller([weakSelf, bridge](facebook::jsi::Runtime &runtime) { + facebook::react::RCTJSIExecutorRuntimeInstaller([weakSelf, bridge, turboModuleManager]( + facebook::jsi::Runtime &runtime) { if (!bridge) { return; } - __typeof(self) strongSelf = weakSelf; + #if RN_FABRIC_ENABLED + __typeof(self) strongSelf = weakSelf; if (strongSelf && strongSelf->_runtimeScheduler) { facebook::react::RuntimeSchedulerBinding::createAndInstallIfNeeded(runtime, strongSelf->_runtimeScheduler); } #endif - if (strongSelf) { - facebook::react::RuntimeExecutor syncRuntimeExecutor = - [&](std::function &&callback) { callback(runtime); }; - [strongSelf->_turboModuleManager installJSBindingWithRuntimeExecutor:syncRuntimeExecutor]; - } + + facebook::react::RuntimeExecutor syncRuntimeExecutor = + [&](std::function &&callback) { callback(runtime); }; + [turboModuleManager installJSBindingWithRuntimeExecutor:syncRuntimeExecutor]; })); } -#pragma mark RCTTurboModuleManagerDelegate +#pragma mark - RCTTurboModuleManagerDelegate - (Class)getModuleClassFromName:(const char *)name { diff --git a/packages/rn-tester/RNTesterIntegrationTests/RCTRootViewIntegrationTests.m b/packages/rn-tester/RNTesterIntegrationTests/RCTRootViewIntegrationTests.m index f200ae230b40a6..5ebcc0adc2c646 100644 --- a/packages/rn-tester/RNTesterIntegrationTests/RCTRootViewIntegrationTests.m +++ b/packages/rn-tester/RNTesterIntegrationTests/RCTRootViewIntegrationTests.m @@ -50,7 +50,7 @@ - (void)rootViewDidChangeIntrinsicSize:(RCTRootView *)rootView @end -static SizeFlexibilityTestDelegate *sizeFlexibilityDelegate() +static SizeFlexibilityTestDelegate *sizeFlexibilityDelegate(void) { static SizeFlexibilityTestDelegate *delegate; if (delegate == nil) { diff --git a/packages/rn-tester/RNTesterPods.xcodeproj/project.pbxproj b/packages/rn-tester/RNTesterPods.xcodeproj/project.pbxproj index ff44d2b4f188f6..4e5505f231fb69 100644 --- a/packages/rn-tester/RNTesterPods.xcodeproj/project.pbxproj +++ b/packages/rn-tester/RNTesterPods.xcodeproj/project.pbxproj @@ -842,6 +842,10 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = RNTester/RNTester.entitlements; DEVELOPMENT_TEAM = ""; + HEADER_SEARCH_PATHS = ( + "${PODS_ROOT}/Headers/Private/Yoga", + "$(inherited)", + ); INFOPLIST_FILE = "$(SRCROOT)/RNTester/Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 13.4; LD_RUNPATH_SEARCH_PATHS = ( @@ -875,6 +879,10 @@ CODE_SIGN_ENTITLEMENTS = RNTester/RNTester.entitlements; DEVELOPMENT_TEAM = ""; EXCLUDED_ARCHS = ""; + HEADER_SEARCH_PATHS = ( + "${PODS_ROOT}/Headers/Private/Yoga", + "$(inherited)", + ); INFOPLIST_FILE = "$(SRCROOT)/RNTester/Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 13.4; LD_RUNPATH_SEARCH_PATHS = ( @@ -1084,6 +1092,10 @@ CODE_SIGN_STYLE = Automatic; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = ""; + HEADER_SEARCH_PATHS = ( + "${PODS_ROOT}/Headers/Private/Yoga", + "$(inherited)", + ); INFOPLIST_FILE = RNTesterUnitTests/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 13.4; LD_RUNPATH_SEARCH_PATHS = ( @@ -1122,6 +1134,10 @@ COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = ""; + HEADER_SEARCH_PATHS = ( + "${PODS_ROOT}/Headers/Private/Yoga", + "$(inherited)", + ); INFOPLIST_FILE = RNTesterUnitTests/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 13.4; LD_RUNPATH_SEARCH_PATHS = ( @@ -1163,6 +1179,10 @@ "FB_REFERENCE_IMAGE_DIR=\"\\\"$(SOURCE_ROOT)/RNTesterIntegrationTests/ReferenceImages\\\"\"", "$(inherited)", ); + HEADER_SEARCH_PATHS = ( + "${PODS_ROOT}/Headers/Private/Yoga", + "$(inherited)", + ); INFOPLIST_FILE = RNTesterIntegrationTests/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 13.4; LD_RUNPATH_SEARCH_PATHS = ( @@ -1198,6 +1218,10 @@ COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = ""; + HEADER_SEARCH_PATHS = ( + "${PODS_ROOT}/Headers/Private/Yoga", + "$(inherited)", + ); INFOPLIST_FILE = RNTesterIntegrationTests/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 13.4; LD_RUNPATH_SEARCH_PATHS = ( diff --git a/packages/rn-tester/RNTesterUnitTests/RCTBundleURLProviderTests.m b/packages/rn-tester/RNTesterUnitTests/RCTBundleURLProviderTests.m index 004da62a6644cc..37f45cc4ff0066 100644 --- a/packages/rn-tester/RNTesterUnitTests/RCTBundleURLProviderTests.m +++ b/packages/rn-tester/RNTesterUnitTests/RCTBundleURLProviderTests.m @@ -26,7 +26,7 @@ URLWithString: [NSString stringWithFormat: - @"http://localhost:8081/%@.bundle?platform=ios&dev=true&minify=false&modulesOnly=false&runModule=true&app=com.apple.dt.xctest.tool", + @"http://localhost:8081/%@.bundle?platform=ios&dev=true&lazy=true&minify=false&modulesOnly=false&runModule=true&app=com.apple.dt.xctest.tool", testFile]]; } @@ -36,7 +36,7 @@ URLWithString: [NSString stringWithFormat: - @"http://192.168.1.1:8081/%@.bundle?platform=ios&dev=true&minify=false&modulesOnly=false&runModule=true&app=com.apple.dt.xctest.tool", + @"http://192.168.1.1:8081/%@.bundle?platform=ios&dev=true&lazy=true&minify=false&modulesOnly=false&runModule=true&app=com.apple.dt.xctest.tool", testFile]]; } diff --git a/packages/rn-tester/android/app/_BUCK b/packages/rn-tester/android/app/_BUCK deleted file mode 100644 index ba612dfab6988e..00000000000000 --- a/packages/rn-tester/android/app/_BUCK +++ /dev/null @@ -1,39 +0,0 @@ -load("//tools/build_defs/oss:rn_defs.bzl", "KEYSTORE_TARGET", "react_native_dep", "react_native_target", "rn_android_binary", "rn_android_library", "rn_android_resource") - -rn_android_binary( - name = "app", - keystore = KEYSTORE_TARGET, - manifest = "src/main/AndroidManifest.xml", - deps = [ - ":rntester-lib", - ], -) - -rn_android_library( - name = "rntester-lib", - srcs = glob(["src/main/java/**/*.java"]), - deps = [ - ":res", - 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"), - react_native_dep("third-party/java/jsr-305:jsr-305"), - react_native_target("java/com/facebook/react:react"), - react_native_target("java/com/facebook/react/common:build_config"), - react_native_target("java/com/facebook/react/modules/core:core"), - react_native_target("java/com/facebook/react/views/text:text"), - react_native_target("java/com/facebook/react/shell:shell"), - react_native_target("jni/prebuilt:android-jsc"), - # .so files are prebuilt by Gradle with `./gradlew :ReactAndroid:packageReactNdkLibsForBuck` - react_native_target("jni/prebuilt:reactnative-libs"), - ], -) - -rn_android_resource( - name = "res", - package = "com.facebook.react.uiapp", - res = "src/main/res", -) diff --git a/packages/rn-tester/android/app/build.gradle b/packages/rn-tester/android/app/build.gradle index b597120366fa47..e9e68fee660565 100644 --- a/packages/rn-tester/android/app/build.gradle +++ b/packages/rn-tester/android/app/build.gradle @@ -116,21 +116,13 @@ android { defaultConfig { applicationId "com.facebook.react.uiapp" - minSdkVersion 21 - targetSdkVersion 33 + minSdk = 21 + targetSdk = 33 versionCode 1 versionName "1.0" testBuildType System.getProperty('testBuildType', 'debug') // This will later be used to control the test apk build type testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' } - signingConfigs { - release { - storeFile file(MYAPP_RELEASE_STORE_FILE) - storePassword MYAPP_RELEASE_STORE_PASSWORD - keyAlias MYAPP_RELEASE_KEY_ALIAS - keyPassword MYAPP_RELEASE_KEY_PASSWORD - } - } externalNativeBuild { cmake { version cmakeVersion @@ -145,15 +137,10 @@ android { } } buildTypes { - debug { - debuggable true - signingConfig signingConfigs.release - } release { - debuggable false minifyEnabled enableProguardInReleaseBuilds - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' - signingConfig signingConfigs.release + proguardFiles getDefaultProguardFile('proguard-android.txt') + signingConfig signingConfigs.debug } } sourceSets.main { @@ -173,8 +160,6 @@ dependencies { // Consume Hermes as built from source only for the Hermes variant. hermesImplementation(project(":packages:react-native:ReactAndroid:hermes-engine")) - implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0" - debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}") diff --git a/packages/rn-tester/android/app/gradle.properties b/packages/rn-tester/android/app/gradle.properties index 838ca18c4c1caa..1d6bf9759649a1 100644 --- a/packages/rn-tester/android/app/gradle.properties +++ b/packages/rn-tester/android/app/gradle.properties @@ -1,11 +1,6 @@ org.gradle.parallel=true # This is causing issue with dependencies task: https://github.com/gradle/gradle/issues/9645#issuecomment-530746758 # org.gradle.configureondemand=true -MYAPP_RELEASE_STORE_FILE=my-release-key.keystore -MYAPP_RELEASE_KEY_ALIAS=androiddebugkey -MYAPP_RELEASE_STORE_PASSWORD=android -MYAPP_RELEASE_KEY_PASSWORD=android - android.useAndroidX=true android.enableJetifier=true diff --git a/packages/rn-tester/android/app/my-release-key.keystore b/packages/rn-tester/android/app/my-release-key.keystore deleted file mode 100644 index 364e105ed39fbf..00000000000000 Binary files a/packages/rn-tester/android/app/my-release-key.keystore and /dev/null differ diff --git a/packages/rn-tester/android/app/proguard-rules.pro b/packages/rn-tester/android/app/proguard-rules.pro deleted file mode 100644 index 10279099c39e6c..00000000000000 --- a/packages/rn-tester/android/app/proguard-rules.pro +++ /dev/null @@ -1,15 +0,0 @@ -# Copyright (c) Meta Platforms, Inc. and affiliates. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. - -# Add project specific ProGuard rules here. -# By default, the flags in this file are appended to flags specified -# in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt -# You can edit the include path and order by changing the proguardFiles -# directive in build.gradle. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# Add any project specific keep options here: diff --git a/packages/rn-tester/android/app/src/main/AndroidManifest.xml b/packages/rn-tester/android/app/src/main/AndroidManifest.xml index 3e0f6056edda0b..14257864c5fbc6 100644 --- a/packages/rn-tester/android/app/src/main/AndroidManifest.xml +++ b/packages/rn-tester/android/app/src/main/AndroidManifest.xml @@ -35,7 +35,8 @@ android:name=".RNTesterApplication" android:allowBackup="true" android:banner="@drawable/tv_banner" - android:icon="@drawable/launcher_icon" + android:icon="@mipmap/ic_launcher" + android:roundIcon="@mipmap/ic_launcher_round" android:label="@string/app_name" android:theme="@style/AppTheme"> ints) { + WritableMap payload = Arguments.createMap(); + + WritableArray newIntArray = Arguments.createArray(); + WritableArray newBoolArray = Arguments.createArray(); + WritableArray newFloatArray = Arguments.createArray(); + WritableArray newDoubleArray = Arguments.createArray(); + WritableArray newYesNoArray = Arguments.createArray(); + WritableArray newStringArray = Arguments.createArray(); + WritableArray newObjectArray = Arguments.createArray(); + WritableArray newArrayArray = Arguments.createArray(); + + for (Integer i : ints) { + newIntArray.pushInt(i * 2); + newBoolArray.pushBoolean(i % 2 == 1); + newFloatArray.pushDouble(i * 3.14); + newDoubleArray.pushDouble(i / 3.14); + newYesNoArray.pushString(i % 2 == 1 ? "yep" : "nope"); + newStringArray.pushString(i.toString()); + + WritableMap latLon = Arguments.createMap(); + latLon.putDouble("lat", -1.0 * i); + latLon.putDouble("lon", 2.0 * i); + newObjectArray.pushMap(latLon); + + WritableArray innerArray = Arguments.createArray(); + innerArray.pushInt(i); + innerArray.pushInt(i); + innerArray.pushInt(i); + newArrayArray.pushArray(innerArray); + } + + payload.putArray("values", newIntArray); + payload.putArray("boolValues", newBoolArray); + payload.putArray("floats", newFloatArray); + payload.putArray("doubles", newDoubleArray); + payload.putArray("yesNos", newYesNoArray); + payload.putArray("strings", newStringArray); + payload.putArray("latLons", newObjectArray); + payload.putArray("multiArrays", newArrayArray); + + ReactContext reactContext = (ReactContext) getContext(); + int surfaceId = UIManagerHelper.getSurfaceId(reactContext); + EventDispatcher eventDispatcher = + UIManagerHelper.getEventDispatcherForReactTag(reactContext, getId()); + Event event = new OnIntArrayChangedEvent(surfaceId, getId(), payload); + + if (eventDispatcher != null) { + eventDispatcher.dispatchEvent(event); + } + } + + class OnIntArrayChangedEvent extends Event { + private WritableMap mPayload; + + public OnIntArrayChangedEvent(int surfaceId, int viewId, WritableMap payload) { + super(surfaceId, viewId); + this.mPayload = payload; + } + + @Override + public String getEventName() { + return "onIntArrayChanged"; + } + + @Override + protected WritableMap getEventData() { + return mPayload; + } + } } diff --git a/packages/rn-tester/android/app/src/main/java/com/facebook/react/uiapp/component/MyNativeViewManager.java b/packages/rn-tester/android/app/src/main/java/com/facebook/react/uiapp/component/MyNativeViewManager.java index d8c8b731acb3cf..05d23b978aad00 100644 --- a/packages/rn-tester/android/app/src/main/java/com/facebook/react/uiapp/component/MyNativeViewManager.java +++ b/packages/rn-tester/android/app/src/main/java/com/facebook/react/uiapp/component/MyNativeViewManager.java @@ -11,6 +11,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.facebook.react.bridge.ReadableArray; +import com.facebook.react.common.MapBuilder; import com.facebook.react.module.annotations.ReactModule; import com.facebook.react.uimanager.SimpleViewManager; import com.facebook.react.uimanager.ThemedReactContext; @@ -19,6 +20,10 @@ import com.facebook.react.uimanager.annotations.ReactProp; import com.facebook.react.viewmanagers.RNTMyNativeViewManagerDelegate; import com.facebook.react.viewmanagers.RNTMyNativeViewManagerInterface; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; /** View manager for {@link MyNativeView} components. */ @ReactModule(name = MyNativeViewManager.REACT_CLASS) @@ -67,4 +72,29 @@ public void callNativeMethodToChangeBackgroundColor(MyNativeView view, String co public void setOpacity(@NonNull MyNativeView view, float opacity) { super.setOpacity(view, opacity); } + + @Override + @ReactProp(name = "values") + public void setValues(@NonNull MyNativeView view, @Nullable ReadableArray value) { + List mValues = new ArrayList(); + for (int i = 0; i < value.size(); i++) { + mValues.add(value.getInt(i)); + } + view.emitOnArrayChangedEvent(mValues); + } + + @Override + public final Map getExportedCustomBubblingEventTypeConstants() { + Map eventTypeConstants = new HashMap(); + eventTypeConstants.putAll( + MapBuilder.builder() + .put( + "onIntArrayChanged", + MapBuilder.of( + "phasedRegistrationNames", + MapBuilder.of( + "bubbled", "onIntArrayChanged", "captured", "onIntArrayChangedCapture"))) + .build()); + return eventTypeConstants; + } } diff --git a/packages/rn-tester/android/app/src/main/res/drawable/ic_launcher_background.xml b/packages/rn-tester/android/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 00000000000000..f3baaded29af3b --- /dev/null +++ b/packages/rn-tester/android/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/rn-tester/android/app/src/main/res/drawable/ic_launcher_foreground.xml b/packages/rn-tester/android/app/src/main/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 00000000000000..4ff27896d09bea --- /dev/null +++ b/packages/rn-tester/android/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,23 @@ + + + + + + diff --git a/packages/rn-tester/android/app/src/main/res/drawable/launcher_icon.png b/packages/rn-tester/android/app/src/main/res/drawable/launcher_icon.png deleted file mode 100644 index a4aa3bd6d9acdc..00000000000000 Binary files a/packages/rn-tester/android/app/src/main/res/drawable/launcher_icon.png and /dev/null differ diff --git a/packages/rn-tester/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/packages/rn-tester/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 00000000000000..50ec886232535e --- /dev/null +++ b/packages/rn-tester/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/packages/rn-tester/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/packages/rn-tester/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 00000000000000..50ec886232535e --- /dev/null +++ b/packages/rn-tester/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/packages/rn-tester/android/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/packages/rn-tester/android/app/src/main/res/mipmap-hdpi/ic_launcher.webp new file mode 100644 index 00000000000000..21a22e50f23be1 Binary files /dev/null and b/packages/rn-tester/android/app/src/main/res/mipmap-hdpi/ic_launcher.webp differ diff --git a/packages/rn-tester/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/packages/rn-tester/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp new file mode 100644 index 00000000000000..7be461f34f10c0 Binary files /dev/null and b/packages/rn-tester/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ diff --git a/packages/rn-tester/android/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/packages/rn-tester/android/app/src/main/res/mipmap-mdpi/ic_launcher.webp new file mode 100644 index 00000000000000..761b8813248575 Binary files /dev/null and b/packages/rn-tester/android/app/src/main/res/mipmap-mdpi/ic_launcher.webp differ diff --git a/packages/rn-tester/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/packages/rn-tester/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp new file mode 100644 index 00000000000000..86adfdb7b61e5d Binary files /dev/null and b/packages/rn-tester/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ diff --git a/packages/rn-tester/android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/packages/rn-tester/android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp new file mode 100644 index 00000000000000..7e73de98bc1d60 Binary files /dev/null and b/packages/rn-tester/android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp differ diff --git a/packages/rn-tester/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/packages/rn-tester/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp new file mode 100644 index 00000000000000..5553d426c186cf Binary files /dev/null and b/packages/rn-tester/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ diff --git a/packages/rn-tester/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/packages/rn-tester/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp new file mode 100644 index 00000000000000..c695cac7e095d6 Binary files /dev/null and b/packages/rn-tester/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ diff --git a/packages/rn-tester/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/packages/rn-tester/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp new file mode 100644 index 00000000000000..32fd7a2e3f8156 Binary files /dev/null and b/packages/rn-tester/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ diff --git a/packages/rn-tester/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/packages/rn-tester/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp new file mode 100644 index 00000000000000..a50331bc40ce4c Binary files /dev/null and b/packages/rn-tester/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ diff --git a/packages/rn-tester/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/packages/rn-tester/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp new file mode 100644 index 00000000000000..877e6d2def6ee7 Binary files /dev/null and b/packages/rn-tester/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ diff --git a/packages/rn-tester/android/app/src/main/res/values/styles.xml b/packages/rn-tester/android/app/src/main/res/values/styles.xml index 42c90f3e99a984..7ba83a2ad5a2c9 100644 --- a/packages/rn-tester/android/app/src/main/res/values/styles.xml +++ b/packages/rn-tester/android/app/src/main/res/values/styles.xml @@ -1,9 +1,8 @@ - diff --git a/packages/rn-tester/js/components/ListExampleShared.js b/packages/rn-tester/js/components/ListExampleShared.js index 1acad0e6f5a5e5..32ddc5633f39c3 100644 --- a/packages/rn-tester/js/components/ListExampleShared.js +++ b/packages/rn-tester/js/components/ListExampleShared.js @@ -13,6 +13,7 @@ const React = require('react'); const { + ActivityIndicator, Animated, Image, Platform, @@ -33,16 +34,28 @@ export type Item = { ... }; -function genItemData(count: number, start: number = 0): Array { +function genItemData(i: number): Item { + const itemHash = Math.abs(hashCode('Item ' + i)); + return { + title: 'Item ' + i, + text: LOREM_IPSUM.slice(0, (itemHash % 301) + 20), + key: String(i), + pressed: false, + }; +} + +function genNewerItems(count: number, start: number = 0): Array { + const dataBlob = []; + for (let i = start; i < count + start; i++) { + dataBlob.push(genItemData(i)); + } + return dataBlob; +} + +function genOlderItems(count: number, start: number = 0): Array { const dataBlob = []; - for (let ii = start; ii < count + start; ii++) { - const itemHash = Math.abs(hashCode('Item ' + ii)); - dataBlob.push({ - title: 'Item ' + ii, - text: LOREM_IPSUM.substr(0, (itemHash % 301) + 20), - key: String(ii), - pressed: false, - }); + for (let i = count; i > 0; i--) { + dataBlob.push(genItemData(start - i)); } return dataBlob; } @@ -147,6 +160,12 @@ class SeparatorComponent extends React.PureComponent<{...}> { } } +const LoadingComponent: React.ComponentType<{}> = React.memo(() => ( + + + +)); + class ItemSeparatorComponent extends React.PureComponent<$FlowFixMeProps> { render(): React.Node { const style = this.props.highlighted @@ -352,6 +371,13 @@ const styles = StyleSheet.create({ text: { flex: 1, }, + loadingContainer: { + alignItems: 'center', + justifyContent: 'center', + height: 100, + borderTopWidth: 1, + borderTopColor: 'rgb(200, 199, 204)', + }, }); module.exports = { @@ -362,8 +388,10 @@ module.exports = { ItemSeparatorComponent, PlainInput, SeparatorComponent, + LoadingComponent, Spindicator, - genItemData, + genNewerItems, + genOlderItems, getItemLayout, pressItem, renderSmallSwitchOption, diff --git a/packages/rn-tester/js/examples/ActivityIndicator/ActivityIndicatorExample.js b/packages/rn-tester/js/examples/ActivityIndicator/ActivityIndicatorExample.js index b2d7c9e8ad849e..97df4046375aa7 100644 --- a/packages/rn-tester/js/examples/ActivityIndicator/ActivityIndicatorExample.js +++ b/packages/rn-tester/js/examples/ActivityIndicator/ActivityIndicatorExample.js @@ -8,7 +8,7 @@ * @flow strict-local */ -import type {Node} from 'React'; +import type {Node} from 'react'; import React, {useCallback, useEffect, useRef, useState} from 'react'; import {ActivityIndicator, StyleSheet, View} from 'react-native'; diff --git a/packages/rn-tester/js/examples/Crash/CrashExample.js b/packages/rn-tester/js/examples/Crash/CrashExample.js index 01b55b70ebbfe6..a1fe3a2cfe0849 100644 --- a/packages/rn-tester/js/examples/Crash/CrashExample.js +++ b/packages/rn-tester/js/examples/Crash/CrashExample.js @@ -8,7 +8,7 @@ * @flow strict-local */ -import type {Node} from 'React'; +import type {Node} from 'react'; import {Button} from 'react-native'; import React from 'react'; diff --git a/packages/rn-tester/js/examples/Experimental/W3CPointerEventPlatformTests/PointerEventPointerCancelTouch.js b/packages/rn-tester/js/examples/Experimental/W3CPointerEventPlatformTests/PointerEventPointerCancelTouch.js index 09dc77c1cf1336..8059b8f9d65572 100644 --- a/packages/rn-tester/js/examples/Experimental/W3CPointerEventPlatformTests/PointerEventPointerCancelTouch.js +++ b/packages/rn-tester/js/examples/Experimental/W3CPointerEventPlatformTests/PointerEventPointerCancelTouch.js @@ -157,10 +157,11 @@ function PointerEventPointerCancelTouchTestCase( } const styles = StyleSheet.create({ - scrollContainer: {width: '100%', height: '100%'}, + scrollContainer: {width: '100%', height: 100}, target: { backgroundColor: 'black', padding: 32, + height: 200, }, }); diff --git a/packages/rn-tester/js/examples/FlatList/FlatList-basic.js b/packages/rn-tester/js/examples/FlatList/FlatList-basic.js index abf37ca4c331ea..360540c61a2277 100644 --- a/packages/rn-tester/js/examples/FlatList/FlatList-basic.js +++ b/packages/rn-tester/js/examples/FlatList/FlatList-basic.js @@ -35,8 +35,10 @@ import { ItemSeparatorComponent, PlainInput, SeparatorComponent, + LoadingComponent, Spindicator, - genItemData, + genNewerItems, + genOlderItems, getItemLayout, pressItem, renderSmallSwitchOption, @@ -44,6 +46,11 @@ import { import type {Item} from '../../components/ListExampleShared'; +const PAGE_SIZE = 100; +const NUM_PAGES = 10; +const INITIAL_PAGE_OFFSET = Math.floor(NUM_PAGES / 2); +const LOAD_TIME = 2000; + const VIEWABILITY_CONFIG = { minimumViewTime: 3000, viewAreaCoveragePercentThreshold: 100, @@ -53,6 +60,8 @@ const VIEWABILITY_CONFIG = { type Props = $ReadOnly<{||}>; type State = {| data: Array, + first: number, + last: number, debug: boolean, horizontal: boolean, inverted: boolean, @@ -66,13 +75,18 @@ type State = {| onPressDisabled: boolean, textSelectable: boolean, isRTL: boolean, + maintainVisibleContentPosition: boolean, + previousLoading: boolean, + nextLoading: boolean, |}; const IS_RTL = I18nManager.isRTL; class FlatListExample extends React.PureComponent { state: State = { - data: genItemData(100), + data: genNewerItems(PAGE_SIZE, PAGE_SIZE * INITIAL_PAGE_OFFSET), + first: PAGE_SIZE * INITIAL_PAGE_OFFSET, + last: PAGE_SIZE + PAGE_SIZE * INITIAL_PAGE_OFFSET, debug: false, horizontal: false, inverted: false, @@ -86,6 +100,9 @@ class FlatListExample extends React.PureComponent { onPressDisabled: false, textSelectable: true, isRTL: IS_RTL, + maintainVisibleContentPosition: true, + previousLoading: false, + nextLoading: false, }; /* $FlowFixMe[missing-local-annot] The type annotation(s) required by Flow's @@ -206,6 +223,11 @@ class FlatListExample extends React.PureComponent { this.state.isRTL, this._setIsRTL, )} + {renderSmallSwitchOption( + 'Maintain content position', + this.state.maintainVisibleContentPosition, + this._setBooleanValue('maintainVisibleContentPosition'), + )} {Platform.OS === 'android' && ( { } - ListFooterComponent={FooterComponent} + ListHeaderComponent={ + this.state.previousLoading ? LoadingComponent : HeaderComponent + } + ListFooterComponent={ + this.state.nextLoading ? LoadingComponent : FooterComponent + } ListEmptyComponent={ListEmptyComponent} // $FlowFixMe[missing-empty-array-annot] data={this.state.empty ? [] : filteredData} @@ -247,6 +273,8 @@ class FlatListExample extends React.PureComponent { keyboardShouldPersistTaps="always" keyboardDismissMode="on-drag" numColumns={1} + onStartReached={this._onStartReached} + initialScrollIndex={Math.floor(PAGE_SIZE / 2)} onEndReached={this._onEndReached} onRefresh={this._onRefresh} onScroll={ @@ -257,6 +285,11 @@ class FlatListExample extends React.PureComponent { refreshing={false} contentContainerStyle={styles.list} viewabilityConfig={VIEWABILITY_CONFIG} + maintainVisibleContentPosition={ + this.state.maintainVisibleContentPosition + ? {minIndexForVisible: 0} + : undefined + } {...flatListItemRendererProps} /> @@ -277,13 +310,33 @@ class FlatListExample extends React.PureComponent { _getItemLayout = (data: any, index: number) => { return getItemLayout(data, index, this.state.horizontal); }; + _onStartReached = () => { + if (this.state.first <= 0 || this.state.previousLoading) { + return; + } + + this.setState({previousLoading: true}); + setTimeout(() => { + this.setState(state => ({ + previousLoading: false, + data: genOlderItems(PAGE_SIZE, state.first).concat(state.data), + first: state.first - PAGE_SIZE, + })); + }, LOAD_TIME); + }; _onEndReached = () => { - if (this.state.data.length >= 1000) { + if (this.state.last >= PAGE_SIZE * NUM_PAGES || this.state.nextLoading) { return; } - this.setState(state => ({ - data: state.data.concat(genItemData(100, state.data.length)), - })); + + this.setState({nextLoading: true}); + setTimeout(() => { + this.setState(state => ({ + nextLoading: false, + data: state.data.concat(genNewerItems(PAGE_SIZE, state.last)), + last: state.last + PAGE_SIZE, + })); + }, LOAD_TIME); }; // $FlowFixMe[missing-local-annot] _onPressCallback = () => { @@ -340,7 +393,7 @@ class FlatListExample extends React.PureComponent { _pressItem = (key: string) => { this._listRef?.recordInteraction(); - const index = Number(key); + const index = this.state.data.findIndex(item => item.key === key); const itemState = pressItem(this.state.data[index]); this.setState(state => ({ ...state, diff --git a/packages/rn-tester/js/examples/FlatList/FlatList-multiColumn.js b/packages/rn-tester/js/examples/FlatList/FlatList-multiColumn.js index 4c5ea5ddd554ab..fd8d10a43474c3 100644 --- a/packages/rn-tester/js/examples/FlatList/FlatList-multiColumn.js +++ b/packages/rn-tester/js/examples/FlatList/FlatList-multiColumn.js @@ -23,7 +23,7 @@ const { ItemComponent, PlainInput, SeparatorComponent, - genItemData, + genNewerItems, getItemLayout, pressItem, renderSmallSwitchOption, @@ -46,7 +46,7 @@ class MultiColumnExample extends React.PureComponent< numColumns: number, virtualized: boolean, |} = { - data: genItemData(1000), + data: genNewerItems(1000), filterText: '', fixedHeight: true, logViewable: false, diff --git a/packages/rn-tester/js/examples/FlatList/FlatList-onEndReached.js b/packages/rn-tester/js/examples/FlatList/FlatList-onEndReached.js index 792b63f677c0d3..a7d3042c6ae258 100644 --- a/packages/rn-tester/js/examples/FlatList/FlatList-onEndReached.js +++ b/packages/rn-tester/js/examples/FlatList/FlatList-onEndReached.js @@ -45,7 +45,7 @@ export default ({ name: 'onEndReached', description: 'Scroll to end of list or tap Test button to see `onEndReached` triggered.', - render: function (): React.Element { + render: function () { return ; }, }: RNTesterModuleExample); diff --git a/packages/rn-tester/js/examples/FlatList/FlatList-onStartReached.js b/packages/rn-tester/js/examples/FlatList/FlatList-onStartReached.js index 344337a796259b..84f1fcaf4229d9 100644 --- a/packages/rn-tester/js/examples/FlatList/FlatList-onStartReached.js +++ b/packages/rn-tester/js/examples/FlatList/FlatList-onStartReached.js @@ -48,7 +48,7 @@ export default ({ name: 'onStartReached', description: 'Scroll to start of list or tap Test button to see `onStartReached` triggered.', - render: function (): React.Element { + render: function () { return ; }, }: RNTesterModuleExample); diff --git a/packages/rn-tester/js/examples/SectionList/SectionList-contentInset.js b/packages/rn-tester/js/examples/SectionList/SectionList-contentInset.js index cb83e64940caea..afd85a6d7ea810 100644 --- a/packages/rn-tester/js/examples/SectionList/SectionList-contentInset.js +++ b/packages/rn-tester/js/examples/SectionList/SectionList-contentInset.js @@ -78,7 +78,7 @@ export default { title: 'SectionList Content Inset', platform: 'ios', name: 'SectionList-contentInset', - render: function (): React.Element { + render: function (): React.MixedElement { return ; }, }; diff --git a/packages/rn-tester/js/examples/SectionList/SectionList-inverted.js b/packages/rn-tester/js/examples/SectionList/SectionList-inverted.js index f965dac8237772..55b84326f6098a 100644 --- a/packages/rn-tester/js/examples/SectionList/SectionList-inverted.js +++ b/packages/rn-tester/js/examples/SectionList/SectionList-inverted.js @@ -38,7 +38,7 @@ export function SectionList_inverted(): React.Node { export default { title: 'SectionList Inverted', name: 'SectionList-inverted', - render: function (): React.Element { + render: function (): React.MixedElement { return ; }, }; diff --git a/packages/rn-tester/js/examples/SectionList/SectionList-onEndReached.js b/packages/rn-tester/js/examples/SectionList/SectionList-onEndReached.js index 1f7794e8b234f1..f1f9812b999ba8 100644 --- a/packages/rn-tester/js/examples/SectionList/SectionList-onEndReached.js +++ b/packages/rn-tester/js/examples/SectionList/SectionList-onEndReached.js @@ -41,7 +41,7 @@ export default { title: 'SectionList onEndReached', name: 'SectionList-onEndReached', description: 'Test onEndReached behavior', - render: function (): React.Element { + render: function (): React.MixedElement { return ; }, }; diff --git a/packages/rn-tester/js/examples/SectionList/SectionList-onViewableItemsChanged.js b/packages/rn-tester/js/examples/SectionList/SectionList-onViewableItemsChanged.js index 61ee3b66e30d5d..fbd5ef4dbbb41b 100644 --- a/packages/rn-tester/js/examples/SectionList/SectionList-onViewableItemsChanged.js +++ b/packages/rn-tester/js/examples/SectionList/SectionList-onViewableItemsChanged.js @@ -73,9 +73,7 @@ const styles = StyleSheet.create({ export default { title: 'SectionList On Viewable Items Changed', name: 'SectionList_onViewableItemsChanged', - render: function (): React.Element< - typeof SectionList_onViewableItemsChanged, - > { + render: function (): React.MixedElement { return ( @@ -358,7 +358,7 @@ const styles = StyleSheet.create({ export default { title: 'SectionList scrollable', name: 'SectionList-scrollable', - render: function (): React.Element { + render: function (): React.MixedElement { return ; }, }; diff --git a/packages/rn-tester/js/examples/SectionList/SectionList-stickyHeadersEnabled.js b/packages/rn-tester/js/examples/SectionList/SectionList-stickyHeadersEnabled.js index 98973e6a8f2dfd..7b4f133430791a 100644 --- a/packages/rn-tester/js/examples/SectionList/SectionList-stickyHeadersEnabled.js +++ b/packages/rn-tester/js/examples/SectionList/SectionList-stickyHeadersEnabled.js @@ -45,9 +45,7 @@ export default { title: 'SectionList Sticky Headers Enabled', name: 'SectionList-stickyHeadersEnabled', description: 'Toggle sticky headers on/off', - render: function (): React.Element< - typeof SectionList_stickySectionHeadersEnabled, - > { + render: function (): React.MixedElement { return ; }, }; diff --git a/packages/rn-tester/js/examples/SectionList/SectionList-withSeparators.js b/packages/rn-tester/js/examples/SectionList/SectionList-withSeparators.js index 309517ccd03071..ad35234d9b004d 100644 --- a/packages/rn-tester/js/examples/SectionList/SectionList-withSeparators.js +++ b/packages/rn-tester/js/examples/SectionList/SectionList-withSeparators.js @@ -54,7 +54,7 @@ const styles = StyleSheet.create({ export default { title: 'SectionList With Separators', name: 'SectionList-withSeparators', - render: function (): React.Element { + render: function (): React.MixedElement { return ; }, }; diff --git a/packages/rn-tester/js/examples/TextInput/TextInputSharedExamples.js b/packages/rn-tester/js/examples/TextInput/TextInputSharedExamples.js index 353379409ffe6a..c05948b0639800 100644 --- a/packages/rn-tester/js/examples/TextInput/TextInputSharedExamples.js +++ b/packages/rn-tester/js/examples/TextInput/TextInputSharedExamples.js @@ -438,7 +438,7 @@ class TokenizedTextExample extends React.Component< if (token[0].length === 0) { index = 1; } - parts.push(_text.substr(0, index)); + parts.push(_text.slice(0, index)); parts.push(token[0]); index = index + token[0].length; _text = _text.slice(index); diff --git a/packages/rn-tester/js/examples/TurboModule/NativeCxxModuleExampleExample.js b/packages/rn-tester/js/examples/TurboModule/NativeCxxModuleExampleExample.js index 9e18022e84cfb4..3aeb55e8040770 100644 --- a/packages/rn-tester/js/examples/TurboModule/NativeCxxModuleExampleExample.js +++ b/packages/rn-tester/js/examples/TurboModule/NativeCxxModuleExampleExample.js @@ -231,7 +231,7 @@ class NativeCxxModuleExampleExample extends React.Component<{||}, State> { item} renderItem={({item}: {item: Examples, ...}) => ( diff --git a/packages/rn-tester/package.json b/packages/rn-tester/package.json index 36e39e0697a1aa..009da93bf1bb77 100644 --- a/packages/rn-tester/package.json +++ b/packages/rn-tester/package.json @@ -1,17 +1,20 @@ { - "private": true, "name": "@react-native/tester", "version": "0.0.1", - "license": "MIT", + "private": true, "description": "React Native tester app.", - "homepage": "https://github.com/facebook/react-native/tree/HEAD/packages/rn-tester", + "license": "MIT", "repository": { "type": "git", - "url": "git@github.com:facebook/react-native.git", + "url": "https://github.com/facebook/react-native.git", "directory": "packages/rn-tester" }, + "engines": { + "node": ">=16" + }, "scripts": { "start": "react-native start", + "android": "react-native run-android --mode HermesDebug --appId 'com.facebook.react.uiapp' --main-activity 'com.facebook.react.uiapp.RNTesterActivity'", "install-android-jsc": "../../gradlew :packages:rn-tester:android:app:installJscDebug", "install-android-hermes": "../../gradlew :packages:rn-tester:android:app:installHermesDebug", "clean-android": "rm -rf android/app/build", @@ -20,7 +23,7 @@ "clean-ios": "rm -rf build/generated/ios Pods Podfile.lock" }, "dependencies": { - "flow-enums-runtime": "^0.0.5", + "flow-enums-runtime": "^0.0.6", "invariant": "^2.2.4", "nullthrows": "^1.1.1" }, diff --git a/packages/rn-tester/react-native.config.js b/packages/rn-tester/react-native.config.js index 845ae99d8cdc9e..099000c501058d 100644 --- a/packages/rn-tester/react-native.config.js +++ b/packages/rn-tester/react-native.config.js @@ -29,5 +29,8 @@ module.exports = { ios: { sourceDir: '.', }, + android: { + sourceDir: '../../', + }, }, }; diff --git a/packages/typescript-config/README.md b/packages/typescript-config/README.md new file mode 100644 index 00000000000000..baa6d6a1581724 --- /dev/null +++ b/packages/typescript-config/README.md @@ -0,0 +1,5 @@ +# @react-native/typescript-config + +This package provides the default `tsconfig.json` used by newly built React Native apps. + +This template is customized for specific versions of React Native, and should be updated in sync with the rest of your app. diff --git a/packages/typescript-config/package.json b/packages/typescript-config/package.json new file mode 100644 index 00000000000000..896de154d849f7 --- /dev/null +++ b/packages/typescript-config/package.json @@ -0,0 +1,15 @@ +{ + "name": "@react-native/typescript-config", + "version": "0.73.0", + "description": "Default TypeScript configuration for React Native apps", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/facebook/react-native.git", + "directory": "packages/typescript-config" + }, + "homepage": "https://github.com/facebook/react-native/tree/HEAD/packages/typescript-config#readme", + "keywords": ["typescript", "tsconfig", "react-native"], + "bugs": "https://github.com/facebook/react-native/issues", + "main": "tsconfig.json" +} diff --git a/packages/typescript-config/tsconfig.json b/packages/typescript-config/tsconfig.json new file mode 100644 index 00000000000000..06686519903f5d --- /dev/null +++ b/packages/typescript-config/tsconfig.json @@ -0,0 +1,42 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "display": "React Native", + "compilerOptions": { + "target": "esnext", + "module": "commonjs", + "types": ["react-native", "jest"], + "lib": [ + "es2019", + "es2020.bigint", + "es2020.date", + "es2020.number", + "es2020.promise", + "es2020.string", + "es2020.symbol.wellknown", + "es2021.promise", + "es2021.string", + "es2021.weakref", + "es2022.array", + "es2022.object", + "es2022.string" + ], + "allowJs": true, + "jsx": "react-native", + "noEmit": true, + "isolatedModules": true, + "strict": true, + "moduleResolution": "nodenext", + "resolveJsonModule": true, + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "skipLibCheck": true, + // Causes issues with package.json "exports" + "forceConsistentCasingInFileNames": false + }, + "exclude": [ + "node_modules", + "babel.config.js", + "metro.config.js", + "jest.config.js" + ] + } diff --git a/packages/virtualized-lists/Lists/VirtualizedList.js b/packages/virtualized-lists/Lists/VirtualizedList.js index 2aca79a2ea2503..8a23e81cbef1a6 100644 --- a/packages/virtualized-lists/Lists/VirtualizedList.js +++ b/packages/virtualized-lists/Lists/VirtualizedList.js @@ -73,6 +73,10 @@ type ViewabilityHelperCallbackTuple = { type State = { renderMask: CellRenderMask, cellsAroundViewport: {first: number, last: number}, + // Used to track items added at the start of the list for maintainVisibleContentPosition. + firstVisibleItemKey: ?string, + // When > 0 the scroll position available in JS is considered stale and should not be used. + pendingScrollUpdateCount: number, }; /** @@ -448,9 +452,24 @@ class VirtualizedList extends StateSafePureComponent { const initialRenderRegion = VirtualizedList._initialRenderRegion(props); + const minIndexForVisible = + this.props.maintainVisibleContentPosition?.minIndexForVisible ?? 0; + this.state = { cellsAroundViewport: initialRenderRegion, renderMask: VirtualizedList._createRenderMask(props, initialRenderRegion), + firstVisibleItemKey: + this.props.getItemCount(this.props.data) > minIndexForVisible + ? VirtualizedList._getItemKey(this.props, minIndexForVisible) + : null, + // When we have a non-zero initialScrollIndex, we will receive a + // scroll event later so this will prevent the window from updating + // until we get a valid offset. + pendingScrollUpdateCount: + this.props.initialScrollIndex != null && + this.props.initialScrollIndex > 0 + ? 1 + : 0, }; } @@ -502,6 +521,40 @@ class VirtualizedList extends StateSafePureComponent { } } + static _findItemIndexWithKey( + props: Props, + key: string, + hint: ?number, + ): ?number { + const itemCount = props.getItemCount(props.data); + if (hint != null && hint >= 0 && hint < itemCount) { + const curKey = VirtualizedList._getItemKey(props, hint); + if (curKey === key) { + return hint; + } + } + for (let ii = 0; ii < itemCount; ii++) { + const curKey = VirtualizedList._getItemKey(props, ii); + if (curKey === key) { + return ii; + } + } + return null; + } + + static _getItemKey( + props: { + data: Props['data'], + getItem: Props['getItem'], + keyExtractor: Props['keyExtractor'], + ... + }, + index: number, + ): string { + const item = props.getItem(props.data, index); + return VirtualizedList._keyExtractor(item, index, props); + } + static _createRenderMask( props: Props, cellsAroundViewport: {first: number, last: number}, @@ -585,6 +638,7 @@ class VirtualizedList extends StateSafePureComponent { _adjustCellsAroundViewport( props: Props, cellsAroundViewport: {first: number, last: number}, + pendingScrollUpdateCount: number, ): {first: number, last: number} { const {data, getItemCount} = props; const onEndReachedThreshold = onEndReachedThresholdOrDefault( @@ -616,22 +670,9 @@ class VirtualizedList extends StateSafePureComponent { ), }; } else { - // If we have a positive 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 != null && - props.initialScrollIndex > 0 && - !this._scrollMetrics.offset && - Math.abs(distanceFromEnd) >= Number.EPSILON - ) { + // If we have a pending scroll update, we should not adjust the render window as it + // might override the correct window. + if (pendingScrollUpdateCount > 0) { return cellsAroundViewport.last >= getItemCount(data) ? VirtualizedList._constrainToItemCount(cellsAroundViewport, props) : cellsAroundViewport; @@ -713,14 +754,59 @@ class VirtualizedList extends StateSafePureComponent { return prevState; } + let maintainVisibleContentPositionAdjustment: ?number = null; + const prevFirstVisibleItemKey = prevState.firstVisibleItemKey; + const minIndexForVisible = + newProps.maintainVisibleContentPosition?.minIndexForVisible ?? 0; + const newFirstVisibleItemKey = + newProps.getItemCount(newProps.data) > minIndexForVisible + ? VirtualizedList._getItemKey(newProps, minIndexForVisible) + : null; + if ( + newProps.maintainVisibleContentPosition != null && + prevFirstVisibleItemKey != null && + newFirstVisibleItemKey != null + ) { + if (newFirstVisibleItemKey !== prevFirstVisibleItemKey) { + // Fast path if items were added at the start of the list. + const hint = + itemCount - prevState.renderMask.numCells() + minIndexForVisible; + const firstVisibleItemIndex = VirtualizedList._findItemIndexWithKey( + newProps, + prevFirstVisibleItemKey, + hint, + ); + maintainVisibleContentPositionAdjustment = + firstVisibleItemIndex != null + ? firstVisibleItemIndex - minIndexForVisible + : null; + } else { + maintainVisibleContentPositionAdjustment = null; + } + } + const constrainedCells = VirtualizedList._constrainToItemCount( - prevState.cellsAroundViewport, + maintainVisibleContentPositionAdjustment != null + ? { + first: + prevState.cellsAroundViewport.first + + maintainVisibleContentPositionAdjustment, + last: + prevState.cellsAroundViewport.last + + maintainVisibleContentPositionAdjustment, + } + : prevState.cellsAroundViewport, newProps, ); return { cellsAroundViewport: constrainedCells, renderMask: VirtualizedList._createRenderMask(newProps, constrainedCells), + firstVisibleItemKey: newFirstVisibleItemKey, + pendingScrollUpdateCount: + maintainVisibleContentPositionAdjustment != null + ? prevState.pendingScrollUpdateCount + 1 + : prevState.pendingScrollUpdateCount, }; } @@ -752,7 +838,7 @@ class VirtualizedList extends StateSafePureComponent { for (let ii = first; ii <= last; ii++) { const item = getItem(data, ii); - const key = this._keyExtractor(item, ii, this.props); + const key = VirtualizedList._keyExtractor(item, ii, this.props); this._indicesToKeys.set(ii, key); if (stickyIndicesFromProps.has(ii + stickyOffset)) { @@ -825,15 +911,14 @@ class VirtualizedList extends StateSafePureComponent { _getSpacerKey = (isVertical: boolean): string => isVertical ? 'height' : 'width'; - _keyExtractor( + static _keyExtractor( item: Item, index: number, props: { keyExtractor?: ?(item: Item, index: number) => string, ... }, - // $FlowFixMe[missing-local-annot] - ) { + ): string { if (props.keyExtractor != null) { return props.keyExtractor(item, index); } @@ -879,6 +964,10 @@ class VirtualizedList extends StateSafePureComponent { cellKey={this._getCellKey() + '-header'} key="$header"> { style: inversionStyle ? [inversionStyle, this.props.style] : this.props.style, + maintainVisibleContentPosition: + this.props.maintainVisibleContentPosition != null + ? { + ...this.props.maintainVisibleContentPosition, + // Adjust index to account for ListHeaderComponent. + minIndexForVisible: + this.props.maintainVisibleContentPosition.minIndexForVisible + + (this.props.ListHeaderComponent ? 1 : 0), + } + : undefined, }; this._hasMore = this.state.cellsAroundViewport.last < itemCount - 1; @@ -1457,8 +1556,13 @@ class VirtualizedList extends StateSafePureComponent { onStartReachedThreshold, onEndReached, onEndReachedThreshold, - initialScrollIndex, } = this.props; + // If we have any pending scroll updates it means that the scroll metrics + // are out of date and we should not call any of the edge reached callbacks. + if (this.state.pendingScrollUpdateCount > 0) { + return; + } + const {contentLength, visibleLength, offset} = this._scrollMetrics; let distanceFromStart = offset; let distanceFromEnd = contentLength - visibleLength - offset; @@ -1510,14 +1614,8 @@ class VirtualizedList extends StateSafePureComponent { 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}); - } + this._sentStartForContentLength = this._scrollMetrics.contentLength; + onStartReached({distanceFromStart}); } // If the user scrolls away from the start or end and back again, @@ -1644,6 +1742,11 @@ class VirtualizedList extends StateSafePureComponent { visibleLength, zoomScale, }; + if (this.state.pendingScrollUpdateCount > 0) { + this.setState(state => ({ + pendingScrollUpdateCount: state.pendingScrollUpdateCount - 1, + })); + } this._updateViewableItems(this.props, this.state.cellsAroundViewport); if (!this.props) { return; @@ -1759,6 +1862,7 @@ class VirtualizedList extends StateSafePureComponent { const cellsAroundViewport = this._adjustCellsAroundViewport( props, state.cellsAroundViewport, + state.pendingScrollUpdateCount, ); const renderMask = VirtualizedList._createRenderMask( props, @@ -1789,7 +1893,7 @@ class VirtualizedList extends StateSafePureComponent { return { index, item, - key: this._keyExtractor(item, index, props), + key: VirtualizedList._keyExtractor(item, index, props), isViewable, }; }; @@ -1850,13 +1954,12 @@ class VirtualizedList extends StateSafePureComponent { inLayout?: boolean, ... } => { - const {data, getItem, getItemCount, getItemLayout} = props; + const {data, 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)]; + const frame = this._frames[VirtualizedList._getItemKey(props, index)]; if (!frame || frame.index !== index) { if (getItemLayout) { /* $FlowFixMe[prop-missing] (>=0.63.0 site=react_native_fb) This comment @@ -1891,11 +1994,8 @@ class VirtualizedList extends StateSafePureComponent { // where it is. if ( focusedCellIndex >= itemCount || - this._keyExtractor( - props.getItem(props.data, focusedCellIndex), - focusedCellIndex, - props, - ) !== this._lastFocusedCellKey + VirtualizedList._getItemKey(props, focusedCellIndex) !== + this._lastFocusedCellKey ) { return []; } @@ -1936,6 +2036,11 @@ class VirtualizedList extends StateSafePureComponent { props: FrameMetricProps, cellsAroundViewport: {first: number, last: number}, ) { + // If we have any pending scroll updates it means that the scroll metrics + // are out of date and we should not call any of the visibility callbacks. + if (this.state.pendingScrollUpdateCount > 0) { + return; + } this._viewabilityTuples.forEach(tuple => { tuple.viewabilityHelper.onUpdate( props, diff --git a/packages/virtualized-lists/Lists/__tests__/VirtualizedList-test.js b/packages/virtualized-lists/Lists/__tests__/VirtualizedList-test.js index 218f7c1cae71db..c030e8a2d7e690 100644 --- a/packages/virtualized-lists/Lists/__tests__/VirtualizedList-test.js +++ b/packages/virtualized-lists/Lists/__tests__/VirtualizedList-test.js @@ -2164,10 +2164,70 @@ it('virtualizes away last focused index if item removed', () => { expect(component).toMatchSnapshot(); }); -function generateItems(count) { +it('handles maintainVisibleContentPosition', () => { + const items = generateItems(20); + const ITEM_HEIGHT = 10; + + let component; + ReactTestRenderer.act(() => { + component = ReactTestRenderer.create( + , + ); + }); + + ReactTestRenderer.act(() => { + simulateLayout(component, { + viewport: {width: 10, height: 50}, + content: {width: 10, height: items.length * ITEM_HEIGHT}, + }); + + performAllBatches(); + }); + + // Initial render. + expect(component).toMatchSnapshot(); + + // Add new items at the start of the list to trigger the maintainVisibleContentPosition adjustment. + const newItems = [...generateItems(10, items.length), ...items]; + ReactTestRenderer.act(() => { + component.update( + , + ); + }); + + // Previously rendered cells should be rendered still. + expect(component).toMatchSnapshot(); + + // Simulate scroll adjustment from native maintainVisibleContentPosition. + ReactTestRenderer.act(() => { + simulateContentLayout(component, { + width: 10, + height: newItems.length * ITEM_HEIGHT, + }); + simulateScroll(component, {x: 0, y: 10 * ITEM_HEIGHT}); + performAllBatches(); + }); + + // Previously rendered cells should be rendered still + starting to render new cells ahead. + expect(component).toMatchSnapshot(); +}); + +function generateItems(count, startKey = 0) { return Array(count) .fill() - .map((_, i) => ({key: i})); + .map((_, i) => ({key: i + startKey})); } function generateItemsStickyEveryN(count, n) { @@ -2225,7 +2285,7 @@ function simulateContentLayout(component, dimensions) { function simulateCellLayout(component, items, itemIndex, dimensions) { const instance = component.getInstance(); - const cellKey = instance._keyExtractor( + const cellKey = VirtualizedList._keyExtractor( items[itemIndex], itemIndex, instance.props, diff --git a/packages/virtualized-lists/Lists/__tests__/__snapshots__/VirtualizedList-test.js.snap b/packages/virtualized-lists/Lists/__tests__/__snapshots__/VirtualizedList-test.js.snap index cd174da04cca2c..b877e3da84d999 100644 --- a/packages/virtualized-lists/Lists/__tests__/__snapshots__/VirtualizedList-test.js.snap +++ b/packages/virtualized-lists/Lists/__tests__/__snapshots__/VirtualizedList-test.js.snap @@ -65,6 +65,7 @@ exports[`VirtualizedList forwards correct stickyHeaderIndices when ListHeaderCom >
@@ -1048,6 +1049,7 @@ exports[`VirtualizedList renders all the bells and whistles 1`] = `
@@ -1834,45 +1837,12 @@ exports[`adjusts render area with non-zero initialScrollIndex 1`] = ` /> - - - - - - - - - - - - - - + style={ + Object { + "height": 50, + } + } + /> `; @@ -3173,7 +3143,7 @@ exports[`gracefully handles negative initialScrollIndex 1`] = ` `; -exports[`initially renders nothing when initialNumToRender is 0 1`] = ` +exports[`handles maintainVisibleContentPosition 1`] = ` + + + + + + + + + + + + + + + @@ -3236,10 +3282,40 @@ exports[`initially renders nothing when initialNumToRender is 0 1`] = ` `; -exports[`keeps viewport above last focused rendered 1`] = ` +exports[`handles maintainVisibleContentPosition 2`] = ` - - - - - - - - - - - - @@ -3371,23 +3420,7 @@ exports[`keeps viewport above last focused rendered 1`] = ` style={null} > - - - - - - - - + style={ + Object { + "height": 150, + } + } + /> `; -exports[`keeps viewport below last focused rendered 1`] = ` +exports[`handles maintainVisibleContentPosition 3`] = ` + + + + + + + + + + + + + + +`; + +exports[`initially renders nothing when initialNumToRender is 0 1`] = ` + + + + + +`; + +exports[`keeps viewport above last focused rendered 1`] = ` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +`; + +exports[`keeps viewport below last focused rendered 1`] = ` + + + + + + + + + + + + + - - - - - + style={ + Object { + "height": 20, + } + } + /> `; diff --git a/packages/virtualized-lists/Lists/__tests__/__snapshots__/VirtualizedSectionList-test.js.snap b/packages/virtualized-lists/Lists/__tests__/__snapshots__/VirtualizedSectionList-test.js.snap index 9f2d41bf9aa513..3f64c8856611e6 100644 --- a/packages/virtualized-lists/Lists/__tests__/__snapshots__/VirtualizedSectionList-test.js.snap +++ b/packages/virtualized-lists/Lists/__tests__/__snapshots__/VirtualizedSectionList-test.js.snap @@ -831,6 +831,7 @@ exports[`VirtualizedSectionList renders all the bells and whistles 1`] = `
diff --git a/packages/virtualized-lists/README.md b/packages/virtualized-lists/README.md new file mode 100644 index 00000000000000..78481f7944ac5e --- /dev/null +++ b/packages/virtualized-lists/README.md @@ -0,0 +1,21 @@ +# @react-native/virtualized-lists + +[![Version][version-badge]][package] + +## Installation + +``` +yarn add @react-native/virtualized-lists +``` + +*Note: We're using `yarn` to install deps. Feel free to change commands to use `npm` 3+ and `npx` if you like* + +[version-badge]: https://img.shields.io/npm/v/@react-native/virtualized-lists?style=flat-square +[package]: https://www.npmjs.com/package/@react-native/virtualized-lists + +## Testing + +To run the tests in this package, run the following commands from the React Native root folder: + +1. `yarn` to install the dependencies. You just need to run this once +2. `yarn jest packages/virtualized-lists`. diff --git a/packages/virtualized-lists/package.json b/packages/virtualized-lists/package.json index b8315f86b5e560..00b078ac22af4c 100644 --- a/packages/virtualized-lists/package.json +++ b/packages/virtualized-lists/package.json @@ -2,12 +2,18 @@ "name": "@react-native/virtualized-lists", "version": "0.73.0", "description": "Virtualized lists for React Native.", + "license": "MIT", "repository": { "type": "git", - "url": "git@github.com:facebook/react-native.git", + "url": "https://github.com/facebook/react-native.git", "directory": "packages/virtualized-lists" }, - "license": "MIT", + "homepage": "https://github.com/facebook/react-native/tree/HEAD/packages/virtualized-lists#readme", + "keywords": ["lists", "virtualized-lists", "section-lists", "react-native"], + "bugs": "https://github.com/facebook/react-native/issues", + "engines": { + "node": ">=16" + }, "dependencies": { "invariant": "^2.2.4", "nullthrows": "^1.1.1" diff --git a/scripts/__tests__/publish-npm-test.js b/scripts/__tests__/publish-npm-test.js new file mode 100644 index 00000000000000..d0944faaa342c8 --- /dev/null +++ b/scripts/__tests__/publish-npm-test.js @@ -0,0 +1,230 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + */ + +const execMock = jest.fn(); +const echoMock = jest.fn(); +const exitMock = jest.fn(); +const isTaggedLatestMock = jest.fn(); +const publishAndroidArtifactsToMavenMock = jest.fn(); +const env = process.env; + +jest + .mock('shelljs', () => ({ + exec: execMock, + echo: echoMock, + exit: exitMock, + })) + .mock('./../scm-utils', () => ({ + exitIfNotOnGit: command => command(), + getCurrentCommit: () => 'currentco_mmit', + isTaggedLatest: isTaggedLatestMock, + })) + .mock('path', () => ({ + join: () => '../packages/react-native', + })) + .mock('fs') + .mock('./../release-utils', () => ({ + generateAndroidArtifacts: jest.fn(), + publishAndroidArtifactsToMaven: publishAndroidArtifactsToMavenMock, + })); + +const date = new Date('2023-04-20T23:52:39.543Z'); + +const publishNpm = require('../publish-npm'); + +describe('publish-npm', () => { + beforeAll(() => { + jest.useFakeTimers({legacyFakeTimers: false}); + jest.setSystemTime(date); + }); + afterAll(() => { + jest.useRealTimers(); + }); + afterEach(() => { + process.env = env; + }); + + afterEach(() => { + jest.resetModules(); + jest.resetAllMocks(); + }); + + describe('dry-run', () => { + it('should set version and not publish', () => { + execMock.mockReturnValueOnce({code: 0}); + + publishNpm('dry-run'); + + expect(exitMock).toHaveBeenCalledWith(0); + expect(isTaggedLatestMock.mock.calls).toHaveLength(0); + expect(echoMock).toHaveBeenCalledWith( + 'Skipping `npm publish` because --dry-run is set.', + ); + expect(execMock).toHaveBeenCalledWith( + 'node scripts/set-rn-version.js --to-version 1000.0.0-currentco --build-type dry-run', + ); + expect(execMock.mock.calls).toHaveLength(1); + }); + }); + + describe('nightly', () => { + it('should publish', () => { + execMock + .mockReturnValueOnce({stdout: '0.81.0-rc.1\n', code: 0}) + .mockReturnValueOnce({code: 0}) + .mockReturnValueOnce({code: 0}); + const expectedVersion = '0.82.0-nightly-20230420-currentco'; + + publishNpm('nightly'); + + expect(publishAndroidArtifactsToMavenMock).toHaveBeenCalledWith( + expectedVersion, + true, + ); + expect(execMock.mock.calls[0][0]).toBe( + `npm view react-native dist-tags.next`, + ); + expect(execMock.mock.calls[1][0]).toBe( + `node scripts/set-rn-version.js --to-version ${expectedVersion} --build-type nightly`, + ); + expect(execMock.mock.calls[2][0]).toBe('npm publish --tag nightly'); + expect(echoMock).toHaveBeenCalledWith( + `Published to npm ${expectedVersion}`, + ); + expect(exitMock).toHaveBeenCalledWith(0); + expect(execMock.mock.calls).toHaveLength(3); + }); + + it('should fail to set version', () => { + execMock + .mockReturnValueOnce({stdout: '0.81.0-rc.1\n', code: 0}) + .mockReturnValueOnce({code: 1}); + const expectedVersion = '0.82.0-nightly-20230420-currentco'; + + publishNpm('nightly'); + + expect(publishAndroidArtifactsToMavenMock).not.toBeCalled(); + expect(execMock.mock.calls[0][0]).toBe( + `npm view react-native dist-tags.next`, + ); + expect(execMock.mock.calls[1][0]).toBe( + `node scripts/set-rn-version.js --to-version ${expectedVersion} --build-type nightly`, + ); + expect(echoMock).toHaveBeenCalledWith( + `Failed to set version number to ${expectedVersion}`, + ); + expect(exitMock).toHaveBeenCalledWith(1); + expect(execMock.mock.calls).toHaveLength(2); + }); + }); + + describe('release', () => { + it('should fail with invalid release version', () => { + process.env.CIRCLE_TAG = '1.0.1'; + expect(() => { + publishNpm('release'); + }).toThrow('Version 1.0.1 is not valid for Release'); + expect(publishAndroidArtifactsToMavenMock).not.toBeCalled(); + }); + + it('should publish non-latest', () => { + execMock.mockReturnValueOnce({code: 0}); + isTaggedLatestMock.mockReturnValueOnce(false); + process.env.CIRCLE_TAG = '0.81.1'; + process.env.NPM_CONFIG_OTP = 'otp'; + + publishNpm('release'); + + const expectedVersion = '0.81.1'; + expect(publishAndroidArtifactsToMavenMock).toHaveBeenCalledWith( + expectedVersion, + false, + ); + expect(execMock).toHaveBeenCalledWith( + `npm publish --tag 0.81-stable --otp otp`, + {cwd: '../packages/react-native'}, + ); + expect(echoMock).toHaveBeenCalledWith( + `Published to npm ${expectedVersion}`, + ); + expect(exitMock).toHaveBeenCalledWith(0); + expect(execMock.mock.calls).toHaveLength(1); + }); + + it('should publish latest stable', () => { + execMock.mockReturnValueOnce({code: 0}); + isTaggedLatestMock.mockReturnValueOnce(true); + process.env.CIRCLE_TAG = '0.81.1'; + process.env.NPM_CONFIG_OTP = 'otp'; + + publishNpm('release'); + + const expectedVersion = '0.81.1'; + expect(publishAndroidArtifactsToMavenMock).toHaveBeenCalledWith( + expectedVersion, + false, + ); + expect(execMock).toHaveBeenCalledWith( + `npm publish --tag latest --otp ${process.env.NPM_CONFIG_OTP}`, + {cwd: '../packages/react-native'}, + ); + expect(echoMock).toHaveBeenCalledWith( + `Published to npm ${expectedVersion}`, + ); + expect(exitMock).toHaveBeenCalledWith(0); + expect(execMock.mock.calls).toHaveLength(1); + }); + + it('should fail to publish latest stable', () => { + execMock.mockReturnValueOnce({code: 1}); + isTaggedLatestMock.mockReturnValueOnce(true); + process.env.CIRCLE_TAG = '0.81.1'; + process.env.NPM_CONFIG_OTP = 'otp'; + + publishNpm('release'); + + const expectedVersion = '0.81.1'; + expect(publishAndroidArtifactsToMavenMock).toHaveBeenCalledWith( + expectedVersion, + false, + ); + expect(execMock).toHaveBeenCalledWith( + `npm publish --tag latest --otp ${process.env.NPM_CONFIG_OTP}`, + {cwd: '../packages/react-native'}, + ); + expect(echoMock).toHaveBeenCalledWith(`Failed to publish package to npm`); + expect(exitMock).toHaveBeenCalledWith(1); + expect(execMock.mock.calls).toHaveLength(1); + }); + + it('should publish next', () => { + execMock.mockReturnValueOnce({code: 0}); + isTaggedLatestMock.mockReturnValueOnce(true); + process.env.CIRCLE_TAG = '0.81.0-rc.4'; + process.env.NPM_CONFIG_OTP = 'otp'; + + publishNpm('release'); + + const expectedVersion = '0.81.0-rc.4'; + expect(publishAndroidArtifactsToMavenMock).toHaveBeenCalledWith( + expectedVersion, + false, + ); + expect(execMock).toHaveBeenCalledWith( + `npm publish --tag next --otp ${process.env.NPM_CONFIG_OTP}`, + {cwd: '../packages/react-native'}, + ); + expect(echoMock).toHaveBeenCalledWith( + `Published to npm ${expectedVersion}`, + ); + expect(exitMock).toHaveBeenCalledWith(0); + expect(execMock.mock.calls).toHaveLength(1); + }); + }); +}); diff --git a/scripts/__tests__/version-utils-test.js b/scripts/__tests__/version-utils-test.js index ad6d958ebff313..1294c0d132d777 100644 --- a/scripts/__tests__/version-utils-test.js +++ b/scripts/__tests__/version-utils-test.js @@ -11,6 +11,7 @@ const { parseVersion, isReleaseBranch, validateBuildType, + isNightly, } = require('../version-utils'); let execResult = null; @@ -300,6 +301,32 @@ describe('version-utils', () => { }); }); + describe('isNightly', () => { + it('should match old version of nightlies', () => { + expect( + isNightly({ + version: '0.0.0-20230420-2108-f84256a92', + major: '0', + minor: '0', + patch: '0', + prerelease: '20230420-2108-f84256a92', + }), + ).toBe(true); + }); + + it('should match nightlies', () => { + expect( + isNightly({ + version: '0.81.0-nightly-20230420-f84256a92', + major: '0', + minor: '81', + patch: '0', + prerelease: 'nightly-20230420-f84256a92', + }), + ).toBe(true); + }); + }); + describe('Validate version', () => { it('Throw error if the buildType is unknown', () => { function testInvalidFunction() { diff --git a/scripts/publish-npm.js b/scripts/publish-npm.js index 40cae87f6a0cc3..661944fa6c39a1 100755 --- a/scripts/publish-npm.js +++ b/scripts/publish-npm.js @@ -9,6 +9,21 @@ 'use strict'; +const {exec, echo, exit} = require('shelljs'); +const {parseVersion} = require('./version-utils'); +const { + exitIfNotOnGit, + getCurrentCommit, + isTaggedLatest, +} = require('./scm-utils'); +const { + generateAndroidArtifacts, + publishAndroidArtifactsToMaven, +} = require('./release-utils'); +const fs = require('fs'); +const path = require('path'); +const yargs = require('yargs'); + /** * This script prepares a release version of react-native and may publish to NPM. * It is supposed to run in CI environment, not on a developer's machine. @@ -31,148 +46,137 @@ * * or otherwise `{major}.{minor}-stable` */ -const {exec, echo, exit} = require('shelljs'); -const {parseVersion} = require('./version-utils'); -const { - exitIfNotOnGit, - getCurrentCommit, - isTaggedLatest, -} = require('./scm-utils'); -const { - generateAndroidArtifacts, - publishAndroidArtifactsToMaven, -} = require('./release-utils'); -const fs = require('fs'); -const path = require('path'); -const yargs = require('yargs'); - -const buildTag = process.env.CIRCLE_TAG; -const otp = process.env.NPM_CONFIG_OTP; - -const RN_PACKAGE_DIR = path.join(__dirname, '..', 'packages', 'react-native'); - -const argv = yargs - .option('n', { - alias: 'nightly', - type: 'boolean', - default: false, - }) - .option('d', { - alias: 'dry-run', - type: 'boolean', - default: false, - }) - .option('r', { - alias: 'release', - type: 'boolean', - default: false, - }) - .strict().argv; -const nightlyBuild = argv.nightly; -const dryRunBuild = argv.dryRun; -const releaseBuild = argv.release; -const isCommitly = nightlyBuild || dryRunBuild; - -const buildType = releaseBuild - ? 'release' - : nightlyBuild - ? 'nightly' - : 'dry-run'; - -// 34c034298dc9cad5a4553964a5a324450fda0385 -const currentCommit = getCurrentCommit(); -const shortCommit = currentCommit.slice(0, 9); - -const rawVersion = - // 0.0.0 triggers issues with cocoapods for codegen when building template project. - dryRunBuild - ? '1000.0.0' - : // For nightly we continue to use 0.0.0 for clarity for npm - nightlyBuild - ? '0.0.0' - : // For pre-release and stable releases, we use the git tag of the version we're releasing (set in bump-oss-version) - buildTag; - -let version, - major, - minor, - prerelease = null; -try { - ({version, major, minor, prerelease} = parseVersion(rawVersion, buildType)); -} catch (e) { - echo(e.message); - exit(1); +if (require.main === module) { + const argv = yargs + .option('n', { + alias: 'nightly', + type: 'boolean', + default: false, + }) + .option('d', { + alias: 'dry-run', + type: 'boolean', + default: false, + }) + .option('r', { + alias: 'release', + type: 'boolean', + default: false, + }) + .strict().argv; + + const buildType = argv.release + ? 'release' + : argv.nightly + ? 'nightly' + : 'dry-run'; + + publishNpm(buildType); } -let releaseVersion; -if (dryRunBuild) { - releaseVersion = `${version}-${shortCommit}`; -} else if (nightlyBuild) { - // 2021-09-28T05:38:40.669Z -> 20210928-0538 - const dateIdentifier = new Date() - .toISOString() - .slice(0, -8) - .replace(/[-:]/g, '') - .replace(/[T]/g, '-'); - releaseVersion = `${version}-${dateIdentifier}-${shortCommit}`; -} else { - releaseVersion = version; +// Get `next` version from npm and +1 on the minor for `main` version +function getMainVersion() { + const cmd = 'npm view react-native dist-tags.next'; + echo(cmd); + const result = exec(cmd); + if (result.code) { + throw 'Failed to get next version from npm'; + } + const {major, minor} = parseVersion(result.stdout.trim(), 'release'); + return `${major}.${parseInt(minor, 10) + 1}.0`; } -// Bump version number in various files (package.json, gradle.properties etc) -// For stable, pre-release releases, we rely on CircleCI job `prepare_package_for_release` to handle this -if (isCommitly) { - if ( - exec( - `node scripts/set-rn-version.js --to-version ${releaseVersion} --build-type ${buildType}`, - ).code - ) { - echo(`Failed to set version number to ${releaseVersion}`); - exit(1); +function getNpmInfo(buildType) { + const currentCommit = getCurrentCommit(); + const shortCommit = currentCommit.slice(0, 9); + + if (buildType === 'dry-run') { + return { + version: `1000.0.0-${shortCommit}`, + tag: null, // We never end up publishing this + }; + } + + if (buildType === 'nightly') { + const mainVersion = getMainVersion(); + const dateIdentifier = new Date() + .toISOString() + .slice(0, -14) + .replace(/[-]/g, ''); + return { + version: `${mainVersion}-nightly-${dateIdentifier}-${shortCommit}`, + tag: 'nightly', + }; } + + const {version, major, minor, prerelease} = parseVersion( + process.env.CIRCLE_TAG, + buildType, + ); + + // See if releaser indicated that this version should be tagged "latest" + // Set in `bump-oss-version` + const isLatest = exitIfNotOnGit( + () => isTaggedLatest(currentCommit), + 'Not in git. We do not want to publish anything', + ); + + const releaseBranchTag = `${major}.${minor}-stable`; + + // npm will automatically tag the version as `latest` if no tag is set when we publish + // To prevent this, use `releaseBranchTag` when we don't want that (ex. releasing a patch on older release) + const tag = + prerelease != null ? 'next' : isLatest ? 'latest' : releaseBranchTag; + + return { + version, + tag, + }; } -generateAndroidArtifacts(releaseVersion); +function publishNpm(buildType) { + const {version, tag} = getNpmInfo(buildType); + + // Set version number in various files (package.json, gradle.properties etc) + // For non-nightly, non-dry-run, CircleCI job `prepare_package_for_release` does this + if (buildType === 'nightly' || buildType === 'dry-run') { + if ( + exec( + `node scripts/set-rn-version.js --to-version ${version} --build-type ${buildType}`, + ).code + ) { + echo(`Failed to set version number to ${version}`); + return exit(1); + } + } + + generateAndroidArtifacts(version); -// Write version number to the build folder -const releaseVersionFile = path.join('build', '.version'); -fs.writeFileSync(releaseVersionFile, releaseVersion); + // Write version number to the build folder + const versionFile = path.join('build', '.version'); + fs.writeFileSync(versionFile, version); -if (dryRunBuild) { - echo('Skipping `npm publish` because --dry-run is set.'); - exit(0); -} + if (buildType === 'dry-run') { + echo('Skipping `npm publish` because --dry-run is set.'); + return exit(0); + } -// Running to see if this commit has been git tagged as `latest` -const isLatest = exitIfNotOnGit( - () => isTaggedLatest(currentCommit), - 'Not in git. We do not want to publish anything', -); - -// We first publish on Maven Central all the necessary artifacts. -// NPM publishing is done just after. -publishAndroidArtifactsToMaven(releaseVersion, nightlyBuild); - -const releaseBranch = `${major}.${minor}-stable`; - -// Set the right tag for nightly and prerelease builds -// If a release is not git-tagged as `latest` we use `releaseBranch` to prevent -// npm from overriding the current `latest` version tag, which it will do if no tag is set. -const tagFlag = nightlyBuild - ? '--tag nightly' - : prerelease != null - ? '--tag next' - : isLatest - ? '--tag latest' - : `--tag ${releaseBranch}`; - -// use otp from envvars if available -const otpFlag = otp ? `--otp ${otp}` : ''; - -if (exec(`npm publish ${tagFlag} ${otpFlag}`, {cwd: RN_PACKAGE_DIR}).code) { - echo('Failed to publish package to npm'); - exit(1); -} else { - echo(`Published to npm ${releaseVersion}`); - exit(0); + // We first publish on Maven Central all the necessary artifacts. + // NPM publishing is done just after. + publishAndroidArtifactsToMaven(version, buildType === 'nightly'); + + const tagFlag = `--tag ${tag}`; + const otp = process.env.NPM_CONFIG_OTP; + const otpFlag = otp ? ` --otp ${otp}` : ''; + + const packageDirPath = path.join(__dirname, '..', 'packages', 'react-native'); + if (exec(`npm publish ${tagFlag}${otpFlag}`, {cwd: packageDirPath}).code) { + echo('Failed to publish package to npm'); + return exit(1); + } else { + echo(`Published to npm ${version}`); + return exit(0); + } } + +module.exports = publishNpm; diff --git a/scripts/version-utils.js b/scripts/version-utils.js index 826050ac0d0f4a..427a9b4d71cb30 100644 --- a/scripts/version-utils.js +++ b/scripts/version-utils.js @@ -19,7 +19,7 @@ const VERSION_REGEX = /^v?((\d+)\.(\d+)\.(\d+)(?:-(.+))?)$/; * - stable: 0.68.1 * - stable prerelease: 0.70.0-rc.0 * - e2e-test: X.Y.Z-20221116-2018 - * - nightly: 0.0.0-20221116-2018-0bc4547fc + * - nightly: X.Y.Z-20221116-0bc4547fc * - dryrun: 1000.0.0 * * Parameters: @@ -106,7 +106,7 @@ function validateRelease(version) { function validateDryRun(version) { if ( !isMain(version) && - !isNightlyBuild(version) && + !isNightly(version) && !isStableRelease(version) && !isStablePrerelease(version) ) { @@ -116,7 +116,7 @@ function validateDryRun(version) { function validateNightly(version) { // a valid nightly is a prerelease - if (!isNightlyBuild(version)) { + if (!isNightly(version)) { throw new Error(`Version ${version.version} is not valid for nightlies`); } } @@ -139,10 +139,13 @@ function isStablePrerelease(version) { ); } -function isNightlyBuild(version) { - return ( - version.major === '0' && version.minor === '0' && version.patch === '0' - ); +function isNightly(version) { + // Check if older nightly version + if (version.major === '0' && version.minor === '0' && version.patch === '0') { + return true; + } + + return version.version.includes('nightly'); } function isMain(version) { @@ -158,6 +161,7 @@ function isReleaseBranch(branch) { module.exports = { validateBuildType, parseVersion, + isNightly, isReleaseBranch, isMain, isStableRelease, diff --git a/tools/eslint/rules/valid-flow-typed-signature.js b/tools/eslint/rules/valid-flow-typed-signature.js index c90ed5bbef663f..76ba9d10ed7872 100644 --- a/tools/eslint/rules/valid-flow-typed-signature.js +++ b/tools/eslint/rules/valid-flow-typed-signature.js @@ -34,7 +34,7 @@ module.exports = { const sourceText = context.getSourceCode().getText(); const firstLineEndIndex = sourceText.indexOf('\n'); - const firstLine = sourceText.substr(0, firstLineEndIndex); + const firstLine = sourceText.slice(0, firstLineEndIndex); const match = firstLine.match(HASH_COMMENT_RE); if (match == null) { @@ -43,7 +43,7 @@ module.exports = { } const hash = match[1]; - const versionedCode = sourceText.substr(firstLineEndIndex + 1); + const versionedCode = sourceText.slice(firstLineEndIndex + 1); if (md5(versionedCode) === hash) { return; } diff --git a/yarn.lock b/yarn.lock index b18b0a9fde2ac7..fb09bc3e4bd30b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1358,6 +1358,18 @@ tar "^6.1.11" tar-stream "^2.1.4" +"@eslint-community/eslint-utils@^4.2.0": + version "4.4.0" + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" + integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== + dependencies: + eslint-visitor-keys "^3.3.0" + +"@eslint-community/regexpp@^4.4.0": + version "4.5.1" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.5.1.tgz#cdd35dce4fa1a89a4fd42b1599eb35b3af408884" + integrity sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ== + "@eslint/eslintrc@^1.3.2": version "1.3.2" resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.3.2.tgz#58b69582f3b7271d8fa67fe5251767a5b38ea356" @@ -1373,6 +1385,26 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" +"@eslint/eslintrc@^2.0.3": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.0.3.tgz#4910db5505f4d503f27774bf356e3704818a0331" + integrity sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ== + dependencies: + ajv "^6.12.4" + debug "^4.3.2" + espree "^9.5.2" + globals "^13.19.0" + ignore "^5.2.0" + import-fresh "^3.2.1" + js-yaml "^4.1.0" + minimatch "^3.1.2" + strip-json-comments "^3.1.1" + +"@eslint/js@8.40.0": + version "8.40.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.40.0.tgz#3ba73359e11f5a7bd3e407f70b3528abfae69cec" + integrity sha512-ElyB54bJIhXQYVKjDSvCkPO1iU1tSAeVQJbllWJq1XQSmmA4dgFk8CbiBGpiOPxleE48vDogxCtmMYku4HSVLA== + "@firebase/analytics-compat@0.1.13": version "0.1.13" resolved "https://registry.yarnpkg.com/@firebase/analytics-compat/-/analytics-compat-0.1.13.tgz#61e1d6f9e4d033c3ed9943d91530eb3e0f382f92" @@ -1828,6 +1860,15 @@ debug "^4.1.1" minimatch "^3.0.4" +"@humanwhocodes/config-array@^0.11.8": + version "0.11.8" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.8.tgz#03595ac2075a4dc0f191cc2131de14fbd7d410b9" + integrity sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g== + dependencies: + "@humanwhocodes/object-schema" "^1.2.1" + debug "^4.1.1" + minimatch "^3.0.5" + "@humanwhocodes/gitignore-to-minimatch@^1.0.2": version "1.0.2" resolved "https://registry.yarnpkg.com/@humanwhocodes/gitignore-to-minimatch/-/gitignore-to-minimatch-1.0.2.tgz#316b0a63b91c10e53f242efb4ace5c3b34e8728d" @@ -2314,7 +2355,7 @@ resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== -"@nodelib/fs.walk@^1.2.3": +"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8": version "1.2.8" resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== @@ -2659,10 +2700,6 @@ prompts "^2.4.0" semver "^6.3.0" -"@reactions/component@^2.0.2": - version "2.0.2" - resolved "https://registry.yarnpkg.com/@reactions/component/-/component-2.0.2.tgz#40f8c1c2c37baabe57a0c944edb9310dc1ec6642" - "@rnx-kit/rn-changelog-generator@^0.4.0": version "0.4.0" resolved "https://registry.yarnpkg.com/@rnx-kit/rn-changelog-generator/-/rn-changelog-generator-0.4.0.tgz#637d87bcf8de6e87599930ed88d9375010277660" @@ -2942,7 +2979,7 @@ dependencies: "@types/yargs-parser" "*" -"@typescript-eslint/eslint-plugin@^5.30.0", "@typescript-eslint/eslint-plugin@^5.30.5": +"@typescript-eslint/eslint-plugin@^5.30.0": version "5.37.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.37.0.tgz#5ccdd5d9004120f28fc6e717fb4b5c9bddcfbc04" integrity sha512-Fde6W0IafXktz1UlnhGkrrmnnGpAo1kyX7dnyHHVrmwJOn72Oqm3eYtddrpOwwel2W8PAK9F3pIL5S+lfoM0og== @@ -2957,7 +2994,23 @@ semver "^7.3.7" tsutils "^3.21.0" -"@typescript-eslint/parser@^5.30.0", "@typescript-eslint/parser@^5.30.5": +"@typescript-eslint/eslint-plugin@^5.57.1": + version "5.59.5" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.5.tgz#f156827610a3f8cefc56baeaa93cd4a5f32966b4" + integrity sha512-feA9xbVRWJZor+AnLNAr7A8JRWeZqHUf4T9tlP+TN04b05pFVhO5eN7/O93Y/1OUlLMHKbnJisgDURs/qvtqdg== + dependencies: + "@eslint-community/regexpp" "^4.4.0" + "@typescript-eslint/scope-manager" "5.59.5" + "@typescript-eslint/type-utils" "5.59.5" + "@typescript-eslint/utils" "5.59.5" + debug "^4.3.4" + grapheme-splitter "^1.0.4" + ignore "^5.2.0" + natural-compare-lite "^1.4.0" + semver "^7.3.7" + tsutils "^3.21.0" + +"@typescript-eslint/parser@^5.30.0": version "5.37.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.37.0.tgz#c382077973f3a4ede7453fb14cadcad3970cbf3b" integrity sha512-01VzI/ipYKuaG5PkE5+qyJ6m02fVALmMPY3Qq5BHflDx3y4VobbLdHQkSMg9VPRS4KdNt4oYTMaomFoHonBGAw== @@ -2967,6 +3020,16 @@ "@typescript-eslint/typescript-estree" "5.37.0" debug "^4.3.4" +"@typescript-eslint/parser@^5.57.1": + version "5.59.5" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.59.5.tgz#63064f5eafbdbfb5f9dfbf5c4503cdf949852981" + integrity sha512-NJXQC4MRnF9N9yWqQE2/KLRSOLvrrlZb48NGVfBa+RuPMN6B7ZcK5jZOvhuygv4D64fRKnZI4L4p8+M+rfeQuw== + dependencies: + "@typescript-eslint/scope-manager" "5.59.5" + "@typescript-eslint/types" "5.59.5" + "@typescript-eslint/typescript-estree" "5.59.5" + debug "^4.3.4" + "@typescript-eslint/scope-manager@5.37.0": version "5.37.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.37.0.tgz#044980e4f1516a774a418dafe701a483a6c9f9ca" @@ -2983,6 +3046,14 @@ "@typescript-eslint/types" "5.54.0" "@typescript-eslint/visitor-keys" "5.54.0" +"@typescript-eslint/scope-manager@5.59.5": + version "5.59.5" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.59.5.tgz#33ffc7e8663f42cfaac873de65ebf65d2bce674d" + integrity sha512-jVecWwnkX6ZgutF+DovbBJirZcAxgxC0EOHYt/niMROf8p4PwxxG32Qdhj/iIQQIuOflLjNkxoXyArkcIP7C3A== + dependencies: + "@typescript-eslint/types" "5.59.5" + "@typescript-eslint/visitor-keys" "5.59.5" + "@typescript-eslint/type-utils@5.37.0": version "5.37.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.37.0.tgz#43ed2f567ada49d7e33a6e4b6f9babd060445fe5" @@ -2993,6 +3064,16 @@ debug "^4.3.4" tsutils "^3.21.0" +"@typescript-eslint/type-utils@5.59.5": + version "5.59.5" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.59.5.tgz#485b0e2c5b923460bc2ea6b338c595343f06fc9b" + integrity sha512-4eyhS7oGym67/pSxA2mmNq7X164oqDYNnZCUayBwJZIRVvKpBCMBzFnFxjeoDeShjtO6RQBHBuwybuX3POnDqg== + dependencies: + "@typescript-eslint/typescript-estree" "5.59.5" + "@typescript-eslint/utils" "5.59.5" + debug "^4.3.4" + tsutils "^3.21.0" + "@typescript-eslint/types@5.37.0": version "5.37.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.37.0.tgz#09e4870a5f3af7af3f84e08d792644a87d232261" @@ -3003,6 +3084,11 @@ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.54.0.tgz#7d519df01f50739254d89378e0dcac504cab2740" integrity sha512-nExy+fDCBEgqblasfeE3aQ3NuafBUxZxgxXcYfzYRZFHdVvk5q60KhCSkG0noHgHRo/xQ/BOzURLZAafFpTkmQ== +"@typescript-eslint/types@5.59.5": + version "5.59.5" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.59.5.tgz#e63c5952532306d97c6ea432cee0981f6d2258c7" + integrity sha512-xkfRPHbqSH4Ggx4eHRIO/eGL8XL4Ysb4woL8c87YuAo8Md7AUjyWKa9YMwTL519SyDPrfEgKdewjkxNCVeJW7w== + "@typescript-eslint/typescript-estree@5.37.0": version "5.37.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.37.0.tgz#956dcf5c98363bcb97bdd5463a0a86072ff79355" @@ -3029,6 +3115,19 @@ semver "^7.3.7" tsutils "^3.21.0" +"@typescript-eslint/typescript-estree@5.59.5": + version "5.59.5" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.5.tgz#9b252ce55dd765e972a7a2f99233c439c5101e42" + integrity sha512-+XXdLN2CZLZcD/mO7mQtJMvCkzRfmODbeSKuMY/yXbGkzvA9rJyDY5qDYNoiz2kP/dmyAxXquL2BvLQLJFPQIg== + dependencies: + "@typescript-eslint/types" "5.59.5" + "@typescript-eslint/visitor-keys" "5.59.5" + debug "^4.3.4" + globby "^11.1.0" + is-glob "^4.0.3" + semver "^7.3.7" + tsutils "^3.21.0" + "@typescript-eslint/utils@5.37.0", "@typescript-eslint/utils@^5.10.0", "@typescript-eslint/utils@^5.30.0": version "5.37.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.37.0.tgz#7784cb8e91390c4f90ccaffd24a0cf9874df81b2" @@ -3041,6 +3140,20 @@ eslint-scope "^5.1.1" eslint-utils "^3.0.0" +"@typescript-eslint/utils@5.59.5": + version "5.59.5" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.59.5.tgz#15b3eb619bb223302e60413adb0accd29c32bcae" + integrity sha512-sCEHOiw+RbyTii9c3/qN74hYDPNORb8yWCoPLmB7BIflhplJ65u2PBpdRla12e3SSTJ2erRkPjz7ngLHhUegxA== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@types/json-schema" "^7.0.9" + "@types/semver" "^7.3.12" + "@typescript-eslint/scope-manager" "5.59.5" + "@typescript-eslint/types" "5.59.5" + "@typescript-eslint/typescript-estree" "5.59.5" + eslint-scope "^5.1.1" + semver "^7.3.7" + "@typescript-eslint/utils@^5.47.1": version "5.54.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.54.0.tgz#3db758aae078be7b54b8ea8ea4537ff6cd3fbc21" @@ -3071,6 +3184,14 @@ "@typescript-eslint/types" "5.54.0" eslint-visitor-keys "^3.3.0" +"@typescript-eslint/visitor-keys@5.59.5": + version "5.59.5" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.5.tgz#ba5b8d6791a13cf9fea6716af1e7626434b29b9b" + integrity sha512-qL+Oz+dbeBRTeyJTIy0eniD3uvqU7x+y1QceBismZ41hd4aBSRh8UAw4pZP0+XzLuPZmx4raNMq/I+59W2lXKA== + dependencies: + "@typescript-eslint/types" "5.59.5" + eslint-visitor-keys "^3.3.0" + abab@^2.0.0: version "2.0.6" resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.6.tgz#41b80f2c871d19686216b82309231cfd3cb3d291" @@ -3626,7 +3747,7 @@ balanced-match@^1.0.0: resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= -base64-js@^1.1.2, base64-js@^1.3.1: +base64-js@^1.3.1, base64-js@^1.5.1: version "1.5.1" resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== @@ -4447,10 +4568,10 @@ depd@~1.1.2: resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= -deprecated-react-native-prop-types@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/deprecated-react-native-prop-types/-/deprecated-react-native-prop-types-4.0.0.tgz#544845e32f3220bc676f18c0b846d673399c45cb" - integrity sha512-q0kk77qFPC4adlnZH7cv9lfbHALeaTkl7wT1uNERc+e0Os3KcBKKy1rVliTE8sfey6TP6OPzoIXpr9OPidvvHw== +deprecated-react-native-prop-types@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/deprecated-react-native-prop-types/-/deprecated-react-native-prop-types-4.1.0.tgz#8ed03a64c21b7fbdd2d000957b6838d4f38d2c66" + integrity sha512-WfepZHmRbbdTvhcolb8aOKEvQdcmTMn5tKLbqbXmkBvjFjRVWAYqsXk/DBsV8TZxws8SdGHLuHaJrHSQUPRdfw== dependencies: "@react-native/normalize-colors" "*" invariant "*" @@ -4883,6 +5004,14 @@ eslint-scope@^7.1.1: esrecurse "^4.3.0" estraverse "^5.2.0" +eslint-scope@^7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.0.tgz#f21ebdafda02352f103634b96dd47d9f81ca117b" + integrity sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw== + dependencies: + esrecurse "^4.3.0" + estraverse "^5.2.0" + eslint-utils@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672" @@ -4900,7 +5029,12 @@ eslint-visitor-keys@^3.3.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826" integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== -eslint@^8.17.0, eslint@^8.19.0: +eslint-visitor-keys@^3.4.1: + version "3.4.1" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz#c22c48f48942d08ca824cc526211ae400478a994" + integrity sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA== + +eslint@^8.17.0: version "8.23.1" resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.23.1.tgz#cfd7b3f7fdd07db8d16b4ac0516a29c8d8dca5dc" integrity sha512-w7C1IXCc6fNqjpuYd0yPlcTKKmHlHHktRkzmBPZ+7cvNBQuiNjx0xaMTjAJGCafJhQkrFJooREv0CtrVzmHwqg== @@ -4945,6 +5079,52 @@ eslint@^8.17.0, eslint@^8.19.0: strip-json-comments "^3.1.0" text-table "^0.2.0" +eslint@^8.19.0: + version "8.40.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.40.0.tgz#a564cd0099f38542c4e9a2f630fa45bf33bc42a4" + integrity sha512-bvR+TsP9EHL3TqNtj9sCNJVAFK3fBN8Q7g5waghxyRsPLIMwL73XSKnZFK0hk/O2ANC+iAoq6PWMQ+IfBAJIiQ== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@eslint-community/regexpp" "^4.4.0" + "@eslint/eslintrc" "^2.0.3" + "@eslint/js" "8.40.0" + "@humanwhocodes/config-array" "^0.11.8" + "@humanwhocodes/module-importer" "^1.0.1" + "@nodelib/fs.walk" "^1.2.8" + ajv "^6.10.0" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.3.2" + doctrine "^3.0.0" + escape-string-regexp "^4.0.0" + eslint-scope "^7.2.0" + eslint-visitor-keys "^3.4.1" + espree "^9.5.2" + esquery "^1.4.2" + esutils "^2.0.2" + fast-deep-equal "^3.1.3" + file-entry-cache "^6.0.1" + find-up "^5.0.0" + glob-parent "^6.0.2" + globals "^13.19.0" + grapheme-splitter "^1.0.4" + ignore "^5.2.0" + import-fresh "^3.0.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + is-path-inside "^3.0.3" + js-sdsl "^4.1.4" + js-yaml "^4.1.0" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.4.1" + lodash.merge "^4.6.2" + minimatch "^3.1.2" + natural-compare "^1.4.0" + optionator "^0.9.1" + strip-ansi "^6.0.1" + strip-json-comments "^3.1.0" + text-table "^0.2.0" + espree@^9.4.0: version "9.4.0" resolved "https://registry.yarnpkg.com/espree/-/espree-9.4.0.tgz#cd4bc3d6e9336c433265fc0aa016fc1aaf182f8a" @@ -4954,6 +5134,15 @@ espree@^9.4.0: acorn-jsx "^5.3.2" eslint-visitor-keys "^3.3.0" +espree@^9.5.2: + version "9.5.2" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.5.2.tgz#e994e7dc33a082a7a82dceaf12883a829353215b" + integrity sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw== + dependencies: + acorn "^8.8.0" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^3.4.1" + esprima@^4.0.0, esprima@^4.0.1, esprima@~4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" @@ -4966,6 +5155,13 @@ esquery@^1.4.0: dependencies: estraverse "^5.1.0" +esquery@^1.4.2: + version "1.5.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.5.0.tgz#6ce17738de8577694edd7361c57182ac8cb0db0b" + integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg== + dependencies: + estraverse "^5.1.0" + esrecurse@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" @@ -5332,15 +5528,15 @@ flatted@^3.1.0: resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.2.tgz#64bfed5cb68fe3ca78b3eb214ad97b63bedce561" integrity sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA== -flow-bin@^0.204.0: - version "0.204.0" - resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.204.0.tgz#0293e22f5ed69dfc46299c4c4787d03e776ae0c2" - integrity sha512-yXIbRjRTcE7IXElwhwbl80sXQDlbB6MPy8mYUXpXp12VsAsE+CeF1yNo6tMDoz6KJTi3+jLws/zkenVOO09TfA== +flow-bin@^0.205.1: + version "0.205.1" + resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.205.1.tgz#5faf24e60df8d36f4deafef20e44863c5b295315" + integrity sha512-pGQ/ZFr9hnbhRmc+K3K1Ui9BwDivlesNEd2mZbm5pCnxEUvbbj9nXHlTD4s4qO0k+LBKYLMZzQwBVYyRUE380g== -flow-enums-runtime@^0.0.5: - version "0.0.5" - resolved "https://registry.yarnpkg.com/flow-enums-runtime/-/flow-enums-runtime-0.0.5.tgz#95884bfcc82edaf27eef7e1dd09732331cfbafbc" - integrity sha512-PSZF9ZuaZD03sT9YaIs0FrGJ7lSUw7rHZIex+73UYVXg46eL/wxN5PaVcPJFudE2cJu5f0fezitV5aBkLHPUOQ== +flow-enums-runtime@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/flow-enums-runtime/-/flow-enums-runtime-0.0.6.tgz#5bb0cd1b0a3e471330f4d109039b7eba5cb3e787" + integrity sha512-3PYnM29RFXwvAN6Pc/scUfkI7RwhQ/xqyLUyPNlXUp9S40zI8nup9tUSrTLSVnWGBN38FNiGWbwZOB6uR4OGdw== flow-parser@0.*, flow-parser@^0.185.0: version "0.185.0" @@ -5594,7 +5790,7 @@ glob-parent@^5.1.2, glob-parent@~5.1.2: dependencies: is-glob "^4.0.1" -glob-parent@^6.0.1: +glob-parent@^6.0.1, glob-parent@^6.0.2: version "6.0.2" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== @@ -5625,6 +5821,13 @@ globals@^13.15.0: dependencies: type-fest "^0.20.2" +globals@^13.19.0: + version "13.20.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.20.0.tgz#ea276a1e508ffd4f1612888f9d1bad1e2717bf82" + integrity sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ== + dependencies: + type-fest "^0.20.2" + globalthis@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.3.tgz#5852882a52b80dc301b0660273e1ed082f0b6ccf" @@ -6265,6 +6468,11 @@ is-number@^7.0.0: resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== +is-path-inside@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" + integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== + is-plain-object@^2.0.3, is-plain-object@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" @@ -8127,7 +8335,7 @@ mimic-response@^3.1.0: resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9" integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ== -minimatch@^3.0.2, minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2: +minimatch@^3.0.2, minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== @@ -8226,6 +8434,11 @@ nanomatch@^1.2.9: snapdragon "^0.8.1" to-regex "^3.0.1" +natural-compare-lite@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz#17b09581988979fddafe0201e931ba933c96cbb4" + integrity sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g== + natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" @@ -9008,10 +9221,10 @@ range-parser@~1.2.0: resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" integrity sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4= -react-devtools-core@^4.27.2: - version "4.27.2" - resolved "https://registry.yarnpkg.com/react-devtools-core/-/react-devtools-core-4.27.2.tgz#d20fc57e258c656eedabafc2c851d38b33583148" - integrity sha512-8SzmIkpO87alD7Xr6gWIEa1jHkMjawOZ+6egjazlnjB4UUcbnzGDf/vBJ4BzGuWWEM+pzrxuzsPpcMqlQkYK2g== +react-devtools-core@^4.27.7: + version "4.27.7" + resolved "https://registry.yarnpkg.com/react-devtools-core/-/react-devtools-core-4.27.7.tgz#458a6541483078d60a036c75bf88f54c478086ec" + integrity sha512-12N0HrhCPbD76Z7SkyJdGdXdPGouUsgV6tlEsbSpAnLDO06tjXZP+irht4wPdYwJAJRQ85DxL48eQoz7UmrSuQ== dependencies: shell-quote "^1.6.1" ws "^7" @@ -9479,6 +9692,13 @@ sax@^1.2.4: resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== +scheduler@0.24.0-canary-efb381bbf-20230505: + version "0.24.0-canary-efb381bbf-20230505" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.24.0-canary-efb381bbf-20230505.tgz#5dddc60e29f91cd7f8b983d7ce4a99c2202d178f" + integrity sha512-ABvovCDe/k9IluqSh4/ISoq8tIJnW8euVAWYt5j/bg6dRnqwQwiGO1F/V4AyK96NGF/FB04FhOUDuWj8IKfABA== + dependencies: + loose-envify "^1.1.0" + scheduler@^0.23.0: version "0.23.0" resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.0.tgz#ba8041afc3d30eb206a487b6b384002e4e61fdfe" @@ -10390,10 +10610,10 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA== -typescript@4.1.3: - version "4.1.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.1.3.tgz#519d582bd94cba0cf8934c7d8e8467e473f53bb7" - integrity sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg== +typescript@5.0.4: + version "5.0.4" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.0.4.tgz#b217fd20119bd61a94d4011274e0ab369058da3b" + integrity sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw== uglify-es@^3.1.9: version "3.3.9"