From 3967635632831b94293f0aff1daf5d2758e062fa Mon Sep 17 00:00:00 2001 From: Christoph Nakazawa Date: Fri, 21 Aug 2020 02:52:03 -0700 Subject: [PATCH 0001/1238] Add a proper "monorepo" setup for React Native Summary: This adds all the packages we use to the workspace in open source, which means we can change our publish scripts to also publish the packages from the repo every time we publish the main repo. I'll work with somebody from the community on that part. Note: We do not use `eslint-config-react-native-community` internally and it pulls in a lot of packages we don't need. It is part of the React Native repo because it is used in the RN app template but we may want to choose to move it out into a separate repo at some point. Changelog: [Internal] Reviewed By: motiz88 Differential Revision: D23208695 fbshipit-source-id: 02d401721dfdc8bbb2305f8ac3381f1e98c18f1d --- package.json | 1 + packages/react-native-codegen/BUCK | 1 - .../buck_tests/generate-tests.sh | 2 +- .../src/cli/combine/combine_js_to_schema.sh | 2 +- .../src/cli/verify_with_old_codegen.sh | 2 +- packages/react-native-codegen/yarn.lock | 1577 ----------------- packages/rn-tester/package.json | 5 +- repo-config/package.json | 2 +- yarn.lock | 23 +- 9 files changed, 13 insertions(+), 1602 deletions(-) delete mode 100644 packages/react-native-codegen/yarn.lock diff --git a/package.json b/package.json index 56762e5255dec5..05eb27d84fbb5c 100644 --- a/package.json +++ b/package.json @@ -78,6 +78,7 @@ "test-ios": "./scripts/objc-test.sh test" }, "workspaces": [ + "packages/!(eslint-config-react-native-community)", "repo-config" ], "peerDependencies": { diff --git a/packages/react-native-codegen/BUCK b/packages/react-native-codegen/BUCK index 434b982c639970..ca38d2bb4dc7ef 100644 --- a/packages/react-native-codegen/BUCK +++ b/packages/react-native-codegen/BUCK @@ -47,7 +47,6 @@ fb_native.sh_binary( "buck_tests/generate-tests.js", "package.json", "//xplat/js:setup_env", - "yarn.lock", ], visibility = ["PUBLIC"], ) diff --git a/packages/react-native-codegen/buck_tests/generate-tests.sh b/packages/react-native-codegen/buck_tests/generate-tests.sh index 9af175095988f8..5a45850d25ef3a 100755 --- a/packages/react-native-codegen/buck_tests/generate-tests.sh +++ b/packages/react-native-codegen/buck_tests/generate-tests.sh @@ -12,7 +12,7 @@ THIS_DIR=$(cd -P "$(dirname "$(readlink "${BASH_SOURCE[0]}" || echo "${BASH_SOUR # shellcheck source=xplat/js/env-utils/setup_env_vars.sh source "$THIS_DIR/../../../../env-utils/setup_env_vars.sh" -pushd "$THIS_DIR/.." >/dev/null +pushd "$JS_DIR" >/dev/null "$INSTALL_NODE_MODULES" popd >/dev/null diff --git a/packages/react-native-codegen/src/cli/combine/combine_js_to_schema.sh b/packages/react-native-codegen/src/cli/combine/combine_js_to_schema.sh index 395152a3acbca6..6b6f30ce92dc3b 100755 --- a/packages/react-native-codegen/src/cli/combine/combine_js_to_schema.sh +++ b/packages/react-native-codegen/src/cli/combine/combine_js_to_schema.sh @@ -12,7 +12,7 @@ THIS_DIR=$(cd -P "$(dirname "$(readlink "${BASH_SOURCE[0]}" || echo "${BASH_SOUR # shellcheck source=xplat/js/env-utils/setup_env_vars.sh source "$THIS_DIR/../../../../../../env-utils/setup_env_vars.sh" -pushd "$THIS_DIR/../../.." >/dev/null +pushd "$JS_DIR" >/dev/null "$INSTALL_NODE_MODULES" popd >/dev/null diff --git a/packages/react-native-codegen/src/cli/verify_with_old_codegen.sh b/packages/react-native-codegen/src/cli/verify_with_old_codegen.sh index 40812dabd259dc..7399c20dcb6294 100755 --- a/packages/react-native-codegen/src/cli/verify_with_old_codegen.sh +++ b/packages/react-native-codegen/src/cli/verify_with_old_codegen.sh @@ -12,7 +12,7 @@ THIS_DIR=$(cd -P "$(dirname "$(readlink "${BASH_SOURCE[0]}" || echo "${BASH_SOUR # shellcheck source=xplat/js/env-utils/setup_env_vars.sh source "$THIS_DIR/../../../../../env-utils/setup_env_vars.sh" -pushd "$THIS_DIR/../.." >/dev/null +pushd "$JS_DIR" >/dev/null "$INSTALL_NODE_MODULES" popd >/dev/null diff --git a/packages/react-native-codegen/yarn.lock b/packages/react-native-codegen/yarn.lock deleted file mode 100644 index cdbe38b80052d5..00000000000000 --- a/packages/react-native-codegen/yarn.lock +++ /dev/null @@ -1,1577 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@babel/code-frame@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.10.4.tgz#168da1a36e90da68ae8d49c0f1b48c7c6249213a" - integrity sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg== - dependencies: - "@babel/highlight" "^7.10.4" - -"@babel/core@^7.0.0", "@babel/core@^7.1.6": - version "7.11.1" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.11.1.tgz#2c55b604e73a40dc21b0e52650b11c65cf276643" - integrity sha512-XqF7F6FWQdKGGWAzGELL+aCO1p+lRY5Tj5/tbT3St1G8NaH70jhhDIKknIZaDans0OQBG5wRAldROLHSt44BgQ== - dependencies: - "@babel/code-frame" "^7.10.4" - "@babel/generator" "^7.11.0" - "@babel/helper-module-transforms" "^7.11.0" - "@babel/helpers" "^7.10.4" - "@babel/parser" "^7.11.1" - "@babel/template" "^7.10.4" - "@babel/traverse" "^7.11.0" - "@babel/types" "^7.11.0" - convert-source-map "^1.7.0" - debug "^4.1.0" - gensync "^1.0.0-beta.1" - json5 "^2.1.2" - lodash "^4.17.19" - resolve "^1.3.2" - semver "^5.4.1" - source-map "^0.5.0" - -"@babel/generator@^7.11.0": - version "7.11.0" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.11.0.tgz#4b90c78d8c12825024568cbe83ee6c9af193585c" - integrity sha512-fEm3Uzw7Mc9Xi//qU20cBKatTfs2aOtKqmvy/Vm7RkJEGFQ4xc9myCfbXxqK//ZS8MR/ciOHw6meGASJuKmDfQ== - dependencies: - "@babel/types" "^7.11.0" - jsesc "^2.5.1" - source-map "^0.5.0" - -"@babel/helper-annotate-as-pure@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.10.4.tgz#5bf0d495a3f757ac3bda48b5bf3b3ba309c72ba3" - integrity sha512-XQlqKQP4vXFB7BN8fEEerrmYvHp3fK/rBkRFz9jaJbzK0B1DSfej9Kc7ZzE8Z/OnId1jpJdNAZ3BFQjWG68rcA== - dependencies: - "@babel/types" "^7.10.4" - -"@babel/helper-create-class-features-plugin@^7.2.1": - version "7.2.1" - resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.2.1.tgz#f6e8027291669ef64433220dc8327531233f1161" - integrity sha512-EsEP7XLFmcJHjcuFYBxYD1FkP0irC8C9fsrt2tX/jrAi/eTnFI6DOPgVFb+WREeg1GboF+Ib+nCHbGBodyAXSg== - dependencies: - "@babel/helper-function-name" "^7.1.0" - "@babel/helper-member-expression-to-functions" "^7.0.0" - "@babel/helper-optimise-call-expression" "^7.0.0" - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-replace-supers" "^7.1.0" - -"@babel/helper-function-name@^7.1.0", "@babel/helper-function-name@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz#d2d3b20c59ad8c47112fa7d2a94bc09d5ef82f1a" - integrity sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ== - dependencies: - "@babel/helper-get-function-arity" "^7.10.4" - "@babel/template" "^7.10.4" - "@babel/types" "^7.10.4" - -"@babel/helper-get-function-arity@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz#98c1cbea0e2332f33f9a4661b8ce1505b2c19ba2" - integrity sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A== - dependencies: - "@babel/types" "^7.10.4" - -"@babel/helper-member-expression-to-functions@^7.0.0", "@babel/helper-member-expression-to-functions@^7.10.4": - version "7.11.0" - resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.11.0.tgz#ae69c83d84ee82f4b42f96e2a09410935a8f26df" - integrity sha512-JbFlKHFntRV5qKw3YC0CvQnDZ4XMwgzzBbld7Ly4Mj4cbFy3KywcR8NtNctRToMWJOVvLINJv525Gd6wwVEx/Q== - dependencies: - "@babel/types" "^7.11.0" - -"@babel/helper-module-imports@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.10.4.tgz#4c5c54be04bd31670a7382797d75b9fa2e5b5620" - integrity sha512-nEQJHqYavI217oD9+s5MUBzk6x1IlvoS9WTPfgG43CbMEeStE0v+r+TucWdx8KFGowPGvyOkDT9+7DHedIDnVw== - dependencies: - "@babel/types" "^7.10.4" - -"@babel/helper-module-transforms@^7.10.4", "@babel/helper-module-transforms@^7.11.0": - version "7.11.0" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.11.0.tgz#b16f250229e47211abdd84b34b64737c2ab2d359" - integrity sha512-02EVu8COMuTRO1TAzdMtpBPbe6aQ1w/8fePD2YgQmxZU4gpNWaL9gK3Jp7dxlkUlUCJOTaSeA+Hrm1BRQwqIhg== - dependencies: - "@babel/helper-module-imports" "^7.10.4" - "@babel/helper-replace-supers" "^7.10.4" - "@babel/helper-simple-access" "^7.10.4" - "@babel/helper-split-export-declaration" "^7.11.0" - "@babel/template" "^7.10.4" - "@babel/types" "^7.11.0" - lodash "^4.17.19" - -"@babel/helper-optimise-call-expression@^7.0.0", "@babel/helper-optimise-call-expression@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.4.tgz#50dc96413d594f995a77905905b05893cd779673" - integrity sha512-n3UGKY4VXwXThEiKrgRAoVPBMqeoPgHVqiHZOanAJCG9nQUL2pLRQirUzl0ioKclHGpGqRgIOkgcIJaIWLpygg== - dependencies: - "@babel/types" "^7.10.4" - -"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.8.0": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz#2f75a831269d4f677de49986dff59927533cf375" - integrity sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg== - -"@babel/helper-remap-async-to-generator@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.10.4.tgz#fce8bea4e9690bbe923056ded21e54b4e8b68ed5" - integrity sha512-86Lsr6NNw3qTNl+TBcF1oRZMaVzJtbWTyTko+CQL/tvNvcGYEFKbLXDPxtW0HKk3McNOk4KzY55itGWCAGK5tg== - dependencies: - "@babel/helper-annotate-as-pure" "^7.10.4" - "@babel/helper-wrap-function" "^7.10.4" - "@babel/template" "^7.10.4" - "@babel/traverse" "^7.10.4" - "@babel/types" "^7.10.4" - -"@babel/helper-replace-supers@^7.1.0", "@babel/helper-replace-supers@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.10.4.tgz#d585cd9388ea06e6031e4cd44b6713cbead9e6cf" - integrity sha512-sPxZfFXocEymYTdVK1UNmFPBN+Hv5mJkLPsYWwGBxZAxaWfFu+xqp7b6qWD0yjNuNL2VKc6L5M18tOXUP7NU0A== - dependencies: - "@babel/helper-member-expression-to-functions" "^7.10.4" - "@babel/helper-optimise-call-expression" "^7.10.4" - "@babel/traverse" "^7.10.4" - "@babel/types" "^7.10.4" - -"@babel/helper-simple-access@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.10.4.tgz#0f5ccda2945277a2a7a2d3a821e15395edcf3461" - integrity sha512-0fMy72ej/VEvF8ULmX6yb5MtHG4uH4Dbd6I/aHDb/JVg0bbivwt9Wg+h3uMvX+QSFtwr5MeItvazbrc4jtRAXw== - dependencies: - "@babel/template" "^7.10.4" - "@babel/types" "^7.10.4" - -"@babel/helper-skip-transparent-expression-wrappers@^7.11.0": - version "7.11.0" - resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.11.0.tgz#eec162f112c2f58d3af0af125e3bb57665146729" - integrity sha512-0XIdiQln4Elglgjbwo9wuJpL/K7AGCY26kmEt0+pRP0TAj4jjyNq1MjoRvikrTVqKcx4Gysxt4cXvVFXP/JO2Q== - dependencies: - "@babel/types" "^7.11.0" - -"@babel/helper-split-export-declaration@^7.11.0": - version "7.11.0" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.11.0.tgz#f8a491244acf6a676158ac42072911ba83ad099f" - integrity sha512-74Vejvp6mHkGE+m+k5vHY93FX2cAtrw1zXrZXRlG4l410Nm9PxfEiVTn1PjDPV5SnmieiueY4AFg2xqhNFuuZg== - dependencies: - "@babel/types" "^7.11.0" - -"@babel/helper-validator-identifier@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz#a78c7a7251e01f616512d31b10adcf52ada5e0d2" - integrity sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw== - -"@babel/helper-wrap-function@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.10.4.tgz#8a6f701eab0ff39f765b5a1cfef409990e624b87" - integrity sha512-6py45WvEF0MhiLrdxtRjKjufwLL1/ob2qDJgg5JgNdojBAZSAKnAjkyOCNug6n+OBl4VW76XjvgSFTdaMcW0Ug== - dependencies: - "@babel/helper-function-name" "^7.10.4" - "@babel/template" "^7.10.4" - "@babel/traverse" "^7.10.4" - "@babel/types" "^7.10.4" - -"@babel/helpers@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.10.4.tgz#2abeb0d721aff7c0a97376b9e1f6f65d7a475044" - integrity sha512-L2gX/XeUONeEbI78dXSrJzGdz4GQ+ZTA/aazfUsFaWjSe95kiCuOZ5HsXvkiw3iwF+mFHSRUfJU8t6YavocdXA== - dependencies: - "@babel/template" "^7.10.4" - "@babel/traverse" "^7.10.4" - "@babel/types" "^7.10.4" - -"@babel/highlight@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.10.4.tgz#7d1bdfd65753538fabe6c38596cdb76d9ac60143" - integrity sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA== - dependencies: - "@babel/helper-validator-identifier" "^7.10.4" - chalk "^2.0.0" - js-tokens "^4.0.0" - -"@babel/parser@^7.1.6", "@babel/parser@^7.10.4", "@babel/parser@^7.11.0", "@babel/parser@^7.11.1": - version "7.11.3" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.11.3.tgz#9e1eae46738bcd08e23e867bab43e7b95299a8f9" - integrity sha512-REo8xv7+sDxkKvoxEywIdsNFiZLybwdI7hcT5uEPyQrSMB4YQ973BfC9OOrD/81MaIjh6UxdulIQXkjmiH3PcA== - -"@babel/plugin-proposal-class-properties@^7.1.0": - version "7.2.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.2.1.tgz#c734a53e0a1ec40fe5c22ee5069d26da3b187d05" - integrity sha512-/4FKFChkQ2Jgb8lBDsvFX496YTi7UWTetVgS8oJUpX1e/DlaoeEK57At27ug8Hu2zI2g8bzkJ+8k9qrHZRPGPA== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.2.1" - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-proposal-nullish-coalescing-operator@^7.0.0", "@babel/plugin-proposal-nullish-coalescing-operator@^7.1.0": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.10.4.tgz#02a7e961fc32e6d5b2db0649e01bf80ddee7e04a" - integrity sha512-wq5n1M3ZUlHl9sqT2ok1T2/MTt6AXE0e1Lz4WzWBr95LsAZ5qDXe4KnFuauYyEyLiohvXFMdbsOTMyLZs91Zlw== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.0" - -"@babel/plugin-proposal-object-rest-spread@^7.0.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.2.0.tgz#88f5fec3e7ad019014c97f7ee3c992f0adbf7fb8" - integrity sha512-1L5mWLSvR76XYUQJXkd/EEQgjq8HHRP6lQuZTTg0VA4tTGPpGemmCdAfQIz1rzEuWAm+ecP8PyyEm30jC1eQCg== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-syntax-object-rest-spread" "^7.2.0" - -"@babel/plugin-proposal-optional-chaining@^7.0.0", "@babel/plugin-proposal-optional-chaining@^7.1.0": - version "7.11.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.11.0.tgz#de5866d0646f6afdaab8a566382fe3a221755076" - integrity sha512-v9fZIu3Y8562RRwhm1BbMRxtqZNFmFA2EG+pT2diuU8PT3H6T/KXoZ54KgYisfOFZHV6PfvAiBIZ9Rcz+/JCxA== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - "@babel/helper-skip-transparent-expression-wrappers" "^7.11.0" - "@babel/plugin-syntax-optional-chaining" "^7.8.0" - -"@babel/plugin-syntax-dynamic-import@^7.0.0": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" - integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-flow@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.2.0.tgz#a765f061f803bc48f240c26f8747faf97c26bf7c" - integrity sha512-r6YMuZDWLtLlu0kqIim5o/3TNRAlWb073HwT3e2nKf9I8IIvOggPrnILYPsrrKilmn/mYEMCf/Z07w3yQJF6dg== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.0": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" - integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-object-rest-spread@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.2.0.tgz#3b7a3e733510c57e820b9142a6579ac8b0dfad2e" - integrity sha512-t0JKGgqk2We+9may3t0xDdmneaXmyxq0xieYcKHxIsrJO64n1OiMWNUtc5gQK1PA0NpdCRrtZp4z+IUaKugrSA== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-syntax-optional-chaining@^7.8.0": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" - integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-typescript@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.2.0.tgz#55d240536bd314dcbbec70fd949c5cabaed1de29" - integrity sha512-WhKr6yu6yGpGcNMVgIBuI9MkredpVc7Y3YR4UzEZmDztHoL6wV56YBHLhWnjO1EvId1B32HrD3DRFc+zSoKI1g== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-transform-async-to-generator@^7.0.0": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.10.4.tgz#41a5017e49eb6f3cda9392a51eef29405b245a37" - integrity sha512-F6nREOan7J5UXTLsDsZG3DXmZSVofr2tGNwfdrVwkDWHfQckbQXnXSPfD7iO+c/2HGqycwyLST3DnZ16n+cBJQ== - dependencies: - "@babel/helper-module-imports" "^7.10.4" - "@babel/helper-plugin-utils" "^7.10.4" - "@babel/helper-remap-async-to-generator" "^7.10.4" - -"@babel/plugin-transform-destructuring@^7.0.0": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.10.4.tgz#70ddd2b3d1bea83d01509e9bb25ddb3a74fc85e5" - integrity sha512-+WmfvyfsyF603iPa6825mq6Qrb7uLjTOsa3XOFzlYcYDHSS4QmpOWOL0NNBY5qMbvrcf3tq0Cw+v4lxswOBpgA== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-transform-flow-strip-types@^7.0.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.2.0.tgz#db6180d098caaabdd609a8da3800f5204e66b69b" - integrity sha512-xhQp0lyXA5vk8z1kJitdMozQYEWfo4MgC6neNXrb5euqHiTIGhj5ZWfFPkVESInQSk9WZz1bbNmIRz6zKfWGVA== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-syntax-flow" "^7.2.0" - -"@babel/plugin-transform-modules-commonjs@^7.1.0": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.10.4.tgz#66667c3eeda1ebf7896d41f1f16b17105a2fbca0" - integrity sha512-Xj7Uq5o80HDLlW64rVfDBhao6OX89HKUmb+9vWYaLXBZOma4gA6tw4Ni1O5qVDoZWUV0fxMYA0aYzOawz0l+1w== - dependencies: - "@babel/helper-module-transforms" "^7.10.4" - "@babel/helper-plugin-utils" "^7.10.4" - "@babel/helper-simple-access" "^7.10.4" - babel-plugin-dynamic-import-node "^2.3.3" - -"@babel/plugin-transform-typescript@^7.1.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.2.0.tgz#bce7c06300434de6a860ae8acf6a442ef74a99d1" - integrity sha512-EnI7i2/gJ7ZNr2MuyvN2Hu+BHJENlxWte5XygPvfj/MbvtOkWor9zcnHpMMQL2YYaaCcqtIvJUyJ7QVfoGs7ew== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-syntax-typescript" "^7.2.0" - -"@babel/preset-flow@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/preset-flow/-/preset-flow-7.0.0.tgz#afd764835d9535ec63d8c7d4caf1c06457263da2" - integrity sha512-bJOHrYOPqJZCkPVbG1Lot2r5OSsB+iUOaxiHdlOeB1yPWS6evswVHwvkDLZ54WTaTRIk89ds0iHmGZSnxlPejQ== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-transform-flow-strip-types" "^7.0.0" - -"@babel/preset-typescript@^7.1.0": - version "7.1.0" - resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.1.0.tgz#49ad6e2084ff0bfb5f1f7fb3b5e76c434d442c7f" - integrity sha512-LYveByuF9AOM8WrsNne5+N79k1YxjNB6gmpCQsnuSBAcV8QUeB+ZUxQzL7Rz7HksPbahymKkq2qBR+o36ggFZA== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-transform-typescript" "^7.1.0" - -"@babel/register@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/register/-/register-7.0.0.tgz#fa634bae1bfa429f60615b754fc1f1d745edd827" - integrity sha512-f/+CRmaCe7rVEvcvPvxeA8j5aJhHC3aJie7YuqcMDhUOuyWLA7J/aNrTaHIzoWPEhpHA54mec4Mm8fv8KBlv3g== - dependencies: - core-js "^2.5.7" - find-cache-dir "^1.0.0" - home-or-tmp "^3.0.0" - lodash "^4.17.10" - mkdirp "^0.5.1" - pirates "^4.0.0" - source-map-support "^0.5.9" - -"@babel/template@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.10.4.tgz#3251996c4200ebc71d1a8fc405fba940f36ba278" - integrity sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA== - dependencies: - "@babel/code-frame" "^7.10.4" - "@babel/parser" "^7.10.4" - "@babel/types" "^7.10.4" - -"@babel/traverse@^7.10.4", "@babel/traverse@^7.11.0": - version "7.11.0" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.11.0.tgz#9b996ce1b98f53f7c3e4175115605d56ed07dd24" - integrity sha512-ZB2V+LskoWKNpMq6E5UUCrjtDUh5IOTAyIl0dTjIEoXum/iKWkoIEKIRDnUucO6f+2FzNkE0oD4RLKoPIufDtg== - dependencies: - "@babel/code-frame" "^7.10.4" - "@babel/generator" "^7.11.0" - "@babel/helper-function-name" "^7.10.4" - "@babel/helper-split-export-declaration" "^7.11.0" - "@babel/parser" "^7.11.0" - "@babel/types" "^7.11.0" - debug "^4.1.0" - globals "^11.1.0" - lodash "^4.17.19" - -"@babel/types@^7.10.4", "@babel/types@^7.11.0": - version "7.11.0" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.11.0.tgz#2ae6bf1ba9ae8c3c43824e5861269871b206e90d" - integrity sha512-O53yME4ZZI0jO1EVGtF1ePGl0LHirG4P1ibcD80XyzZcKhcMFeCXmh4Xb1ifGBIV233Qg12x4rBfQgA+tmOukA== - dependencies: - "@babel/helper-validator-identifier" "^7.10.4" - lodash "^4.17.19" - to-fast-properties "^2.0.0" - -"@types/color-name@^1.1.1": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0" - integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ== - -ansi-styles@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" - integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== - dependencies: - color-convert "^1.9.0" - -ansi-styles@^4.1.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.2.1.tgz#90ae75c424d008d2624c5bf29ead3177ebfcf359" - integrity sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA== - dependencies: - "@types/color-name" "^1.1.1" - color-convert "^2.0.1" - -arr-diff@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" - integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= - -arr-flatten@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" - integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== - -arr-union@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" - integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= - -array-unique@^0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" - integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= - -assign-symbols@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" - integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= - -ast-types@0.13.3: - version "0.13.3" - resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.13.3.tgz#50da3f28d17bdbc7969a3a2d83a0e4a72ae755a7" - integrity sha512-XTZ7xGML849LkQP86sWdQzfhwbt3YwIO6MqbX9mUNYY98VKaaVZP7YNNm70IpwecbkkxmfC5IYAzOQ/2p29zRA== - -atob@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" - integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== - -babel-core@^7.0.0-bridge.0: - version "7.0.0-bridge.0" - resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-7.0.0-bridge.0.tgz#95a492ddd90f9b4e9a4a1da14eb335b87b634ece" - integrity sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg== - -babel-plugin-dynamic-import-node@^2.3.3: - version "2.3.3" - resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz#84fda19c976ec5c6defef57f9427b3def66e17a3" - integrity sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ== - dependencies: - object.assign "^4.1.0" - -balanced-match@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" - integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= - -base@^0.11.1: - version "0.11.2" - resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" - integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== - dependencies: - cache-base "^1.0.1" - class-utils "^0.3.5" - component-emitter "^1.2.1" - define-property "^1.0.0" - isobject "^3.0.1" - mixin-deep "^1.2.0" - pascalcase "^0.1.1" - -brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== - dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" - -braces@^2.3.1: - version "2.3.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" - integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== - dependencies: - arr-flatten "^1.1.0" - array-unique "^0.3.2" - extend-shallow "^2.0.1" - fill-range "^4.0.0" - isobject "^3.0.1" - repeat-element "^1.1.2" - snapdragon "^0.8.1" - snapdragon-node "^2.0.1" - split-string "^3.0.2" - to-regex "^3.0.1" - -braces@^3.0.1: - version "3.0.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" - integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== - dependencies: - fill-range "^7.0.1" - -buffer-from@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" - integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== - -cache-base@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" - integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== - dependencies: - collection-visit "^1.0.0" - component-emitter "^1.2.1" - get-value "^2.0.6" - has-value "^1.0.0" - isobject "^3.0.1" - set-value "^2.0.0" - to-object-path "^0.3.0" - union-value "^1.0.0" - unset-value "^1.0.0" - -chalk@^2.0.0: - version "2.4.1" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e" - integrity sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ== - dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" - -chalk@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.0.tgz#4e14870a618d9e2edd97dd8345fd9d9dc315646a" - integrity sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - -class-utils@^0.3.5: - version "0.3.6" - resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" - integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== - dependencies: - arr-union "^3.1.0" - define-property "^0.2.5" - isobject "^3.0.0" - static-extend "^0.1.1" - -collection-visit@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" - integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA= - dependencies: - map-visit "^1.0.0" - object-visit "^1.0.0" - -color-convert@^1.9.0: - version "1.9.3" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" - integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== - dependencies: - color-name "1.1.3" - -color-convert@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" - integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== - dependencies: - color-name "~1.1.4" - -color-name@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" - integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= - -color-name@~1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - -colors@^1.1.2: - version "1.3.2" - resolved "https://registry.yarnpkg.com/colors/-/colors-1.3.2.tgz#2df8ff573dfbf255af562f8ce7181d6b971a359b" - integrity sha512-rhP0JSBGYvpcNQj4s5AdShMeE5ahMop96cTeDl/v9qQQm2fYClE2QXZRi8wLzc+GmXSxdIqqbOIAhyObEXDbfQ== - -commondir@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" - integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= - -component-emitter@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" - integrity sha1-E3kY1teCg/ffemt8WmPhQOaUJeY= - -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= - -convert-source-map@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442" - integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA== - dependencies: - safe-buffer "~5.1.1" - -copy-descriptor@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" - integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= - -core-js@^2.5.7: - version "2.6.0" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.0.tgz#1e30793e9ee5782b307e37ffa22da0eacddd84d4" - integrity sha512-kLRC6ncVpuEW/1kwrOXYX6KQASCVtrh1gQr/UiaVgFlf9WE5Vp+lNe5+h3LuMr5PAucWnnEXwH0nQHRH/gpGtw== - -debug@^2.2.0, debug@^2.3.3: - version "2.6.9" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" - integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== - dependencies: - ms "2.0.0" - -debug@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.0.tgz#373687bffa678b38b1cd91f861b63850035ddc87" - integrity sha512-heNPJUJIqC+xB6ayLAMHaIrmN9HKa7aQO8MGqKpvCA+uJYVcvR6l5kgdrhRuwPFHU7P5/A1w0BjByPHwpfTDKg== - dependencies: - ms "^2.1.1" - -decode-uri-component@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" - integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= - -define-properties@^1.1.2: - version "1.1.3" - resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" - integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== - dependencies: - object-keys "^1.0.12" - -define-property@^0.2.5: - version "0.2.5" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" - integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY= - dependencies: - is-descriptor "^0.1.0" - -define-property@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" - integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY= - dependencies: - is-descriptor "^1.0.0" - -define-property@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" - integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== - dependencies: - is-descriptor "^1.0.2" - isobject "^3.0.1" - -escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= - -esprima@~4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" - integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== - -expand-brackets@^2.1.4: - version "2.1.4" - resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" - integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI= - dependencies: - debug "^2.3.3" - define-property "^0.2.5" - extend-shallow "^2.0.1" - posix-character-classes "^0.1.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - -extend-shallow@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" - integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= - dependencies: - is-extendable "^0.1.0" - -extend-shallow@^3.0.0, extend-shallow@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" - integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg= - dependencies: - assign-symbols "^1.0.0" - is-extendable "^1.0.1" - -extglob@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" - integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== - dependencies: - array-unique "^0.3.2" - define-property "^1.0.0" - expand-brackets "^2.1.4" - extend-shallow "^2.0.1" - fragment-cache "^0.2.1" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - -fill-range@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" - integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc= - dependencies: - extend-shallow "^2.0.1" - is-number "^3.0.0" - repeat-string "^1.6.1" - to-regex-range "^2.1.0" - -fill-range@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" - integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== - dependencies: - to-regex-range "^5.0.1" - -find-cache-dir@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-1.0.0.tgz#9288e3e9e3cc3748717d39eade17cf71fc30ee6f" - integrity sha1-kojj6ePMN0hxfTnq3hfPcfww7m8= - dependencies: - commondir "^1.0.1" - make-dir "^1.0.0" - pkg-dir "^2.0.0" - -find-up@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" - integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= - dependencies: - locate-path "^2.0.0" - -flow-parser@0.*, flow-parser@^0.121.0: - version "0.121.0" - resolved "https://registry.yarnpkg.com/flow-parser/-/flow-parser-0.121.0.tgz#9f9898eaec91a9f7c323e9e992d81ab5c58e618f" - integrity sha512-1gIBiWJNR0tKUNv8gZuk7l9rVX06OuLzY9AoGio7y/JT4V1IZErEMEq2TJS+PFcw/y0RshZ1J/27VfK1UQzYVg== - -for-in@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" - integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= - -fragment-cache@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" - integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk= - dependencies: - map-cache "^0.2.2" - -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= - -function-bind@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" - integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== - -gensync@^1.0.0-beta.1: - version "1.0.0-beta.1" - resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.1.tgz#58f4361ff987e5ff6e1e7a210827aa371eaac269" - integrity sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg== - -get-value@^2.0.3, get-value@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" - integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= - -glob@^7.1.1: - version "7.1.6" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" - integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - -globals@^11.1.0: - version "11.9.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-11.9.0.tgz#bde236808e987f290768a93d065060d78e6ab249" - integrity sha512-5cJVtyXWH8PiJPVLZzzoIizXx944O4OmRro5MWKx5fT4MgcN7OfaMutPeaTdJCCURwbWdhhcCWcKIffPnmTzBg== - -graceful-fs@^4.1.11: - version "4.1.15" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00" - integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA== - -has-flag@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" - integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= - -has-flag@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" - integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== - -has-symbols@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8" - integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg== - -has-value@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" - integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8= - dependencies: - get-value "^2.0.3" - has-values "^0.1.4" - isobject "^2.0.0" - -has-value@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" - integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc= - dependencies: - get-value "^2.0.6" - has-values "^1.0.0" - isobject "^3.0.0" - -has-values@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" - integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E= - -has-values@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" - integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8= - dependencies: - is-number "^3.0.0" - kind-of "^4.0.0" - -home-or-tmp@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-3.0.0.tgz#57a8fe24cf33cdd524860a15821ddc25c86671fb" - integrity sha1-V6j+JM8zzdUkhgoVgh3cJchmcfs= - -imurmurhash@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" - integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= - -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@2: - version "2.0.4" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" - integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== - -is-accessor-descriptor@^0.1.6: - version "0.1.6" - resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" - integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY= - dependencies: - kind-of "^3.0.2" - -is-accessor-descriptor@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" - integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ== - dependencies: - kind-of "^6.0.0" - -is-buffer@^1.1.5: - version "1.1.6" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" - integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== - -is-data-descriptor@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" - integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y= - dependencies: - kind-of "^3.0.2" - -is-data-descriptor@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" - integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ== - dependencies: - kind-of "^6.0.0" - -is-descriptor@^0.1.0: - version "0.1.6" - resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" - integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg== - dependencies: - is-accessor-descriptor "^0.1.6" - is-data-descriptor "^0.1.4" - kind-of "^5.0.0" - -is-descriptor@^1.0.0, is-descriptor@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" - integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== - dependencies: - is-accessor-descriptor "^1.0.0" - is-data-descriptor "^1.0.0" - kind-of "^6.0.2" - -is-extendable@^0.1.0, is-extendable@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" - integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= - -is-extendable@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" - integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== - dependencies: - is-plain-object "^2.0.4" - -is-number@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" - integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU= - dependencies: - kind-of "^3.0.2" - -is-number@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" - integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== - -is-plain-object@^2.0.1, 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" - integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== - dependencies: - isobject "^3.0.1" - -is-windows@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" - integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== - -isarray@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" - integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= - -isobject@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" - integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk= - dependencies: - isarray "1.0.0" - -isobject@^3.0.0, isobject@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" - integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= - -js-tokens@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" - integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== - -jscodeshift@^0.9.0: - version "0.9.0" - resolved "https://registry.yarnpkg.com/jscodeshift/-/jscodeshift-0.9.0.tgz#672025658e868a63e24d6a6f4c44af9edb6e55f3" - integrity sha512-SUeXq8dJzj5LR8uy71axgG3bmiHoC0IdHy7n89SqKzkzBWpAds5F9IIGE+lqUSZX9J0ZfEzN8fXWIqQV0dIp2w== - dependencies: - "@babel/core" "^7.1.6" - "@babel/parser" "^7.1.6" - "@babel/plugin-proposal-class-properties" "^7.1.0" - "@babel/plugin-proposal-nullish-coalescing-operator" "^7.1.0" - "@babel/plugin-proposal-optional-chaining" "^7.1.0" - "@babel/plugin-transform-modules-commonjs" "^7.1.0" - "@babel/preset-flow" "^7.0.0" - "@babel/preset-typescript" "^7.1.0" - "@babel/register" "^7.0.0" - babel-core "^7.0.0-bridge.0" - colors "^1.1.2" - flow-parser "0.*" - graceful-fs "^4.1.11" - micromatch "^3.1.10" - neo-async "^2.5.0" - node-dir "^0.1.17" - recast "^0.18.1" - temp "^0.8.1" - write-file-atomic "^2.3.0" - -jsesc@^2.5.1: - version "2.5.2" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" - integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== - -json5@^2.1.2: - version "2.1.3" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.3.tgz#c9b0f7fa9233bfe5807fe66fcf3a5617ed597d43" - integrity sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA== - dependencies: - minimist "^1.2.5" - -kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: - version "3.2.2" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" - integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= - dependencies: - is-buffer "^1.1.5" - -kind-of@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" - integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc= - dependencies: - is-buffer "^1.1.5" - -kind-of@^5.0.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" - integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== - -kind-of@^6.0.0, kind-of@^6.0.2: - version "6.0.2" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051" - integrity sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA== - -locate-path@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" - integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= - dependencies: - p-locate "^2.0.0" - path-exists "^3.0.0" - -lodash@^4.17.10, lodash@^4.17.19: - version "4.17.20" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" - integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA== - -make-dir@^1.0.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c" - integrity sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ== - dependencies: - pify "^3.0.0" - -map-cache@^0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" - integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= - -map-visit@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" - integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48= - dependencies: - object-visit "^1.0.0" - -micromatch@^3.1.10: - version "3.1.10" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" - integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== - dependencies: - arr-diff "^4.0.0" - array-unique "^0.3.2" - braces "^2.3.1" - define-property "^2.0.2" - extend-shallow "^3.0.2" - extglob "^2.0.4" - fragment-cache "^0.2.1" - kind-of "^6.0.2" - nanomatch "^1.2.9" - object.pick "^1.3.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.2" - -micromatch@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.2.tgz#4fcb0999bf9fbc2fcbdd212f6d629b9a56c39259" - integrity sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q== - dependencies: - braces "^3.0.1" - picomatch "^2.0.5" - -minimatch@^3.0.2, minimatch@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== - dependencies: - brace-expansion "^1.1.7" - -minimist@0.0.8: - version "0.0.8" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" - integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= - -minimist@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" - integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== - -mixin-deep@^1.2.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.1.tgz#a49e7268dce1a0d9698e45326c5626df3543d0fe" - integrity sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ== - dependencies: - for-in "^1.0.2" - is-extendable "^1.0.1" - -mkdirp@^0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" - integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= - dependencies: - minimist "0.0.8" - -ms@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= - -ms@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" - integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== - -nanomatch@^1.2.9: - version "1.2.13" - resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" - integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== - dependencies: - arr-diff "^4.0.0" - array-unique "^0.3.2" - define-property "^2.0.2" - extend-shallow "^3.0.2" - fragment-cache "^0.2.1" - is-windows "^1.0.2" - kind-of "^6.0.2" - object.pick "^1.3.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - -neo-async@^2.5.0: - version "2.6.0" - resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.0.tgz#b9d15e4d71c6762908654b5183ed38b753340835" - integrity sha512-MFh0d/Wa7vkKO3Y3LlacqAEeHK0mckVqzDieUKTT+KGxi+zIpeVsFxymkIiRpbpDziHc290Xr9A1O4Om7otoRA== - -node-dir@^0.1.17: - version "0.1.17" - resolved "https://registry.yarnpkg.com/node-dir/-/node-dir-0.1.17.tgz#5f5665d93351335caabef8f1c554516cf5f1e4e5" - integrity sha1-X1Zl2TNRM1yqvvjxxVRRbPXx5OU= - dependencies: - minimatch "^3.0.2" - -node-modules-regexp@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz#8d9dbe28964a4ac5712e9131642107c71e90ec40" - integrity sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA= - -nullthrows@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/nullthrows/-/nullthrows-1.1.1.tgz#7818258843856ae971eae4208ad7d7eb19a431b1" - integrity sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw== - -object-copy@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" - integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw= - dependencies: - copy-descriptor "^0.1.0" - define-property "^0.2.5" - kind-of "^3.0.3" - -object-keys@^1.0.11, object-keys@^1.0.12: - version "1.1.1" - resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" - integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== - -object-visit@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" - integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs= - dependencies: - isobject "^3.0.0" - -object.assign@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da" - integrity sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w== - dependencies: - define-properties "^1.1.2" - function-bind "^1.1.1" - has-symbols "^1.0.0" - object-keys "^1.0.11" - -object.pick@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" - integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c= - dependencies: - isobject "^3.0.1" - -once@^1.3.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= - dependencies: - wrappy "1" - -os-tmpdir@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" - integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= - -p-limit@^1.1.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" - integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== - dependencies: - p-try "^1.0.0" - -p-locate@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" - integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= - dependencies: - p-limit "^1.1.0" - -p-try@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" - integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= - -pascalcase@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" - integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= - -path-exists@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" - integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= - -path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= - -path-parse@^1.0.5: - version "1.0.6" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" - integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== - -picomatch@^2.0.5: - version "2.2.2" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad" - integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg== - -pify@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" - integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= - -pirates@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.0.tgz#850b18781b4ac6ec58a43c9ed9ec5fe6796addbd" - integrity sha512-8t5BsXy1LUIjn3WWOlOuFDuKswhQb/tkak641lvBgmPOBUQHXveORtlMCp6OdPV1dtuTaEahKA8VNz6uLfKBtA== - dependencies: - node-modules-regexp "^1.0.0" - -pkg-dir@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b" - integrity sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s= - dependencies: - find-up "^2.1.0" - -posix-character-classes@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" - integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= - -prettier@1.19.1: - version "1.19.1" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb" - integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew== - -private@^0.1.8: - version "0.1.8" - resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" - integrity sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg== - -recast@^0.18.1: - version "0.18.10" - resolved "https://registry.yarnpkg.com/recast/-/recast-0.18.10.tgz#605ebbe621511eb89b6356a7e224bff66ed91478" - integrity sha512-XNvYvkfdAN9QewbrxeTOjgINkdY/odTgTS56ZNEWL9Ml0weT4T3sFtvnTuF+Gxyu46ANcRm1ntrF6F5LAJPAaQ== - dependencies: - ast-types "0.13.3" - esprima "~4.0.0" - private "^0.1.8" - source-map "~0.6.1" - -regex-not@^1.0.0, regex-not@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" - integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== - dependencies: - extend-shallow "^3.0.2" - safe-regex "^1.1.0" - -repeat-element@^1.1.2: - version "1.1.3" - resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce" - integrity sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g== - -repeat-string@^1.6.1: - version "1.6.1" - resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" - integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= - -resolve-url@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" - integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= - -resolve@^1.3.2: - version "1.8.1" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.8.1.tgz#82f1ec19a423ac1fbd080b0bab06ba36e84a7a26" - integrity sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA== - dependencies: - path-parse "^1.0.5" - -ret@~0.1.10: - version "0.1.15" - resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" - integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== - -rimraf@~2.2.6: - version "2.2.8" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.2.8.tgz#e439be2aaee327321952730f99a8929e4fc50582" - integrity sha1-5Dm+Kq7jJzIZUnMPmaiSnk/FBYI= - -safe-buffer@~5.1.1: - version "5.1.2" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" - integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== - -safe-regex@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" - integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4= - dependencies: - ret "~0.1.10" - -semver@^5.4.1: - version "5.6.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" - integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg== - -set-value@^0.4.3: - version "0.4.3" - resolved "https://registry.yarnpkg.com/set-value/-/set-value-0.4.3.tgz#7db08f9d3d22dc7f78e53af3c3bf4666ecdfccf1" - integrity sha1-fbCPnT0i3H945Trzw79GZuzfzPE= - dependencies: - extend-shallow "^2.0.1" - is-extendable "^0.1.1" - is-plain-object "^2.0.1" - to-object-path "^0.3.0" - -set-value@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.0.tgz#71ae4a88f0feefbbf52d1ea604f3fb315ebb6274" - integrity sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg== - dependencies: - extend-shallow "^2.0.1" - is-extendable "^0.1.1" - is-plain-object "^2.0.3" - split-string "^3.0.1" - -signal-exit@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" - integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= - -snapdragon-node@^2.0.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" - integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== - dependencies: - define-property "^1.0.0" - isobject "^3.0.0" - snapdragon-util "^3.0.1" - -snapdragon-util@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" - integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== - dependencies: - kind-of "^3.2.0" - -snapdragon@^0.8.1: - version "0.8.2" - resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" - integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== - dependencies: - base "^0.11.1" - debug "^2.2.0" - define-property "^0.2.5" - extend-shallow "^2.0.1" - map-cache "^0.2.2" - source-map "^0.5.6" - source-map-resolve "^0.5.0" - use "^3.1.0" - -source-map-resolve@^0.5.0: - version "0.5.2" - resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259" - integrity sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA== - dependencies: - atob "^2.1.1" - decode-uri-component "^0.2.0" - resolve-url "^0.2.1" - source-map-url "^0.4.0" - urix "^0.1.0" - -source-map-support@^0.5.9: - version "0.5.9" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.9.tgz#41bc953b2534267ea2d605bccfa7bfa3111ced5f" - integrity sha512-gR6Rw4MvUlYy83vP0vxoVNzM6t8MUXqNuRsuBmBHQDu1Fh6X015FrLdgoDKcNdkwGubozq0P4N0Q37UyFVr1EA== - dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" - -source-map-url@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" - integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM= - -source-map@^0.5.0, source-map@^0.5.6: - version "0.5.7" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" - integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= - -source-map@^0.6.0, source-map@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" - integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== - -split-string@^3.0.1, split-string@^3.0.2: - version "3.1.0" - resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" - integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== - dependencies: - extend-shallow "^3.0.0" - -static-extend@^0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" - integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY= - dependencies: - define-property "^0.2.5" - object-copy "^0.1.0" - -supports-color@^5.3.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" - integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== - dependencies: - has-flag "^3.0.0" - -supports-color@^7.1.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.1.0.tgz#68e32591df73e25ad1c4b49108a2ec507962bfd1" - integrity sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g== - dependencies: - has-flag "^4.0.0" - -temp@^0.8.1: - version "0.8.3" - resolved "https://registry.yarnpkg.com/temp/-/temp-0.8.3.tgz#e0c6bc4d26b903124410e4fed81103014dfc1f59" - integrity sha1-4Ma8TSa5AxJEEOT+2BEDAU38H1k= - dependencies: - os-tmpdir "^1.0.0" - rimraf "~2.2.6" - -to-fast-properties@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" - integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= - -to-object-path@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" - integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68= - dependencies: - kind-of "^3.0.2" - -to-regex-range@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" - integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg= - dependencies: - is-number "^3.0.0" - repeat-string "^1.6.1" - -to-regex-range@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" - integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== - dependencies: - is-number "^7.0.0" - -to-regex@^3.0.1, to-regex@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" - integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== - dependencies: - define-property "^2.0.2" - extend-shallow "^3.0.2" - regex-not "^1.0.2" - safe-regex "^1.1.0" - -union-value@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4" - integrity sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ= - dependencies: - arr-union "^3.1.0" - get-value "^2.0.6" - is-extendable "^0.1.1" - set-value "^0.4.3" - -unset-value@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" - integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk= - dependencies: - has-value "^0.3.1" - isobject "^3.0.0" - -urix@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" - integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= - -use@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" - integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== - -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= - -write-file-atomic@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.3.0.tgz#1ff61575c2e2a4e8e510d6fa4e243cce183999ab" - integrity sha512-xuPeK4OdjWqtfi59ylvVL0Yn35SF3zgcAcv7rBPFHVaEapaDr4GdGgm3j7ckTwH9wHL7fGmgfAnb0+THrHb8tA== - dependencies: - graceful-fs "^4.1.11" - imurmurhash "^0.1.4" - signal-exit "^3.0.2" diff --git a/packages/rn-tester/package.json b/packages/rn-tester/package.json index 8fcd4bd4da6d0c..268966a0890777 100644 --- a/packages/rn-tester/package.json +++ b/packages/rn-tester/package.json @@ -8,10 +8,11 @@ "type": "git", "url": "git@github.com:facebook/react-native.git" }, - "scripts": {}, "dependencies": { "invariant": "^2.2.4", - "nullthrows": "^1.1.1", + "nullthrows": "^1.1.1" + }, + "peerDependencies": { "react": "16.13.1", "react-native": "*" }, diff --git a/repo-config/package.json b/repo-config/package.json index 92ed81ebeec4aa..16fdef134f6646 100644 --- a/repo-config/package.json +++ b/repo-config/package.json @@ -11,7 +11,7 @@ "dependencies": { "@babel/core": "^7.0.0", "@babel/generator": "^7.5.0", - "@react-native-community/eslint-plugin": "file:../packages/eslint-plugin-react-native-community", + "@react-native-community/eslint-plugin": "*", "@reactions/component": "^2.0.2", "async": "^2.4.0", "babel-eslint": "^10.1.0", diff --git a/yarn.lock b/yarn.lock index 5a56487df8848e..b1d5ed65973bc1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1141,24 +1141,6 @@ sudo-prompt "^9.0.0" wcwidth "^1.0.1" -"@react-native-community/eslint-plugin@file:packages/eslint-plugin-react-native-community": - version "1.1.0" - -"@react-native/assets@1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@react-native/assets/-/assets-1.0.0.tgz#c6f9bf63d274bafc8e970628de24986b30a55c8e" - integrity sha512-KrwSpS1tKI70wuKl68DwJZYEvXktDHdZMG0k2AXD/rJVSlB23/X2CB2cutVR0HwNMJIal9HOUOBB2rVfa6UGtQ== - -"@react-native/normalize-color@1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@react-native/normalize-color/-/normalize-color-1.0.0.tgz#c52a99d4fe01049102d47dc45d40cbde4f720ab6" - integrity sha512-xUNRvNmCl3UGCPbbHvfyFMnpvLPoOjDCcp5bT9m2k+TF/ZBklEQwhPZlkrxRx2NhgFh1X3a5uL7mJ7ZR+8G7Qg== - -"@react-native/polyfills@1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@react-native/polyfills/-/polyfills-1.0.0.tgz#05bb0031533598f9458cf65a502b8df0eecae780" - integrity sha512-0jbp4RxjYopTsIdLl+/Fy2TiwVYHy4mgeu07DG4b/LyM0OS/+lPP5c9sbnt/AMlnF6qz2JRZpPpGw1eMNS6A4w== - "@reactions/component@^2.0.2": version "2.0.2" resolved "https://registry.yarnpkg.com/@reactions/component/-/component-2.0.2.tgz#40f8c1c2c37baabe57a0c944edb9310dc1ec6642" @@ -3289,6 +3271,11 @@ flow-parser@0.*: resolved "https://registry.yarnpkg.com/flow-parser/-/flow-parser-0.89.0.tgz#c87bf45831644733dd576983ab12e75a3546573b" integrity sha512-vC8YuwhAPE+tbkz49DA/TjtFyfhcqM48occMdRQiZ/HL+Wg97IcuebMZUGVB4oBq7aHw0iJJtnvmlnmOQF7Ydg== +flow-parser@^0.121.0: + version "0.121.0" + resolved "https://registry.yarnpkg.com/flow-parser/-/flow-parser-0.121.0.tgz#9f9898eaec91a9f7c323e9e992d81ab5c58e618f" + integrity sha512-1gIBiWJNR0tKUNv8gZuk7l9rVX06OuLzY9AoGio7y/JT4V1IZErEMEq2TJS+PFcw/y0RshZ1J/27VfK1UQzYVg== + for-in@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" From 38c3b9579808db16309f4aa65959f4c93ca9b6db Mon Sep 17 00:00:00 2001 From: Peter Argany Date: Fri, 21 Aug 2020 13:19:06 -0700 Subject: [PATCH 0002/1238] Bridgeless support for RCTKeyboardObserver Summary: RCTKeyboardObserver only uses the bridge to avoid sending events during a reload. See D6573855 (https://github.com/facebook/react-native/commit/d9c658566a14ce8767d87435264997aa18dd08e4) for reference. In bridgeless mode, the bridge is expected to always be nil, as the module uses `invokeJS` block to send events instead. Changelog: [Internal] Reviewed By: shergin Differential Revision: D23176990 fbshipit-source-id: 7946c9c2684d7d9ea0a606bad375309a5530a719 --- React/CoreModules/RCTKeyboardObserver.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/React/CoreModules/RCTKeyboardObserver.mm b/React/CoreModules/RCTKeyboardObserver.mm index c60b1030c0bf61..b00f08c21cabb6 100644 --- a/React/CoreModules/RCTKeyboardObserver.mm +++ b/React/CoreModules/RCTKeyboardObserver.mm @@ -64,7 +64,7 @@ - (void)stopObserving #define IMPLEMENT_KEYBOARD_HANDLER(EVENT) \ -(void)EVENT : (NSNotification *)notification \ { \ - if (!self.bridge) { \ + if (!self.bridge && !self.invokeJS) { \ return; \ } \ [self sendEventWithName:@ #EVENT body:RCTParseKeyboardNotification(notification)]; \ From 60a5223ff71969ec1f3e60595cdb9e4ef477625b Mon Sep 17 00:00:00 2001 From: David Vacca Date: Fri, 21 Aug 2020 14:15:17 -0700 Subject: [PATCH 0003/1238] Integrate AndroidTextInput in RN Tester OSS App Summary: This diff integrates AndroidTextInput in RN Tester OSS App changelog: [internal] Internal Reviewed By: fkgozali Differential Revision: D23179389 fbshipit-source-id: 709d71343ca374ca2ece00774f4f273145bffd20 --- .../com/facebook/react/fabric/jni/Android.mk | 3 +- .../fabric/jni/CoreComponentsRegistry.cpp | 3 ++ .../renderer/components/textinput/Android.mk | 44 +++++++++++++++++++ 3 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 ReactCommon/react/renderer/components/textinput/Android.mk diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Android.mk b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Android.mk index 3a5910bfca5a2c..b79f5669199655 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Android.mk +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Android.mk @@ -11,7 +11,7 @@ LOCAL_MODULE := fabricjni LOCAL_SRC_FILES := $(wildcard $(LOCAL_PATH)/*.cpp) -LOCAL_SHARED_LIBRARIES := libreactconfig libyoga libglog libfb libfbjni libglog_init libfolly_json libfolly_futures libreact_render_mounting libreactnativeutilsjni libreact_utils libreact_render_debug libreact_render_graphics libreact_render_core libreact_render_mapbuffer react_render_componentregistry libreact_render_components_view libreact_render_components_unimplementedview libreact_render_components_root libreact_render_components_scrollview libbetter libreact_render_attributedstring libreact_render_uimanager libreact_render_templateprocessor libreact_render_scheduler libreact_render_animations libreact_render_imagemanager libreact_render_textlayoutmanager libreact_render_viewmanagers react_render_components_text libreact_render_components_image +LOCAL_SHARED_LIBRARIES := libreactconfig libyoga libglog libfb libfbjni libglog_init libfolly_json libfolly_futures libreact_render_mounting libreactnativeutilsjni libreact_utils libreact_render_debug libreact_render_graphics libreact_render_core libreact_render_mapbuffer react_render_componentregistry libreact_render_components_view libreact_render_components_unimplementedview libreact_render_components_root libreact_render_components_scrollview libbetter libreact_render_attributedstring libreact_render_uimanager libreact_render_templateprocessor libreact_render_scheduler libreact_render_animations libreact_render_imagemanager libreact_render_textlayoutmanager libreact_render_viewmanagers react_render_components_text libreact_render_components_image react_render_components_textinput LOCAL_STATIC_LIBRARIES := @@ -44,6 +44,7 @@ $(call import-module,react/renderer/components/root) $(call import-module,react/renderer/components/scrollview) $(call import-module,react/renderer/components/unimplementedview) $(call import-module,react/renderer/components/text) +$(call import-module,react/renderer/components/textinput) $(call import-module,react/renderer/components/view) $(call import-module,react/renderer/debug) $(call import-module,react/renderer/graphics) diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/CoreComponentsRegistry.cpp b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/CoreComponentsRegistry.cpp index ae75c1df1a6532..04bb606dc5f0dd 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/CoreComponentsRegistry.cpp +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/CoreComponentsRegistry.cpp @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -32,6 +33,8 @@ CoreComponentsRegistry::sharedProviderRegistry() { auto providerRegistry = std::make_shared(); + providerRegistry->add(concreteComponentDescriptorProvider< + AndroidTextInputComponentDescriptor>()); providerRegistry->add( concreteComponentDescriptorProvider()); providerRegistry->add( diff --git a/ReactCommon/react/renderer/components/textinput/Android.mk b/ReactCommon/react/renderer/components/textinput/Android.mk new file mode 100644 index 00000000000000..80f6bf8fa1aafd --- /dev/null +++ b/ReactCommon/react/renderer/components/textinput/Android.mk @@ -0,0 +1,44 @@ +# 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. + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := react_render_components_textinput + +LOCAL_SRC_FILES := $(wildcard $(LOCAL_PATH)/androidtextinput/react/renderer/components/androidtextinput/*.cpp) + +LOCAL_C_INCLUDES := $(LOCAL_PATH)/androidtextinput/react/renderer/components/androidtextinput/ +LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/androidtextinput/ + +LOCAL_CFLAGS := \ + -DLOG_TAG=\"Fabric\" + +LOCAL_CFLAGS += -fexceptions -frtti -std=c++14 -Wall + +LOCAL_STATIC_LIBRARIES := + +LOCAL_SHARED_LIBRARIES := libyoga glog libfolly_json libglog_init libreact_render_core libreact_render_mounting libreact_render_componentregistry libreact_render_debug libreact_render_graphics libreact_render_uimanager libreact_render_imagemanager libreact_render_textlayoutmanager libreact_render_attributedstring libreact_render_components_text libreact_render_components_image libreact_render_components_view libreact_utils + +include $(BUILD_SHARED_LIBRARY) + +$(call import-module,glog) +$(call import-module,folly) +$(call import-module,fbgloginit) +$(call import-module,react/renderer/attributedstring) +$(call import-module,react/renderer/componentregistry) +$(call import-module,react/renderer/core) +$(call import-module,react/renderer/debug) +$(call import-module,react/renderer/graphics) +$(call import-module,react/renderer/imagemanager) +$(call import-module,react/renderer/mounting) +$(call import-module,react/renderer/textlayoutmanager) +$(call import-module,react/renderer/uimanager) +$(call import-module,react/renderer/components/image) +$(call import-module,react/renderer/components/view) +$(call import-module,react/renderer/components/text) +$(call import-module,react/utils) +$(call import-module,yogajni) From 9b811fb0bfd7800395d8c15fcb9e54ac602b8515 Mon Sep 17 00:00:00 2001 From: David Vacca Date: Fri, 21 Aug 2020 14:15:17 -0700 Subject: [PATCH 0004/1238] Integrate ScrollView in RN Tester Android OSS APP Summary: This diff integrates ScrollView in RN Tester Android OSS APP changelog: [internal] internal Reviewed By: fkgozali Differential Revision: D23179883 fbshipit-source-id: 8e892ae613a1f44c8d6cfb837bfdbc0771a89176 --- .../com/facebook/react/fabric/jni/CoreComponentsRegistry.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/CoreComponentsRegistry.cpp b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/CoreComponentsRegistry.cpp index 04bb606dc5f0dd..cd2f0291c9cae2 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/CoreComponentsRegistry.cpp +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/CoreComponentsRegistry.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -43,6 +44,8 @@ CoreComponentsRegistry::sharedProviderRegistry() { concreteComponentDescriptorProvider()); providerRegistry->add( concreteComponentDescriptorProvider()); + providerRegistry->add( + concreteComponentDescriptorProvider()); providerRegistry->add( concreteComponentDescriptorProvider()); From 3790569a71bbb85017ad9854864dfc0b77f0aaa9 Mon Sep 17 00:00:00 2001 From: David Vacca Date: Fri, 21 Aug 2020 14:15:17 -0700 Subject: [PATCH 0005/1238] Integrate Modal into RN Tester Fabric OSS APP Summary: This diff integrates Modal into RN Tester Fabric OSS APP changelog: [internal] internal Reviewed By: fkgozali Differential Revision: D23183507 fbshipit-source-id: bc2513c39c783d387a985c86a12b04dadac49933 --- .../com/facebook/react/fabric/jni/Android.mk | 5 ++- .../java/com/facebook/react/fabric/jni/BUCK | 1 + .../fabric/jni/CoreComponentsRegistry.cpp | 3 ++ .../renderer/components/modal/Android.mk | 39 +++++++++++++++++++ 4 files changed, 46 insertions(+), 2 deletions(-) create mode 100644 ReactCommon/react/renderer/components/modal/Android.mk diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Android.mk b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Android.mk index b79f5669199655..3a607e1137f128 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Android.mk +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Android.mk @@ -11,7 +11,7 @@ LOCAL_MODULE := fabricjni LOCAL_SRC_FILES := $(wildcard $(LOCAL_PATH)/*.cpp) -LOCAL_SHARED_LIBRARIES := libreactconfig libyoga libglog libfb libfbjni libglog_init libfolly_json libfolly_futures libreact_render_mounting libreactnativeutilsjni libreact_utils libreact_render_debug libreact_render_graphics libreact_render_core libreact_render_mapbuffer react_render_componentregistry libreact_render_components_view libreact_render_components_unimplementedview libreact_render_components_root libreact_render_components_scrollview libbetter libreact_render_attributedstring libreact_render_uimanager libreact_render_templateprocessor libreact_render_scheduler libreact_render_animations libreact_render_imagemanager libreact_render_textlayoutmanager libreact_render_viewmanagers react_render_components_text libreact_render_components_image react_render_components_textinput +LOCAL_SHARED_LIBRARIES := libreactconfig libreact_render_components_modal libyoga libglog libfb libfbjni libglog_init libfolly_json libfolly_futures libreact_render_mounting libreactnativeutilsjni libreact_utils libreact_render_debug libreact_render_graphics libreact_render_core libreact_render_mapbuffer react_render_componentregistry libreact_render_components_view libreact_render_components_unimplementedview libreact_render_components_root libreact_render_components_scrollview libbetter libreact_render_attributedstring libreact_render_uimanager libreact_render_templateprocessor libreact_render_scheduler libreact_render_animations libreact_render_imagemanager libreact_render_textlayoutmanager libreact_render_viewmanagers react_render_components_text libreact_render_components_image react_render_components_textinput LOCAL_STATIC_LIBRARIES := @@ -40,11 +40,12 @@ $(call import-module,react/renderer/attributedstring) $(call import-module,react/renderer/componentregistry) $(call import-module,react/renderer/core) $(call import-module,react/renderer/components/image) +$(call import-module,react/renderer/components/modal) $(call import-module,react/renderer/components/root) $(call import-module,react/renderer/components/scrollview) -$(call import-module,react/renderer/components/unimplementedview) $(call import-module,react/renderer/components/text) $(call import-module,react/renderer/components/textinput) +$(call import-module,react/renderer/components/unimplementedview) $(call import-module,react/renderer/components/view) $(call import-module,react/renderer/debug) $(call import-module,react/renderer/graphics) diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/BUCK b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/BUCK index ede1b68846ad50..a6cab8b8310801 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/BUCK +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/BUCK @@ -47,6 +47,7 @@ rn_xplat_cxx_library( "//xplat/js/react-native-github:generated_components-rncore", react_native_xplat_target("react/renderer/components/image:image"), react_native_xplat_target("react/renderer/components/text:text"), + react_native_xplat_target("react/renderer/components/modal:modal"), react_native_xplat_target("react/renderer/components/textinput:androidtextinput"), ], ) diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/CoreComponentsRegistry.cpp b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/CoreComponentsRegistry.cpp index cd2f0291c9cae2..74b54374eac2b5 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/CoreComponentsRegistry.cpp +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/CoreComponentsRegistry.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -40,6 +41,8 @@ CoreComponentsRegistry::sharedProviderRegistry() { concreteComponentDescriptorProvider()); providerRegistry->add( concreteComponentDescriptorProvider()); + providerRegistry->add(concreteComponentDescriptorProvider< + ModalHostViewComponentDescriptor>()); providerRegistry->add( concreteComponentDescriptorProvider()); providerRegistry->add( diff --git a/ReactCommon/react/renderer/components/modal/Android.mk b/ReactCommon/react/renderer/components/modal/Android.mk new file mode 100644 index 00000000000000..dd404e8dbda309 --- /dev/null +++ b/ReactCommon/react/renderer/components/modal/Android.mk @@ -0,0 +1,39 @@ +# 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. + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := react_render_components_modal + +LOCAL_SRC_FILES := $(wildcard $(LOCAL_PATH)/*.cpp) + +LOCAL_C_INCLUDES := $(LOCAL_PATH)/ +LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/../../../../ + +LOCAL_CFLAGS := \ + -DLOG_TAG=\"Fabric\" + +LOCAL_CFLAGS += -fexceptions -frtti -std=c++14 -Wall + +LOCAL_STATIC_LIBRARIES := + +LOCAL_SHARED_LIBRARIES := libyoga glog libfolly_json libglog_init libreact_render_core libreact_render_debug libreact_render_graphics libreact_render_components_image libreact_render_uimanager libreact_render_imagemanager libreact_render_components_view libreact_render_componentregistry libreact_render_viewmanagers + +include $(BUILD_SHARED_LIBRARY) + +$(call import-module,glog) +$(call import-module,folly) +$(call import-module,fbgloginit) +$(call import-module,react/renderer/core) +$(call import-module,react/renderer/componentregistry) +$(call import-module,react/renderer/debug) +$(call import-module,react/renderer/graphics) +$(call import-module,react/renderer/imagemanager) +$(call import-module,react/renderer/uimanager) +$(call import-module,react/renderer/components/image) +$(call import-module,react/renderer/components/view) +$(call import-module,yogajni) From a76c55e0f5e1dc0f3838dc783c180dfffbe2a4e2 Mon Sep 17 00:00:00 2001 From: David Vacca Date: Fri, 21 Aug 2020 14:15:17 -0700 Subject: [PATCH 0006/1238] Integrate AndroidDrawerLayout component into RN Tester Android OSS APP Summary: This diff registers the AndroidDrawerLayout component into RN Tester Android OSS APP Changelog: [internal] Reviewed By: fkgozali Differential Revision: D23198359 fbshipit-source-id: 4033c7e968a993a7f8fcaa3f57e7dd78bf84fe57 --- .../com/facebook/react/fabric/jni/CoreComponentsRegistry.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/CoreComponentsRegistry.cpp b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/CoreComponentsRegistry.cpp index 74b54374eac2b5..869d2a2c0af553 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/CoreComponentsRegistry.cpp +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/CoreComponentsRegistry.cpp @@ -51,6 +51,8 @@ CoreComponentsRegistry::sharedProviderRegistry() { concreteComponentDescriptorProvider()); providerRegistry->add( concreteComponentDescriptorProvider()); + providerRegistry->add(concreteComponentDescriptorProvider< + AndroidDrawerLayoutComponentDescriptor>()); return providerRegistry; }(); From 1663f27f953aad1fcff1cabb868ea27be750ce7a Mon Sep 17 00:00:00 2001 From: David Vacca Date: Fri, 21 Aug 2020 14:15:17 -0700 Subject: [PATCH 0007/1238] Integrate Activity Indicator into RN Tester Android OSS app Summary: This diff integrates Activity Indicator into RN Tester Android OSS app changelog: [internal] internal Reviewed By: fkgozali Differential Revision: D23198641 fbshipit-source-id: 93614a3f856b4fc162d4618b168d9c82d18a91eb --- .../com/facebook/react/fabric/jni/CoreComponentsRegistry.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/CoreComponentsRegistry.cpp b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/CoreComponentsRegistry.cpp index 869d2a2c0af553..5e7df5bbd4aa46 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/CoreComponentsRegistry.cpp +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/CoreComponentsRegistry.cpp @@ -35,6 +35,8 @@ CoreComponentsRegistry::sharedProviderRegistry() { auto providerRegistry = std::make_shared(); + providerRegistry->add(concreteComponentDescriptorProvider< + ActivityIndicatorViewComponentDescriptor>()); providerRegistry->add(concreteComponentDescriptorProvider< AndroidTextInputComponentDescriptor>()); providerRegistry->add( From 7afb39d0284644087f13e282f3a1a30de232589c Mon Sep 17 00:00:00 2001 From: David Vacca Date: Fri, 21 Aug 2020 14:15:17 -0700 Subject: [PATCH 0008/1238] Move AndroidDialogPicker C++ files to make it compatible with RN OSS build system Summary: This diff moves AndroidDialogPicker C++ files to make it compatible with RN OSS build system. changelog: [internal] Reviewed By: fkgozali Differential Revision: D23198857 fbshipit-source-id: 8fd4b7081f5f573946a6b9cd3fdc408488f91e13 --- ReactCommon/react/renderer/components/picker/BUCK | 2 +- .../androidpicker}/AndroidDialogPickerComponentDescriptor.h | 0 .../androidpicker}/AndroidDialogPickerEventEmitter.cpp | 0 .../components/androidpicker}/AndroidDialogPickerEventEmitter.h | 0 .../components/androidpicker}/AndroidDialogPickerProps.cpp | 0 .../components/androidpicker}/AndroidDialogPickerProps.h | 0 .../components/androidpicker}/AndroidDialogPickerShadowNode.cpp | 0 .../components/androidpicker}/AndroidDialogPickerShadowNode.h | 0 .../androidpicker}/AndroidDropdownPickerComponentDescriptor.h | 0 .../androidpicker}/AndroidDropdownPickerEventEmitter.cpp | 0 .../androidpicker}/AndroidDropdownPickerEventEmitter.h | 0 .../components/androidpicker}/AndroidDropdownPickerProps.cpp | 0 .../components/androidpicker}/AndroidDropdownPickerProps.h | 0 .../androidpicker}/AndroidDropdownPickerShadowNode.cpp | 0 .../components/androidpicker}/AndroidDropdownPickerShadowNode.h | 0 15 files changed, 1 insertion(+), 1 deletion(-) rename ReactCommon/react/renderer/components/picker/androidpicker/{ => react/renderer/components/androidpicker}/AndroidDialogPickerComponentDescriptor.h (100%) rename ReactCommon/react/renderer/components/picker/androidpicker/{ => react/renderer/components/androidpicker}/AndroidDialogPickerEventEmitter.cpp (100%) rename ReactCommon/react/renderer/components/picker/androidpicker/{ => react/renderer/components/androidpicker}/AndroidDialogPickerEventEmitter.h (100%) rename ReactCommon/react/renderer/components/picker/androidpicker/{ => react/renderer/components/androidpicker}/AndroidDialogPickerProps.cpp (100%) rename ReactCommon/react/renderer/components/picker/androidpicker/{ => react/renderer/components/androidpicker}/AndroidDialogPickerProps.h (100%) rename ReactCommon/react/renderer/components/picker/androidpicker/{ => react/renderer/components/androidpicker}/AndroidDialogPickerShadowNode.cpp (100%) rename ReactCommon/react/renderer/components/picker/androidpicker/{ => react/renderer/components/androidpicker}/AndroidDialogPickerShadowNode.h (100%) rename ReactCommon/react/renderer/components/picker/androidpicker/{ => react/renderer/components/androidpicker}/AndroidDropdownPickerComponentDescriptor.h (100%) rename ReactCommon/react/renderer/components/picker/androidpicker/{ => react/renderer/components/androidpicker}/AndroidDropdownPickerEventEmitter.cpp (100%) rename ReactCommon/react/renderer/components/picker/androidpicker/{ => react/renderer/components/androidpicker}/AndroidDropdownPickerEventEmitter.h (100%) rename ReactCommon/react/renderer/components/picker/androidpicker/{ => react/renderer/components/androidpicker}/AndroidDropdownPickerProps.cpp (100%) rename ReactCommon/react/renderer/components/picker/androidpicker/{ => react/renderer/components/androidpicker}/AndroidDropdownPickerProps.h (100%) rename ReactCommon/react/renderer/components/picker/androidpicker/{ => react/renderer/components/androidpicker}/AndroidDropdownPickerShadowNode.cpp (100%) rename ReactCommon/react/renderer/components/picker/androidpicker/{ => react/renderer/components/androidpicker}/AndroidDropdownPickerShadowNode.h (100%) diff --git a/ReactCommon/react/renderer/components/picker/BUCK b/ReactCommon/react/renderer/components/picker/BUCK index d83a54ff910ff1..985b331f4ac36f 100644 --- a/ReactCommon/react/renderer/components/picker/BUCK +++ b/ReactCommon/react/renderer/components/picker/BUCK @@ -30,7 +30,7 @@ rn_xplat_cxx_library( exported_headers = subdir_glob( [ ("", "*.h"), - ("androidpicker", "*.h"), + ("androidpicker/react/renderer/components/androidpicker", "*.h"), ], prefix = "react/renderer/components/androidpicker", ), diff --git a/ReactCommon/react/renderer/components/picker/androidpicker/AndroidDialogPickerComponentDescriptor.h b/ReactCommon/react/renderer/components/picker/androidpicker/react/renderer/components/androidpicker/AndroidDialogPickerComponentDescriptor.h similarity index 100% rename from ReactCommon/react/renderer/components/picker/androidpicker/AndroidDialogPickerComponentDescriptor.h rename to ReactCommon/react/renderer/components/picker/androidpicker/react/renderer/components/androidpicker/AndroidDialogPickerComponentDescriptor.h diff --git a/ReactCommon/react/renderer/components/picker/androidpicker/AndroidDialogPickerEventEmitter.cpp b/ReactCommon/react/renderer/components/picker/androidpicker/react/renderer/components/androidpicker/AndroidDialogPickerEventEmitter.cpp similarity index 100% rename from ReactCommon/react/renderer/components/picker/androidpicker/AndroidDialogPickerEventEmitter.cpp rename to ReactCommon/react/renderer/components/picker/androidpicker/react/renderer/components/androidpicker/AndroidDialogPickerEventEmitter.cpp diff --git a/ReactCommon/react/renderer/components/picker/androidpicker/AndroidDialogPickerEventEmitter.h b/ReactCommon/react/renderer/components/picker/androidpicker/react/renderer/components/androidpicker/AndroidDialogPickerEventEmitter.h similarity index 100% rename from ReactCommon/react/renderer/components/picker/androidpicker/AndroidDialogPickerEventEmitter.h rename to ReactCommon/react/renderer/components/picker/androidpicker/react/renderer/components/androidpicker/AndroidDialogPickerEventEmitter.h diff --git a/ReactCommon/react/renderer/components/picker/androidpicker/AndroidDialogPickerProps.cpp b/ReactCommon/react/renderer/components/picker/androidpicker/react/renderer/components/androidpicker/AndroidDialogPickerProps.cpp similarity index 100% rename from ReactCommon/react/renderer/components/picker/androidpicker/AndroidDialogPickerProps.cpp rename to ReactCommon/react/renderer/components/picker/androidpicker/react/renderer/components/androidpicker/AndroidDialogPickerProps.cpp diff --git a/ReactCommon/react/renderer/components/picker/androidpicker/AndroidDialogPickerProps.h b/ReactCommon/react/renderer/components/picker/androidpicker/react/renderer/components/androidpicker/AndroidDialogPickerProps.h similarity index 100% rename from ReactCommon/react/renderer/components/picker/androidpicker/AndroidDialogPickerProps.h rename to ReactCommon/react/renderer/components/picker/androidpicker/react/renderer/components/androidpicker/AndroidDialogPickerProps.h diff --git a/ReactCommon/react/renderer/components/picker/androidpicker/AndroidDialogPickerShadowNode.cpp b/ReactCommon/react/renderer/components/picker/androidpicker/react/renderer/components/androidpicker/AndroidDialogPickerShadowNode.cpp similarity index 100% rename from ReactCommon/react/renderer/components/picker/androidpicker/AndroidDialogPickerShadowNode.cpp rename to ReactCommon/react/renderer/components/picker/androidpicker/react/renderer/components/androidpicker/AndroidDialogPickerShadowNode.cpp diff --git a/ReactCommon/react/renderer/components/picker/androidpicker/AndroidDialogPickerShadowNode.h b/ReactCommon/react/renderer/components/picker/androidpicker/react/renderer/components/androidpicker/AndroidDialogPickerShadowNode.h similarity index 100% rename from ReactCommon/react/renderer/components/picker/androidpicker/AndroidDialogPickerShadowNode.h rename to ReactCommon/react/renderer/components/picker/androidpicker/react/renderer/components/androidpicker/AndroidDialogPickerShadowNode.h diff --git a/ReactCommon/react/renderer/components/picker/androidpicker/AndroidDropdownPickerComponentDescriptor.h b/ReactCommon/react/renderer/components/picker/androidpicker/react/renderer/components/androidpicker/AndroidDropdownPickerComponentDescriptor.h similarity index 100% rename from ReactCommon/react/renderer/components/picker/androidpicker/AndroidDropdownPickerComponentDescriptor.h rename to ReactCommon/react/renderer/components/picker/androidpicker/react/renderer/components/androidpicker/AndroidDropdownPickerComponentDescriptor.h diff --git a/ReactCommon/react/renderer/components/picker/androidpicker/AndroidDropdownPickerEventEmitter.cpp b/ReactCommon/react/renderer/components/picker/androidpicker/react/renderer/components/androidpicker/AndroidDropdownPickerEventEmitter.cpp similarity index 100% rename from ReactCommon/react/renderer/components/picker/androidpicker/AndroidDropdownPickerEventEmitter.cpp rename to ReactCommon/react/renderer/components/picker/androidpicker/react/renderer/components/androidpicker/AndroidDropdownPickerEventEmitter.cpp diff --git a/ReactCommon/react/renderer/components/picker/androidpicker/AndroidDropdownPickerEventEmitter.h b/ReactCommon/react/renderer/components/picker/androidpicker/react/renderer/components/androidpicker/AndroidDropdownPickerEventEmitter.h similarity index 100% rename from ReactCommon/react/renderer/components/picker/androidpicker/AndroidDropdownPickerEventEmitter.h rename to ReactCommon/react/renderer/components/picker/androidpicker/react/renderer/components/androidpicker/AndroidDropdownPickerEventEmitter.h diff --git a/ReactCommon/react/renderer/components/picker/androidpicker/AndroidDropdownPickerProps.cpp b/ReactCommon/react/renderer/components/picker/androidpicker/react/renderer/components/androidpicker/AndroidDropdownPickerProps.cpp similarity index 100% rename from ReactCommon/react/renderer/components/picker/androidpicker/AndroidDropdownPickerProps.cpp rename to ReactCommon/react/renderer/components/picker/androidpicker/react/renderer/components/androidpicker/AndroidDropdownPickerProps.cpp diff --git a/ReactCommon/react/renderer/components/picker/androidpicker/AndroidDropdownPickerProps.h b/ReactCommon/react/renderer/components/picker/androidpicker/react/renderer/components/androidpicker/AndroidDropdownPickerProps.h similarity index 100% rename from ReactCommon/react/renderer/components/picker/androidpicker/AndroidDropdownPickerProps.h rename to ReactCommon/react/renderer/components/picker/androidpicker/react/renderer/components/androidpicker/AndroidDropdownPickerProps.h diff --git a/ReactCommon/react/renderer/components/picker/androidpicker/AndroidDropdownPickerShadowNode.cpp b/ReactCommon/react/renderer/components/picker/androidpicker/react/renderer/components/androidpicker/AndroidDropdownPickerShadowNode.cpp similarity index 100% rename from ReactCommon/react/renderer/components/picker/androidpicker/AndroidDropdownPickerShadowNode.cpp rename to ReactCommon/react/renderer/components/picker/androidpicker/react/renderer/components/androidpicker/AndroidDropdownPickerShadowNode.cpp diff --git a/ReactCommon/react/renderer/components/picker/androidpicker/AndroidDropdownPickerShadowNode.h b/ReactCommon/react/renderer/components/picker/androidpicker/react/renderer/components/androidpicker/AndroidDropdownPickerShadowNode.h similarity index 100% rename from ReactCommon/react/renderer/components/picker/androidpicker/AndroidDropdownPickerShadowNode.h rename to ReactCommon/react/renderer/components/picker/androidpicker/react/renderer/components/androidpicker/AndroidDropdownPickerShadowNode.h From 6e13ca30158e2e293dcc43bcf6656f1f8312e3f3 Mon Sep 17 00:00:00 2001 From: David Vacca Date: Fri, 21 Aug 2020 14:15:17 -0700 Subject: [PATCH 0009/1238] Integrate Android Picker into RN Tester OSS app Summary: This diff integrates AndroidPicker into RN Tester OSS app changelog: [inernal] internal Reviewed By: fkgozali Differential Revision: D23199578 fbshipit-source-id: 7c34b0ee4887ffc15dbdffad464230b19f176fc8 --- .../com/facebook/react/fabric/jni/Android.mk | 3 +- .../java/com/facebook/react/fabric/jni/BUCK | 1 + .../fabric/jni/CoreComponentsRegistry.cpp | 6 +++ .../renderer/components/picker/Android.mk | 37 +++++++++++++++++++ 4 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 ReactCommon/react/renderer/components/picker/Android.mk diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Android.mk b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Android.mk index 3a607e1137f128..bc29dd15e88779 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Android.mk +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Android.mk @@ -11,7 +11,7 @@ LOCAL_MODULE := fabricjni LOCAL_SRC_FILES := $(wildcard $(LOCAL_PATH)/*.cpp) -LOCAL_SHARED_LIBRARIES := libreactconfig libreact_render_components_modal libyoga libglog libfb libfbjni libglog_init libfolly_json libfolly_futures libreact_render_mounting libreactnativeutilsjni libreact_utils libreact_render_debug libreact_render_graphics libreact_render_core libreact_render_mapbuffer react_render_componentregistry libreact_render_components_view libreact_render_components_unimplementedview libreact_render_components_root libreact_render_components_scrollview libbetter libreact_render_attributedstring libreact_render_uimanager libreact_render_templateprocessor libreact_render_scheduler libreact_render_animations libreact_render_imagemanager libreact_render_textlayoutmanager libreact_render_viewmanagers react_render_components_text libreact_render_components_image react_render_components_textinput +LOCAL_SHARED_LIBRARIES := libreactconfig libreact_render_components_modal libyoga libglog libfb libfbjni libglog_init libfolly_json libfolly_futures libreact_render_mounting libreactnativeutilsjni libreact_utils libreact_render_debug libreact_render_graphics libreact_render_core libreact_render_mapbuffer react_render_componentregistry libreact_render_components_view libreact_render_components_unimplementedview libreact_render_components_root libreact_render_components_scrollview libbetter libreact_render_attributedstring libreact_render_uimanager libreact_render_templateprocessor libreact_render_scheduler libreact_render_animations libreact_render_imagemanager libreact_render_textlayoutmanager libreact_render_viewmanagers react_render_components_text libreact_render_components_image react_render_components_textinput react_render_components_picker LOCAL_STATIC_LIBRARIES := @@ -42,6 +42,7 @@ $(call import-module,react/renderer/core) $(call import-module,react/renderer/components/image) $(call import-module,react/renderer/components/modal) $(call import-module,react/renderer/components/root) +$(call import-module,react/renderer/components/picker) $(call import-module,react/renderer/components/scrollview) $(call import-module,react/renderer/components/text) $(call import-module,react/renderer/components/textinput) diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/BUCK b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/BUCK index a6cab8b8310801..20bcef1c872c86 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/BUCK +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/BUCK @@ -48,6 +48,7 @@ rn_xplat_cxx_library( react_native_xplat_target("react/renderer/components/image:image"), react_native_xplat_target("react/renderer/components/text:text"), react_native_xplat_target("react/renderer/components/modal:modal"), + react_native_xplat_target("react/renderer/components/picker:androidpicker"), react_native_xplat_target("react/renderer/components/textinput:androidtextinput"), ], ) diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/CoreComponentsRegistry.cpp b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/CoreComponentsRegistry.cpp index 5e7df5bbd4aa46..7a02fc8fca499e 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/CoreComponentsRegistry.cpp +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/CoreComponentsRegistry.cpp @@ -12,6 +12,8 @@ #include #include +#include +#include #include #include #include @@ -55,6 +57,10 @@ CoreComponentsRegistry::sharedProviderRegistry() { concreteComponentDescriptorProvider()); providerRegistry->add(concreteComponentDescriptorProvider< AndroidDrawerLayoutComponentDescriptor>()); + providerRegistry->add(concreteComponentDescriptorProvider< + AndroidDialogPickerComponentDescriptor>()); + providerRegistry->add(concreteComponentDescriptorProvider< + AndroidDropdownPickerComponentDescriptor>()); return providerRegistry; }(); diff --git a/ReactCommon/react/renderer/components/picker/Android.mk b/ReactCommon/react/renderer/components/picker/Android.mk new file mode 100644 index 00000000000000..be55965cece467 --- /dev/null +++ b/ReactCommon/react/renderer/components/picker/Android.mk @@ -0,0 +1,37 @@ +# 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. + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := react_render_components_picker + +LOCAL_SRC_FILES := $(wildcard $(LOCAL_PATH)/androidpicker/react/renderer/components/androidpicker/*.cpp) + +LOCAL_C_INCLUDES := $(LOCAL_PATH)/androidpicker/react/renderer/components/androidpicker/ +LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/androidpicker/ + +LOCAL_CFLAGS := \ + -DLOG_TAG=\"Fabric\" + +LOCAL_CFLAGS += -fexceptions -frtti -std=c++14 -Wall + +LOCAL_STATIC_LIBRARIES := + +LOCAL_SHARED_LIBRARIES := libyoga glog libfolly_json libglog_init libreact_render_core libreact_render_debug libreact_render_graphics libreact_render_uimanager libreact_render_components_view libreact_render_componentregistry libreact_render_viewmanagers + +include $(BUILD_SHARED_LIBRARY) + +$(call import-module,glog) +$(call import-module,folly) +$(call import-module,fbgloginit) +$(call import-module,react/renderer/core) +$(call import-module,react/renderer/componentregistry) +$(call import-module,react/renderer/debug) +$(call import-module,react/renderer/graphics) +$(call import-module,react/renderer/uimanager) +$(call import-module,react/renderer/components/view) +$(call import-module,yogajni) From 6c7a8ce87d3ec5d29b220da1cfb1968e42c3a4fd Mon Sep 17 00:00:00 2001 From: David Vacca Date: Fri, 21 Aug 2020 14:15:17 -0700 Subject: [PATCH 0010/1238] Move Android Slider C++ files to make them compatible with RN Tester OSS build Summary: This diff moves Android Slider C++ files to make them compatible with RN Tester OSS build changelog: [internal] internal Reviewed By: JoshuaGross Differential Revision: D23227862 fbshipit-source-id: 7a5ed1bdc03cbe715467eddd4aad9af82761d4f0 --- ReactCommon/react/renderer/components/slider/BUCK | 6 +++--- .../components/slider}/SliderMeasurementsManager.cpp | 0 .../renderer/components/slider}/SliderMeasurementsManager.h | 0 3 files changed, 3 insertions(+), 3 deletions(-) rename ReactCommon/react/renderer/components/slider/platform/android/{ => react/renderer/components/slider}/SliderMeasurementsManager.cpp (100%) rename ReactCommon/react/renderer/components/slider/platform/android/{ => react/renderer/components/slider}/SliderMeasurementsManager.h (100%) diff --git a/ReactCommon/react/renderer/components/slider/BUCK b/ReactCommon/react/renderer/components/slider/BUCK index 05c3232fda5d3e..7030c52be1751f 100644 --- a/ReactCommon/react/renderer/components/slider/BUCK +++ b/ReactCommon/react/renderer/components/slider/BUCK @@ -46,15 +46,15 @@ rn_xplat_cxx_library( fbandroid_exported_headers = subdir_glob( [ ("", "*.h"), - ("platform/android", "*.h"), + ("platform/android/react/renderer/components/slider", "*.h"), ], prefix = "react/renderer/components/slider", ), fbandroid_headers = glob( - ["platform/android/*.h"], + ["platform/android/react/renderer/components/slider/*.h"], ), fbandroid_srcs = glob( - ["platform/android/*.cpp"], + ["platform/android/react/renderer/components/slider/*.cpp"], ), fbobjc_compiler_flags = APPLE_COMPILER_FLAGS, fbobjc_preprocessor_flags = get_preprocessor_flags_for_build_mode() + get_apple_inspector_flags(), diff --git a/ReactCommon/react/renderer/components/slider/platform/android/SliderMeasurementsManager.cpp b/ReactCommon/react/renderer/components/slider/platform/android/react/renderer/components/slider/SliderMeasurementsManager.cpp similarity index 100% rename from ReactCommon/react/renderer/components/slider/platform/android/SliderMeasurementsManager.cpp rename to ReactCommon/react/renderer/components/slider/platform/android/react/renderer/components/slider/SliderMeasurementsManager.cpp diff --git a/ReactCommon/react/renderer/components/slider/platform/android/SliderMeasurementsManager.h b/ReactCommon/react/renderer/components/slider/platform/android/react/renderer/components/slider/SliderMeasurementsManager.h similarity index 100% rename from ReactCommon/react/renderer/components/slider/platform/android/SliderMeasurementsManager.h rename to ReactCommon/react/renderer/components/slider/platform/android/react/renderer/components/slider/SliderMeasurementsManager.h From 6a4df5c9be18996954dbe88a97e15826bf051660 Mon Sep 17 00:00:00 2001 From: Rick Hanlon Date: Fri, 21 Aug 2020 14:56:29 -0700 Subject: [PATCH 0011/1238] Re-add changes to RNTester Summary: D23034761 (https://github.com/facebook/react-native/commit/63992c0b96ec45e4dfb37eaea8535c06833ab298) had a bad rebase and we lost some changes from the past week. Changelog: [Internal] Reviewed By: mdvacca Differential Revision: D23249804 fbshipit-source-id: 7433e1b7673bb6ec8c10fd33a34e94b0998b06d6 --- packages/rn-tester/android/app/build.gradle | 31 ++++++++++++------- .../react/uiapp/RNTesterApplication.java | 4 +-- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/packages/rn-tester/android/app/build.gradle b/packages/rn-tester/android/app/build.gradle index 38df57f3c6632b..3bad38b8dc353f 100644 --- a/packages/rn-tester/android/app/build.gradle +++ b/packages/rn-tester/android/app/build.gradle @@ -66,8 +66,8 @@ plugins { * // Root dir for all JS files for the app. Defaults to `root` above. * jsRootDir: "../..", * - * // Enable react-native-codegen during build time. - * enableCodegen: true, + * // Enable Fabric at build time and runtime. + * enableFabric: true, * * // Java package name to use for any codegen artifacts produced during build time. * // Defaults to "com.facebook.fbreact.specs". @@ -85,7 +85,7 @@ project.ext.react = [ hermesCommand: "$rootDir/node_modules/hermes-engine/%OS-BIN%/hermesc", enableHermesForVariant: { def v -> v.name.contains("hermes") }, jsRootDir: "$rootDir/RNTester", - enableCodegen: System.getenv('USE_CODEGEN'), + enableFabric: (System.getenv('USE_FABRIC') ?: '0').toBoolean(), ] apply from: "../../../../react.gradle" @@ -106,6 +106,11 @@ def enableSeparateBuildPerCPUArchitecture = true */ def enableProguardInReleaseBuilds = true +/** + * Build and enable Fabric in RN Tester app. + */ +def enableFabric = project.ext.react.enableFabric + /** * Use the international variant of JavaScriptCore * This variant includes the ICU i18n library to make APIs like `Date.toLocaleString` @@ -121,7 +126,9 @@ android { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } - + dexOptions { + javaMaxHeapSize "4g" + } flavorDimensions "vm" productFlavors { hermes { @@ -130,10 +137,6 @@ android { jsc { dimension "vm" } - fabric { - // TODO T71370706 - Create a different dimension to build fabric - dimension "vm" - } } defaultConfig { @@ -144,6 +147,7 @@ android { 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' + buildConfigField("boolean", "ENABLE_FABRIC", "$enableFabric") } signingConfigs { release { @@ -178,8 +182,6 @@ android { configurations { hermesDebugImplementation {} hermesReleaseImplementation {} - fabricDebugImplementation {} - fabricReleaseImplementation {} } dependencies { @@ -192,9 +194,7 @@ dependencies { def hermesPath = '$projectDir/../../../../../node_modules/hermes-engine/android/' hermesDebugImplementation files(hermesPath + "hermes-debug.aar") - fabricDebugImplementation files(hermesPath + "hermes-debug.aar") hermesReleaseImplementation files(hermesPath + "hermes-release.aar") - fabricReleaseImplementation files(hermesPath + "hermes-release.aar") debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") { exclude group:'com.facebook.fbjni' @@ -218,3 +218,10 @@ dependencies { androidTestImplementation('com.wix:detox:+') { transitive = true } androidTestImplementation 'junit:junit:4.12' } + +react { + enableCodegen = System.getenv("USE_CODEGEN") ?: false + jsRootDir = file("$rootDir/packages/rn-tester") + reactNativeRootDir = file("$rootDir") + useJavaGenerator = System.getenv("USE_CODEGEN_JAVAPOET") ?: false +} diff --git a/packages/rn-tester/android/app/src/main/java/com/facebook/react/uiapp/RNTesterApplication.java b/packages/rn-tester/android/app/src/main/java/com/facebook/react/uiapp/RNTesterApplication.java index a225306ddf1c3d..e9a946ee224f75 100644 --- a/packages/rn-tester/android/app/src/main/java/com/facebook/react/uiapp/RNTesterApplication.java +++ b/packages/rn-tester/android/app/src/main/java/com/facebook/react/uiapp/RNTesterApplication.java @@ -7,7 +7,7 @@ package com.facebook.react.uiapp; -import static com.facebook.react.uiapp.BuildConfig.FLAVOR; +import static com.facebook.react.uiapp.BuildConfig.ENABLE_FABRIC; import android.app.Application; import android.content.Context; @@ -38,7 +38,7 @@ public class RNTesterApplication extends Application implements ReactApplication { - static final boolean IS_FABRIC_ENABLED = FLAVOR.contains("fabric"); + static final boolean IS_FABRIC_ENABLED = ENABLE_FABRIC; private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) { From 55911eafb8e74e1b4199de196fcf58787f57bea5 Mon Sep 17 00:00:00 2001 From: Rick Hanlon Date: Fri, 21 Aug 2020 14:56:29 -0700 Subject: [PATCH 0012/1238] Add react back to dev dependencies for RNTester Summary: This is a partial revert of D23165627 (https://github.com/facebook/react-native/commit/f3930a93d5cf5f19058b0bfe453c7b9324eb8552) which broke RNTester testing internally. Changelog: [Internal] Reviewed By: mdvacca, cpojer Differential Revision: D23267175 fbshipit-source-id: d0d7010d00cf65497731dd973094fe334215044b --- package.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/package.json b/package.json index 05eb27d84fbb5c..d1db234a0ac755 100644 --- a/package.json +++ b/package.json @@ -118,6 +118,9 @@ "whatwg-fetch": "^3.0.0", "ws": "^6.1.4" }, + "devDependencies": { + "react": "16.13.1" + }, "detox": { "test-runner": "jest", "runner-config": "packages/rn-tester/e2e/config.json", From be53aae324546ca038e2b58184ecc7066cfb598e Mon Sep 17 00:00:00 2001 From: Neil Dhar Date: Fri, 21 Aug 2020 16:46:21 -0700 Subject: [PATCH 0013/1238] Fix task ordering for including Hermes Summary: Fix a failure in running a single command to clean and rebuild with Hermes (e.g. `./gradlew clean :RNTester:android:app:installHermesDebug`). From my limited understanding of Gradle, the failure was caused by the fact that the `clean` task could end up running after `prepareHermes`, and therefore delete the shared library after it had been copied. This change updates the `prepareHermes` task to impose the proper order. In investigating this failure, I also updated inconsistent use of the `$thirdPartyNdkDir` variable. Changelog: [Internal][Fixed] Fix a failure in running a single command to clean and rebuild ReactAndroid with Hermes Reviewed By: mdvacca Differential Revision: D23098220 fbshipit-source-id: 822fa8ac9874d54a3fdd432ad8cbee78295228ee --- ReactAndroid/build.gradle | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/ReactAndroid/build.gradle b/ReactAndroid/build.gradle index 94b58475bdff2f..1189ead6e9a4c4 100644 --- a/ReactAndroid/build.gradle +++ b/ReactAndroid/build.gradle @@ -101,7 +101,7 @@ task prepareFolly(dependsOn: dependenciesPath ? [] : [downloadFolly], type: Copy into("$thirdPartyNdkDir/folly") } -task prepareHermes() { +task prepareHermes(dependsOn: createNativeDepsDirectories, type: Copy) { def hermesPackagePath = findNodeModulePath(projectDir, "hermes-engine") if (!hermesPackagePath) { throw new GradleScriptException("Could not find the hermes-engine npm package", null) @@ -114,11 +114,9 @@ task prepareHermes() { def soFiles = zipTree(hermesAAR).matching({ it.include "**/*.so" }) - copy { - from soFiles - from "src/main/jni/first-party/hermes/Android.mk" - into "$thirdPartyNdkDir/hermes" - } + from soFiles + from "src/main/jni/first-party/hermes/Android.mk" + into "$thirdPartyNdkDir/hermes" } task downloadGlog(dependsOn: createNativeDepsDirectories, type: Download) { @@ -314,7 +312,7 @@ def buildReactNdkLib = tasks.register("buildReactNdkLib", Exec) { "NDK_APPLICATION_MK=$projectDir/src/main/jni/Application.mk", "NDK_OUT=" + temporaryDir, "NDK_LIBS_OUT=$buildDir/react-ndk/all", - "THIRD_PARTY_NDK_DIR=$buildDir/third-party-ndk", + "THIRD_PARTY_NDK_DIR=$thirdPartyNdkDir", "REACT_COMMON_DIR=$projectDir/../ReactCommon", "REACT_SRC_DIR=$projectDir/src/main/java/com/facebook/react", "BUILD_FABRIC=$enableFabric", @@ -328,7 +326,7 @@ def cleanReactNdkLib = tasks.register("cleanReactNdkLib", Exec) { errorOutput(new ByteArrayOutputStream()) commandLine(getNdkBuildFullPath(), "NDK_APPLICATION_MK=$projectDir/src/main/jni/Application.mk", - "THIRD_PARTY_NDK_DIR=$buildDir/third-party-ndk", + "THIRD_PARTY_NDK_DIR=$thirdPartyNdkDir", "REACT_COMMON_DIR=$projectDir/../ReactCommon", "-C", file("src/main/jni/react/jni").absolutePath, "clean") From f0ebfe380c8104c7ec0a944d298c50bf8ec026eb Mon Sep 17 00:00:00 2001 From: Lulu Wu Date: Fri, 21 Aug 2020 17:16:48 -0700 Subject: [PATCH 0014/1238] Convert RCTFileReaderModule to avoid using bridge Summary: Changelog: [iOS][Changed] - DescriptionConvert RCTFileReaderModule to avoid using bridge Reviewed By: PeteTheHeat Differential Revision: D23264211 fbshipit-source-id: 7d92749238aa45b4ff1b39c961e1b471f15df252 --- Libraries/Blob/RCTFileReaderModule.mm | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Libraries/Blob/RCTFileReaderModule.mm b/Libraries/Blob/RCTFileReaderModule.mm index 62e817dc487aed..315605acc1174d 100644 --- a/Libraries/Blob/RCTFileReaderModule.mm +++ b/Libraries/Blob/RCTFileReaderModule.mm @@ -24,6 +24,7 @@ @implementation RCTFileReaderModule RCT_EXPORT_MODULE(FileReaderModule) @synthesize bridge = _bridge; +@synthesize turboModuleRegistry = _turboModuleRegistry; RCT_EXPORT_METHOD(readAsText:(NSDictionary *)blob encoding:(NSString *)encoding @@ -55,7 +56,12 @@ @implementation RCTFileReaderModule resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) { - RCTBlobManager *blobManager = [[self bridge] moduleForClass:[RCTBlobManager class]]; + RCTBlobManager *blobManager = nil; + if ([self bridge]) { + blobManager = [[self bridge] moduleForClass:[RCTBlobManager class]]; + } else { + blobManager = [[self turboModuleRegistry] moduleForName:[NSStringFromClass([RCTBlobManager class]) UTF8String]]; + } NSData *data = [blobManager resolve:blob]; if (data == nil) { From 82deeaff2654cb37e2d6a5572d6a4dce3852626d Mon Sep 17 00:00:00 2001 From: David Vacca Date: Fri, 21 Aug 2020 22:27:15 -0700 Subject: [PATCH 0015/1238] Integrate Slider into RN Tester OSS Android app Summary: This diff integrates Slider View Manager into RN Tester OSS Android app Changelog: [Internal] internal Reviewed By: fkgozali Differential Revision: D23227858 fbshipit-source-id: d785dbdaa3e05e0dfcd7c2134769eaba72f40977 --- .../com/facebook/react/fabric/jni/Android.mk | 3 +- .../java/com/facebook/react/fabric/jni/BUCK | 3 +- .../fabric/jni/CoreComponentsRegistry.cpp | 3 ++ .../renderer/components/slider/Android.mk | 40 +++++++++++++++++++ 4 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 ReactCommon/react/renderer/components/slider/Android.mk diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Android.mk b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Android.mk index bc29dd15e88779..3f2fcd196ae852 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Android.mk +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Android.mk @@ -11,7 +11,7 @@ LOCAL_MODULE := fabricjni LOCAL_SRC_FILES := $(wildcard $(LOCAL_PATH)/*.cpp) -LOCAL_SHARED_LIBRARIES := libreactconfig libreact_render_components_modal libyoga libglog libfb libfbjni libglog_init libfolly_json libfolly_futures libreact_render_mounting libreactnativeutilsjni libreact_utils libreact_render_debug libreact_render_graphics libreact_render_core libreact_render_mapbuffer react_render_componentregistry libreact_render_components_view libreact_render_components_unimplementedview libreact_render_components_root libreact_render_components_scrollview libbetter libreact_render_attributedstring libreact_render_uimanager libreact_render_templateprocessor libreact_render_scheduler libreact_render_animations libreact_render_imagemanager libreact_render_textlayoutmanager libreact_render_viewmanagers react_render_components_text libreact_render_components_image react_render_components_textinput react_render_components_picker +LOCAL_SHARED_LIBRARIES := libreactconfig libreact_render_components_slider libreact_render_components_modal libyoga libglog libfb libfbjni libglog_init libfolly_json libfolly_futures libreact_render_mounting libreactnativeutilsjni libreact_utils libreact_render_debug libreact_render_graphics libreact_render_core libreact_render_mapbuffer react_render_componentregistry libreact_render_components_view libreact_render_components_unimplementedview libreact_render_components_root libreact_render_components_scrollview libbetter libreact_render_attributedstring libreact_render_uimanager libreact_render_templateprocessor libreact_render_scheduler libreact_render_animations libreact_render_imagemanager libreact_render_textlayoutmanager libreact_render_viewmanagers react_render_components_text libreact_render_components_image react_render_components_textinput react_render_components_picker LOCAL_STATIC_LIBRARIES := @@ -44,6 +44,7 @@ $(call import-module,react/renderer/components/modal) $(call import-module,react/renderer/components/root) $(call import-module,react/renderer/components/picker) $(call import-module,react/renderer/components/scrollview) +$(call import-module,react/renderer/components/slider) $(call import-module,react/renderer/components/text) $(call import-module,react/renderer/components/textinput) $(call import-module,react/renderer/components/unimplementedview) diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/BUCK b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/BUCK index 20bcef1c872c86..1eda3de5d5ac0e 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/BUCK +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/BUCK @@ -46,9 +46,10 @@ rn_xplat_cxx_library( # The following dependencies are required by CoreComponentsRegistry "//xplat/js/react-native-github:generated_components-rncore", react_native_xplat_target("react/renderer/components/image:image"), - react_native_xplat_target("react/renderer/components/text:text"), react_native_xplat_target("react/renderer/components/modal:modal"), react_native_xplat_target("react/renderer/components/picker:androidpicker"), + react_native_xplat_target("react/renderer/components/slider:slider"), + react_native_xplat_target("react/renderer/components/text:text"), react_native_xplat_target("react/renderer/components/textinput:androidtextinput"), ], ) diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/CoreComponentsRegistry.cpp b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/CoreComponentsRegistry.cpp index 7a02fc8fca499e..2f60069ebfe665 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/CoreComponentsRegistry.cpp +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/CoreComponentsRegistry.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -51,6 +52,8 @@ CoreComponentsRegistry::sharedProviderRegistry() { concreteComponentDescriptorProvider()); providerRegistry->add( concreteComponentDescriptorProvider()); + providerRegistry->add( + concreteComponentDescriptorProvider()); providerRegistry->add( concreteComponentDescriptorProvider()); providerRegistry->add( diff --git a/ReactCommon/react/renderer/components/slider/Android.mk b/ReactCommon/react/renderer/components/slider/Android.mk new file mode 100644 index 00000000000000..23e58023b81d81 --- /dev/null +++ b/ReactCommon/react/renderer/components/slider/Android.mk @@ -0,0 +1,40 @@ +# 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. + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := react_render_components_slider + +LOCAL_SRC_FILES := $(wildcard $(LOCAL_PATH)/*.cpp) $(wildcard $(LOCAL_PATH)/platform/android/react/renderer/components/slider/*.cpp) + +LOCAL_C_INCLUDES := $(LOCAL_PATH)/ $(LOCAL_PATH)/platform/android/ +LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/../../../../ $(LOCAL_PATH)/platform/android/ + +LOCAL_CFLAGS := \ + -DLOG_TAG=\"Fabric\" + +LOCAL_CFLAGS += -fexceptions -frtti -std=c++14 -Wall + +LOCAL_STATIC_LIBRARIES := + +LOCAL_SHARED_LIBRARIES := libfbjni libreact_render_viewmanagers libreact_render_imagemanager libreactnativeutilsjni libreact_render_componentregistry libreact_render_uimanager libreact_render_components_image libyoga libfolly_futures glog libfolly_json libglog_init libreact_render_core libreact_render_debug libreact_render_graphics libreact_render_components_view + +include $(BUILD_SHARED_LIBRARY) + +$(call import-module,fbjni) +$(call import-module,folly) +$(call import-module,fbgloginit) +$(call import-module,glog) +$(call import-module,react/renderer/componentregistry) +$(call import-module,react/renderer/core) +$(call import-module,react/renderer/debug) +$(call import-module,react/renderer/graphics) +$(call import-module,react/renderer/imagemanager) +$(call import-module,react/renderer/components/image) +$(call import-module,react/renderer/components/view) +$(call import-module,react/renderer/uimanager) +$(call import-module,yogajni) From cae68718ba579f26d4496f024252c1be49a25b4f Mon Sep 17 00:00:00 2001 From: David Vacca Date: Fri, 21 Aug 2020 22:27:15 -0700 Subject: [PATCH 0016/1238] Move AndroidSwitch C++ files to make them compatible with RN OSS Build Summary: This diff moves AndroidSwitch C++ files to make them compatible with RN OSS Build Changelog: [Internal] internal Reviewed By: PeteTheHeat Differential Revision: D23227861 fbshipit-source-id: 8f23c2eb266a47cb9af82f4159f64b987c14141b --- ReactCommon/react/renderer/components/switch/BUCK | 6 +++--- .../androidswitch}/AndroidSwitchComponentDescriptor.h | 0 .../androidswitch}/AndroidSwitchMeasurementsManager.cpp | 0 .../androidswitch}/AndroidSwitchMeasurementsManager.h | 0 .../components/androidswitch}/AndroidSwitchShadowNode.cpp | 0 .../components/androidswitch}/AndroidSwitchShadowNode.h | 0 6 files changed, 3 insertions(+), 3 deletions(-) rename ReactCommon/react/renderer/components/switch/androidswitch/{ => react/renderer/components/androidswitch}/AndroidSwitchComponentDescriptor.h (100%) rename ReactCommon/react/renderer/components/switch/androidswitch/{ => react/renderer/components/androidswitch}/AndroidSwitchMeasurementsManager.cpp (100%) rename ReactCommon/react/renderer/components/switch/androidswitch/{ => react/renderer/components/androidswitch}/AndroidSwitchMeasurementsManager.h (100%) rename ReactCommon/react/renderer/components/switch/androidswitch/{ => react/renderer/components/androidswitch}/AndroidSwitchShadowNode.cpp (100%) rename ReactCommon/react/renderer/components/switch/androidswitch/{ => react/renderer/components/androidswitch}/AndroidSwitchShadowNode.h (100%) diff --git a/ReactCommon/react/renderer/components/switch/BUCK b/ReactCommon/react/renderer/components/switch/BUCK index 67b258e98a6670..fa27ee25fe0f59 100644 --- a/ReactCommon/react/renderer/components/switch/BUCK +++ b/ReactCommon/react/renderer/components/switch/BUCK @@ -19,18 +19,18 @@ APPLE_COMPILER_FLAGS = get_apple_compiler_flags() rn_xplat_cxx_library( name = "androidswitch", srcs = glob( - ["**/*.cpp"], + ["androidswitch/react/renderer/components/androidswitch/*.cpp"], exclude = glob(["tests/**/*.cpp"]), ), headers = glob( - ["**/*.h"], + ["androidswitch/react/renderer/components/androidswitch/*.h"], exclude = glob(["tests/**/*.h"]), ), header_namespace = "", exported_headers = subdir_glob( [ ("", "*.h"), - ("androidswitch", "*.h"), + ("androidswitch/react/renderer/components/androidswitch", "*.h"), ], prefix = "react/renderer/components/androidswitch", ), diff --git a/ReactCommon/react/renderer/components/switch/androidswitch/AndroidSwitchComponentDescriptor.h b/ReactCommon/react/renderer/components/switch/androidswitch/react/renderer/components/androidswitch/AndroidSwitchComponentDescriptor.h similarity index 100% rename from ReactCommon/react/renderer/components/switch/androidswitch/AndroidSwitchComponentDescriptor.h rename to ReactCommon/react/renderer/components/switch/androidswitch/react/renderer/components/androidswitch/AndroidSwitchComponentDescriptor.h diff --git a/ReactCommon/react/renderer/components/switch/androidswitch/AndroidSwitchMeasurementsManager.cpp b/ReactCommon/react/renderer/components/switch/androidswitch/react/renderer/components/androidswitch/AndroidSwitchMeasurementsManager.cpp similarity index 100% rename from ReactCommon/react/renderer/components/switch/androidswitch/AndroidSwitchMeasurementsManager.cpp rename to ReactCommon/react/renderer/components/switch/androidswitch/react/renderer/components/androidswitch/AndroidSwitchMeasurementsManager.cpp diff --git a/ReactCommon/react/renderer/components/switch/androidswitch/AndroidSwitchMeasurementsManager.h b/ReactCommon/react/renderer/components/switch/androidswitch/react/renderer/components/androidswitch/AndroidSwitchMeasurementsManager.h similarity index 100% rename from ReactCommon/react/renderer/components/switch/androidswitch/AndroidSwitchMeasurementsManager.h rename to ReactCommon/react/renderer/components/switch/androidswitch/react/renderer/components/androidswitch/AndroidSwitchMeasurementsManager.h diff --git a/ReactCommon/react/renderer/components/switch/androidswitch/AndroidSwitchShadowNode.cpp b/ReactCommon/react/renderer/components/switch/androidswitch/react/renderer/components/androidswitch/AndroidSwitchShadowNode.cpp similarity index 100% rename from ReactCommon/react/renderer/components/switch/androidswitch/AndroidSwitchShadowNode.cpp rename to ReactCommon/react/renderer/components/switch/androidswitch/react/renderer/components/androidswitch/AndroidSwitchShadowNode.cpp diff --git a/ReactCommon/react/renderer/components/switch/androidswitch/AndroidSwitchShadowNode.h b/ReactCommon/react/renderer/components/switch/androidswitch/react/renderer/components/androidswitch/AndroidSwitchShadowNode.h similarity index 100% rename from ReactCommon/react/renderer/components/switch/androidswitch/AndroidSwitchShadowNode.h rename to ReactCommon/react/renderer/components/switch/androidswitch/react/renderer/components/androidswitch/AndroidSwitchShadowNode.h From 57798408a32c8f51044f5e2087602cff69489e9d Mon Sep 17 00:00:00 2001 From: David Vacca Date: Fri, 21 Aug 2020 22:27:15 -0700 Subject: [PATCH 0017/1238] Integrate Android Switch into RN Tester Android OSS app Summary: This diff integrates Android Switch into RN Tester Android OSS app Changelog: [Internal] internal Reviewed By: fkgozali Differential Revision: D23227856 fbshipit-source-id: 0ef74456a15827f1aaa9e5b2aefb9c692cc1d1f4 --- .../com/facebook/react/fabric/jni/Android.mk | 3 +- .../java/com/facebook/react/fabric/jni/BUCK | 1 + .../fabric/jni/CoreComponentsRegistry.cpp | 3 ++ .../renderer/components/switch/Android.mk | 38 +++++++++++++++++++ 4 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 ReactCommon/react/renderer/components/switch/Android.mk diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Android.mk b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Android.mk index 3f2fcd196ae852..6ee21a2d0224ed 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Android.mk +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Android.mk @@ -11,7 +11,7 @@ LOCAL_MODULE := fabricjni LOCAL_SRC_FILES := $(wildcard $(LOCAL_PATH)/*.cpp) -LOCAL_SHARED_LIBRARIES := libreactconfig libreact_render_components_slider libreact_render_components_modal libyoga libglog libfb libfbjni libglog_init libfolly_json libfolly_futures libreact_render_mounting libreactnativeutilsjni libreact_utils libreact_render_debug libreact_render_graphics libreact_render_core libreact_render_mapbuffer react_render_componentregistry libreact_render_components_view libreact_render_components_unimplementedview libreact_render_components_root libreact_render_components_scrollview libbetter libreact_render_attributedstring libreact_render_uimanager libreact_render_templateprocessor libreact_render_scheduler libreact_render_animations libreact_render_imagemanager libreact_render_textlayoutmanager libreact_render_viewmanagers react_render_components_text libreact_render_components_image react_render_components_textinput react_render_components_picker +LOCAL_SHARED_LIBRARIES := libreactconfig libreact_render_components_slider libreact_render_components_switch libreact_render_components_modal libyoga libglog libfb libfbjni libglog_init libfolly_json libfolly_futures libreact_render_mounting libreactnativeutilsjni libreact_utils libreact_render_debug libreact_render_graphics libreact_render_core libreact_render_mapbuffer react_render_componentregistry libreact_render_components_view libreact_render_components_unimplementedview libreact_render_components_root libreact_render_components_scrollview libbetter libreact_render_attributedstring libreact_render_uimanager libreact_render_templateprocessor libreact_render_scheduler libreact_render_animations libreact_render_imagemanager libreact_render_textlayoutmanager libreact_render_viewmanagers react_render_components_text libreact_render_components_image react_render_components_textinput react_render_components_picker LOCAL_STATIC_LIBRARIES := @@ -45,6 +45,7 @@ $(call import-module,react/renderer/components/root) $(call import-module,react/renderer/components/picker) $(call import-module,react/renderer/components/scrollview) $(call import-module,react/renderer/components/slider) +$(call import-module,react/renderer/components/switch) $(call import-module,react/renderer/components/text) $(call import-module,react/renderer/components/textinput) $(call import-module,react/renderer/components/unimplementedview) diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/BUCK b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/BUCK index 1eda3de5d5ac0e..92380fa7168bc1 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/BUCK +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/BUCK @@ -49,6 +49,7 @@ rn_xplat_cxx_library( react_native_xplat_target("react/renderer/components/modal:modal"), react_native_xplat_target("react/renderer/components/picker:androidpicker"), react_native_xplat_target("react/renderer/components/slider:slider"), + react_native_xplat_target("react/renderer/components/switch:androidswitch"), react_native_xplat_target("react/renderer/components/text:text"), react_native_xplat_target("react/renderer/components/textinput:androidtextinput"), ], diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/CoreComponentsRegistry.cpp b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/CoreComponentsRegistry.cpp index 2f60069ebfe665..5824556162def5 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/CoreComponentsRegistry.cpp +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/CoreComponentsRegistry.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -48,6 +49,8 @@ CoreComponentsRegistry::sharedProviderRegistry() { concreteComponentDescriptorProvider()); providerRegistry->add(concreteComponentDescriptorProvider< ModalHostViewComponentDescriptor>()); + providerRegistry->add(concreteComponentDescriptorProvider< + AndroidSwitchComponentDescriptor>()); providerRegistry->add( concreteComponentDescriptorProvider()); providerRegistry->add( diff --git a/ReactCommon/react/renderer/components/switch/Android.mk b/ReactCommon/react/renderer/components/switch/Android.mk new file mode 100644 index 00000000000000..65be95635a04d8 --- /dev/null +++ b/ReactCommon/react/renderer/components/switch/Android.mk @@ -0,0 +1,38 @@ +# 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. + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := react_render_components_switch + +LOCAL_SRC_FILES := $(wildcard $(LOCAL_PATH)/androidswitch/react/renderer/components/androidswitch/*.cpp) + +LOCAL_C_INCLUDES := $(LOCAL_PATH)/androidswitch/ +LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/androidswitch/ + +LOCAL_CFLAGS := \ + -DLOG_TAG=\"Fabric\" + +LOCAL_CFLAGS += -fexceptions -frtti -std=c++14 -Wall + +LOCAL_STATIC_LIBRARIES := + +LOCAL_SHARED_LIBRARIES := libfbjni libreact_render_viewmanagers libreactnativeutilsjni libreact_render_componentregistry libreact_render_uimanager libyoga libfolly_futures glog libfolly_json libglog_init libreact_render_core libreact_render_debug libreact_render_graphics libreact_render_components_view + +include $(BUILD_SHARED_LIBRARY) + +$(call import-module,fbjni) +$(call import-module,folly) +$(call import-module,fbgloginit) +$(call import-module,glog) +$(call import-module,react/renderer/componentregistry) +$(call import-module,react/renderer/core) +$(call import-module,react/renderer/debug) +$(call import-module,react/renderer/graphics) +$(call import-module,react/renderer/components/view) +$(call import-module,react/renderer/uimanager) +$(call import-module,yogajni) From 2d34c221f2ae37a4918c49920dafa160f05fcf3b Mon Sep 17 00:00:00 2001 From: David Vacca Date: Fri, 21 Aug 2020 22:27:15 -0700 Subject: [PATCH 0018/1238] Integrate AndroidSwipeRefreshLayout into RN Tester Android OSS app Summary: This diff integrates AndroidSwipeRefreshLayout into RN Tester Android OSS app Changelog: [Internal] internal Reviewed By: fkgozali Differential Revision: D23227855 fbshipit-source-id: 52bb457d655500b60614dfa3512b5173516f8483 --- .../com/facebook/react/fabric/jni/CoreComponentsRegistry.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/CoreComponentsRegistry.cpp b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/CoreComponentsRegistry.cpp index 5824556162def5..fa4802913b8a17 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/CoreComponentsRegistry.cpp +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/CoreComponentsRegistry.cpp @@ -39,6 +39,8 @@ CoreComponentsRegistry::sharedProviderRegistry() { auto providerRegistry = std::make_shared(); + providerRegistry->add(concreteComponentDescriptorProvider< + AndroidSwipeRefreshLayoutComponentDescriptor>()); providerRegistry->add(concreteComponentDescriptorProvider< ActivityIndicatorViewComponentDescriptor>()); providerRegistry->add(concreteComponentDescriptorProvider< From 6aa63272dcbe4bfbfe21b175ea7fa84708a4ef66 Mon Sep 17 00:00:00 2001 From: Paige Sun Date: Sat, 22 Aug 2020 01:17:11 -0700 Subject: [PATCH 0019/1238] Create internal Fabric subclass of RCTImageComponentView Summary: Changelog: [Internal] Create internal Fabric subclass of RCTImageComponentView Reviewed By: sammy-SC Differential Revision: D23211115 fbshipit-source-id: 0e756de3f3e555bf212dc88dfc8c32930ac85132 --- .../ComponentViews/Image/RCTImageComponentView.mm | 15 ++++++++++++--- .../ComponentViews/RCTFabricComponentsPlugins.h | 1 - .../ComponentViews/RCTFabricComponentsPlugins.mm | 1 - .../ComponentViews/View/RCTViewComponentView.mm | 15 ++++++++++++--- 4 files changed, 24 insertions(+), 8 deletions(-) diff --git a/React/Fabric/Mounting/ComponentViews/Image/RCTImageComponentView.mm b/React/Fabric/Mounting/ComponentViews/Image/RCTImageComponentView.mm index fbef56afa10e5d..e617f20b72c702 100644 --- a/React/Fabric/Mounting/ComponentViews/Image/RCTImageComponentView.mm +++ b/React/Fabric/Mounting/ComponentViews/Image/RCTImageComponentView.mm @@ -7,6 +7,7 @@ #import "RCTImageComponentView.h" +#import #import #import #import @@ -18,9 +19,6 @@ #import #import -#import "RCTConversions.h" -#import "RCTFabricComponentsPlugins.h" - using namespace facebook::react; @interface RCTImageComponentView () @@ -209,6 +207,17 @@ - (void)didReceiveFailureFromObserver:(void const *)observer @end +#ifdef __cplusplus +extern "C" { +#endif + +// Can't the import generated Plugin.h because plugins are not in this BUCK target +Class RCTImageCls(void); + +#ifdef __cplusplus +} +#endif + Class RCTImageCls(void) { return RCTImageComponentView.class; diff --git a/React/Fabric/Mounting/ComponentViews/RCTFabricComponentsPlugins.h b/React/Fabric/Mounting/ComponentViews/RCTFabricComponentsPlugins.h index fa7984df03a481..4f6ea0e815679c 100644 --- a/React/Fabric/Mounting/ComponentViews/RCTFabricComponentsPlugins.h +++ b/React/Fabric/Mounting/ComponentViews/RCTFabricComponentsPlugins.h @@ -36,7 +36,6 @@ Class RCTActivityIndicatorViewCls(void) __attribute__( Class RCTSliderCls(void) __attribute__((used)); Class RCTSwitchCls(void) __attribute__((used)); Class RCTUnimplementedNativeViewCls(void) __attribute__((used)); -Class RCTImageCls(void) __attribute__((used)); Class RCTParagraphCls(void) __attribute__((used)); Class RCTTextInputCls(void) __attribute__((used)); Class RCTInputAccessoryCls(void) __attribute__((used)); diff --git a/React/Fabric/Mounting/ComponentViews/RCTFabricComponentsPlugins.mm b/React/Fabric/Mounting/ComponentViews/RCTFabricComponentsPlugins.mm index c8bee6acfce398..a52c8c06e366da 100644 --- a/React/Fabric/Mounting/ComponentViews/RCTFabricComponentsPlugins.mm +++ b/React/Fabric/Mounting/ComponentViews/RCTFabricComponentsPlugins.mm @@ -25,7 +25,6 @@ {"Slider", RCTSliderCls}, {"Switch", RCTSwitchCls}, {"UnimplementedNativeView", RCTUnimplementedNativeViewCls}, - {"Image", RCTImageCls}, {"Paragraph", RCTParagraphCls}, {"TextInput", RCTTextInputCls}, {"InputAccessoryView", RCTInputAccessoryCls}, diff --git a/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm b/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm index 1b6c81c167964a..e5c7e6a85375fb 100644 --- a/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm +++ b/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm @@ -9,14 +9,12 @@ #import #import +#import #import #import #import #import -#import "RCTConversions.h" -#import "RCTFabricComponentsPlugins.h" - using namespace facebook::react; @implementation RCTViewComponentView { @@ -622,6 +620,17 @@ - (NSString *)componentViewName_DO_NOT_USE_THIS_IS_BROKEN @end +#ifdef __cplusplus +extern "C" { +#endif + +// Can't the import generated Plugin.h because plugins are not in this BUCK target +Class RCTViewCls(void); + +#ifdef __cplusplus +} +#endif + Class RCTViewCls(void) { return RCTViewComponentView.class; From 62de5c001c1d5cf9435cb2ceab70a43a2f9dc3b1 Mon Sep 17 00:00:00 2001 From: David Vacca Date: Sat, 22 Aug 2020 01:43:55 -0700 Subject: [PATCH 0020/1238] Migrate AndroidProgressBarComponent to Fabric Summary: This diff migrates AndroidProgressBar component to Fabric changeLog: [internal] internal Reviewed By: sammy-SC Differential Revision: D23227857 fbshipit-source-id: c5cbbdcc36e63226286cd714d601f0d4690496b2 --- .../ProgressBarAndroidNativeComponent.js | 6 +- .../components/rncore/ComponentDescriptors.h | 1 - .../components/rncore/ShadowNodes.cpp | 1 - .../renderer/components/rncore/ShadowNodes.h | 9 -- .../ReactProgressBarViewManager.java | 40 ++++++ .../ComponentDescriptorRegistry.cpp | 4 - .../renderer/components/progressbar/BUCK | 121 ++++++++++++++++++ .../AndroidProgressBarComponentDescriptor.h | 53 ++++++++ .../AndroidProgressBarMeasurementsManager.cpp | 75 +++++++++++ .../AndroidProgressBarMeasurementsManager.h | 38 ++++++ .../AndroidProgressBarShadowNode.cpp | 35 +++++ .../AndroidProgressBarShadowNode.h | 46 +++++++ .../components/progressbar/conversions.h | 30 +++++ 13 files changed, 441 insertions(+), 18 deletions(-) create mode 100644 ReactCommon/react/renderer/components/progressbar/BUCK create mode 100644 ReactCommon/react/renderer/components/progressbar/android/react/renderer/components/progressbar/AndroidProgressBarComponentDescriptor.h create mode 100644 ReactCommon/react/renderer/components/progressbar/android/react/renderer/components/progressbar/AndroidProgressBarMeasurementsManager.cpp create mode 100644 ReactCommon/react/renderer/components/progressbar/android/react/renderer/components/progressbar/AndroidProgressBarMeasurementsManager.h create mode 100644 ReactCommon/react/renderer/components/progressbar/android/react/renderer/components/progressbar/AndroidProgressBarShadowNode.cpp create mode 100644 ReactCommon/react/renderer/components/progressbar/android/react/renderer/components/progressbar/AndroidProgressBarShadowNode.h create mode 100644 ReactCommon/react/renderer/components/progressbar/android/react/renderer/components/progressbar/conversions.h diff --git a/Libraries/Components/ProgressBarAndroid/ProgressBarAndroidNativeComponent.js b/Libraries/Components/ProgressBarAndroid/ProgressBarAndroidNativeComponent.js index c3efe138a71653..0274e5866792e0 100644 --- a/Libraries/Components/ProgressBarAndroid/ProgressBarAndroidNativeComponent.js +++ b/Libraries/Components/ProgressBarAndroid/ProgressBarAndroidNativeComponent.js @@ -30,6 +30,6 @@ type NativeProps = $ReadOnly<{| testID?: WithDefault, |}>; -export default (codegenNativeComponent( - 'AndroidProgressBar', -): HostComponent); +export default (codegenNativeComponent('AndroidProgressBar', { + interfaceOnly: true, +}): HostComponent); diff --git a/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/jni/react/renderer/components/rncore/ComponentDescriptors.h b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/jni/react/renderer/components/rncore/ComponentDescriptors.h index a8efdeaed7cb35..cc3c195dd3a24f 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/jni/react/renderer/components/rncore/ComponentDescriptors.h +++ b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/jni/react/renderer/components/rncore/ComponentDescriptors.h @@ -20,7 +20,6 @@ using ActivityIndicatorViewComponentDescriptor = ConcreteComponentDescriptor; using AndroidDrawerLayoutComponentDescriptor = ConcreteComponentDescriptor; using RCTMaskedViewComponentDescriptor = ConcreteComponentDescriptor; -using AndroidProgressBarComponentDescriptor = ConcreteComponentDescriptor; using RCTProgressViewComponentDescriptor = ConcreteComponentDescriptor; using AndroidSwipeRefreshLayoutComponentDescriptor = ConcreteComponentDescriptor; using PullToRefreshViewComponentDescriptor = ConcreteComponentDescriptor; diff --git a/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/jni/react/renderer/components/rncore/ShadowNodes.cpp b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/jni/react/renderer/components/rncore/ShadowNodes.cpp index 767f4779ed1bfb..befdb19c30df35 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/jni/react/renderer/components/rncore/ShadowNodes.cpp +++ b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/jni/react/renderer/components/rncore/ShadowNodes.cpp @@ -17,7 +17,6 @@ extern const char ActivityIndicatorViewComponentName[] = "ActivityIndicatorView" extern const char DatePickerComponentName[] = "DatePicker"; extern const char AndroidDrawerLayoutComponentName[] = "AndroidDrawerLayout"; extern const char RCTMaskedViewComponentName[] = "RCTMaskedView"; -extern const char AndroidProgressBarComponentName[] = "AndroidProgressBar"; extern const char RCTProgressViewComponentName[] = "RCTProgressView"; extern const char AndroidSwipeRefreshLayoutComponentName[] = "AndroidSwipeRefreshLayout"; extern const char PullToRefreshViewComponentName[] = "PullToRefreshView"; diff --git a/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/jni/react/renderer/components/rncore/ShadowNodes.h b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/jni/react/renderer/components/rncore/ShadowNodes.h index 748f811c69dae4..f8a84f5836b01b 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/jni/react/renderer/components/rncore/ShadowNodes.h +++ b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/jni/react/renderer/components/rncore/ShadowNodes.h @@ -55,15 +55,6 @@ using RCTMaskedViewShadowNode = ConcreteViewShadowNode< RCTMaskedViewComponentName, RCTMaskedViewProps>; -extern const char AndroidProgressBarComponentName[]; - -/* - * `ShadowNode` for component. - */ -using AndroidProgressBarShadowNode = ConcreteViewShadowNode< - AndroidProgressBarComponentName, - AndroidProgressBarProps>; - extern const char RCTProgressViewComponentName[]; /* diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/progressbar/ReactProgressBarViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/progressbar/ReactProgressBarViewManager.java index 12ff350d0688bb..aae6bd5cfc43ef 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/progressbar/ReactProgressBarViewManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/progressbar/ReactProgressBarViewManager.java @@ -8,17 +8,25 @@ package com.facebook.react.views.progressbar; import android.content.Context; +import android.util.Pair; +import android.view.View; +import android.view.ViewGroup; import android.widget.ProgressBar; import androidx.annotation.Nullable; import com.facebook.react.bridge.JSApplicationIllegalArgumentException; +import com.facebook.react.bridge.ReadableMap; import com.facebook.react.module.annotations.ReactModule; import com.facebook.react.uimanager.BaseViewManager; +import com.facebook.react.uimanager.PixelUtil; import com.facebook.react.uimanager.ThemedReactContext; import com.facebook.react.uimanager.ViewManagerDelegate; import com.facebook.react.uimanager.ViewProps; import com.facebook.react.uimanager.annotations.ReactProp; import com.facebook.react.viewmanagers.AndroidProgressBarManagerDelegate; import com.facebook.react.viewmanagers.AndroidProgressBarManagerInterface; +import com.facebook.yoga.YogaMeasureMode; +import com.facebook.yoga.YogaMeasureOutput; +import java.util.WeakHashMap; /** * Manages instances of ProgressBar. ProgressBar is wrapped in a ProgressBarContainerView because @@ -33,6 +41,8 @@ public class ReactProgressBarViewManager public static final String REACT_CLASS = "AndroidProgressBar"; + private final WeakHashMap> mMeasuredStyles = new WeakHashMap<>(); + /* package */ static final String PROP_STYLE = "styleAttr"; /* package */ static final String PROP_INDETERMINATE = "indeterminate"; /* package */ static final String PROP_PROGRESS = "progress"; @@ -154,4 +164,34 @@ protected ViewManagerDelegate getDelegate() { throw new JSApplicationIllegalArgumentException("Unknown ProgressBar style: " + styleStr); } } + + @Override + public long measure( + Context context, + ReadableMap localData, + ReadableMap props, + ReadableMap state, + float width, + YogaMeasureMode widthMode, + float height, + YogaMeasureMode heightMode, + @Nullable float[] attachmentsPositions) { + + final Integer style = + ReactProgressBarViewManager.getStyleFromString(props.getString(PROP_STYLE)); + Pair value = mMeasuredStyles.get(style); + if (value == null) { + ProgressBar progressBar = ReactProgressBarViewManager.createProgressBar(context, style); + + final int spec = + View.MeasureSpec.makeMeasureSpec( + ViewGroup.LayoutParams.WRAP_CONTENT, View.MeasureSpec.UNSPECIFIED); + progressBar.measure(spec, spec); + value = Pair.create(progressBar.getMeasuredWidth(), progressBar.getMeasuredHeight()); + mMeasuredStyles.put(style, value); + } + + return YogaMeasureOutput.make( + PixelUtil.toDIPFromPixel(value.first), PixelUtil.toDIPFromPixel(value.second)); + } } diff --git a/ReactCommon/react/renderer/componentregistry/ComponentDescriptorRegistry.cpp b/ReactCommon/react/renderer/componentregistry/ComponentDescriptorRegistry.cpp index 8499e3ca24c9d2..ede6ca809372ea 100644 --- a/ReactCommon/react/renderer/componentregistry/ComponentDescriptorRegistry.cpp +++ b/ReactCommon/react/renderer/componentregistry/ComponentDescriptorRegistry.cpp @@ -91,10 +91,6 @@ static std::string componentNameByReactViewName(std::string viewName) { return "PullToRefreshView"; } - if (viewName == "AndroidProgressBar") { - return "ActivityIndicatorView"; - } - // We need this temporarily for testing purposes until we have proper // implementation of core components. if (viewName == "ScrollContentView" || diff --git a/ReactCommon/react/renderer/components/progressbar/BUCK b/ReactCommon/react/renderer/components/progressbar/BUCK new file mode 100644 index 00000000000000..8afe40dc616d16 --- /dev/null +++ b/ReactCommon/react/renderer/components/progressbar/BUCK @@ -0,0 +1,121 @@ +load("@fbsource//tools/build_defs/apple:flag_defs.bzl", "get_preprocessor_flags_for_build_mode") +load( + "//tools/build_defs/oss:rn_defs.bzl", + "ANDROID", + "APPLE", + "CXX", + "YOGA_CXX_TARGET", + "fb_xplat_cxx_test", + "get_apple_compiler_flags", + "get_apple_inspector_flags", + "react_native_target", + "react_native_xplat_target", + "rn_xplat_cxx_library", + "subdir_glob", +) + +APPLE_COMPILER_FLAGS = get_apple_compiler_flags() + +rn_xplat_cxx_library( + name = "androidprogressbar", + srcs = glob( + ["**/*.cpp"], + exclude = glob([ + "tests/**/*.cpp", + ]), + ), + headers = [], + header_namespace = "", + exported_headers = subdir_glob( + [ + ("", "*.h"), + ], + prefix = "react/renderer/components/progressbar", + ), + compiler_flags = [ + "-fexceptions", + "-frtti", + "-std=c++14", + "-Wall", + ], + cxx_tests = [":tests"], + fbandroid_deps = [ + react_native_target("jni/react/jni:jni"), + ], + fbandroid_exported_headers = subdir_glob( + [ + ("", "*.h"), + ("android/react/renderer/components/progressbar", "*.h"), + ], + prefix = "react/renderer/components/progressbar", + ), + fbandroid_headers = glob( + ["android/react/renderer/components/progressbar/*.h"], + ), + fbandroid_srcs = glob( + ["android/react/renderer/components/progressbar/*.cpp"], + ), + fbobjc_compiler_flags = APPLE_COMPILER_FLAGS, + fbobjc_preprocessor_flags = get_preprocessor_flags_for_build_mode() + get_apple_inspector_flags(), + force_static = True, + ios_exported_headers = subdir_glob( + [ + ("", "*.h"), + ("platform/ios", "*.h"), + ], + prefix = "react/renderer/components/progressbar", + ), + ios_headers = glob( + ["platform/ios/*.h"], + ), + ios_srcs = glob( + ["platform/ios/*.cpp"], + ), + labels = ["supermodule:xplat/default/public.react_native.infra"], + platforms = (ANDROID, APPLE, CXX), + preprocessor_flags = [ + "-DLOG_TAG=\"ReactNative\"", + "-DWITH_FBSYSTRACE=1", + ], + visibility = ["PUBLIC"], + deps = [ + "//third-party/glog:glog", + "//xplat/fbsystrace:fbsystrace", + "//xplat/folly:headers_only", + "//xplat/folly:memory", + "//xplat/folly:molly", + YOGA_CXX_TARGET, + react_native_xplat_target("react/renderer/debug:debug"), + react_native_xplat_target("react/renderer/core:core"), + react_native_xplat_target("react/renderer/components/image:image"), + react_native_xplat_target("react/renderer/components/view:view"), + react_native_xplat_target("react/renderer/graphics:graphics"), + react_native_xplat_target("react/renderer/imagemanager:imagemanager"), + react_native_xplat_target("react/renderer/uimanager:uimanager"), + react_native_xplat_target("react/renderer/componentregistry:componentregistry"), + "//xplat/js/react-native-github:generated_components-rncore", + ], +) + +fb_xplat_cxx_test( + name = "tests", + srcs = glob(["tests/**/*.cpp"]), + headers = glob(["tests/**/*.h"]), + compiler_flags = [ + "-fexceptions", + "-frtti", + "-std=c++14", + "-Wall", + ], + contacts = ["oncall+react_native@xmail.facebook.com"], + platforms = ( + # `Apple` and `Android` flavors are disabled because the module (built with those flavors) requires Emulator/Simulator (which is expensive and slow). At the same time, we don't really have tests here. + # ANDROID, + # APPLE, + CXX, + ), + deps = [ + "//xplat/folly:molly", + "//xplat/third-party/gmock:gtest", + ], +) diff --git a/ReactCommon/react/renderer/components/progressbar/android/react/renderer/components/progressbar/AndroidProgressBarComponentDescriptor.h b/ReactCommon/react/renderer/components/progressbar/android/react/renderer/components/progressbar/AndroidProgressBarComponentDescriptor.h new file mode 100644 index 00000000000000..4b3802666a1e2a --- /dev/null +++ b/ReactCommon/react/renderer/components/progressbar/android/react/renderer/components/progressbar/AndroidProgressBarComponentDescriptor.h @@ -0,0 +1,53 @@ +/* + * 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. + */ + +#pragma once + +#include +#include "AndroidProgressBarMeasurementsManager.h" +#include "AndroidProgressBarShadowNode.h" + +namespace facebook { +namespace react { + +/* + * Descriptor for component. + */ +class AndroidProgressBarComponentDescriptor final + : public ConcreteComponentDescriptor { + public: + AndroidProgressBarComponentDescriptor( + ComponentDescriptorParameters const ¶meters) + : ConcreteComponentDescriptor(parameters), + measurementsManager_( + std::make_shared( + contextContainer_)) {} + + void adopt(UnsharedShadowNode shadowNode) const override { + ConcreteComponentDescriptor::adopt(shadowNode); + + assert(std::dynamic_pointer_cast(shadowNode)); + auto androidProgressBarShadowNode = + std::static_pointer_cast(shadowNode); + + // `AndroidProgressBarShadowNode` uses + // `AndroidProgressBarMeasurementsManager` to provide measurements to Yoga. + androidProgressBarShadowNode->setAndroidProgressBarMeasurementsManager( + measurementsManager_); + + // All `AndroidProgressBarShadowNode`s must have leaf Yoga nodes with + // properly setup measure function. + androidProgressBarShadowNode->enableMeasurement(); + } + + private: + const std::shared_ptr + measurementsManager_; +}; + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/react/renderer/components/progressbar/android/react/renderer/components/progressbar/AndroidProgressBarMeasurementsManager.cpp b/ReactCommon/react/renderer/components/progressbar/android/react/renderer/components/progressbar/AndroidProgressBarMeasurementsManager.cpp new file mode 100644 index 00000000000000..9e4c2fdbe92a7d --- /dev/null +++ b/ReactCommon/react/renderer/components/progressbar/android/react/renderer/components/progressbar/AndroidProgressBarMeasurementsManager.cpp @@ -0,0 +1,75 @@ +/* + * 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. + */ + +#include "AndroidProgressBarMeasurementsManager.h" + +#include +#include +#include + +using namespace facebook::jni; + +namespace facebook { +namespace react { + +Size AndroidProgressBarMeasurementsManager::measure( + SurfaceId surfaceId, + AndroidProgressBarProps props, + LayoutConstraints layoutConstraints) const { + { + std::lock_guard lock(mutex_); + if (hasBeenMeasured_) { + return cachedMeasurement_; + } + } + + const jni::global_ref &fabricUIManager = + contextContainer_->at>("FabricUIManager"); + + static auto measure = facebook::jni::findClassStatic( + "com/facebook/react/fabric/FabricUIManager") + ->getMethod("measure"); + + auto minimumSize = layoutConstraints.minimumSize; + auto maximumSize = layoutConstraints.maximumSize; + + local_ref componentName = make_jstring("AndroidProgressBar"); + + auto serialiazedProps = toDynamic(props); + local_ref propsRNM = + ReadableNativeMap::newObjectCxxArgs(serialiazedProps); + local_ref propsRM = + make_local(reinterpret_cast(propsRNM.get())); + + auto measurement = yogaMeassureToSize(measure( + fabricUIManager, + surfaceId, + componentName.get(), + nullptr, + propsRM.get(), + nullptr, + minimumSize.width, + maximumSize.width, + minimumSize.height, + maximumSize.height)); + + std::lock_guard lock(mutex_); + cachedMeasurement_ = measurement; + return measurement; +} + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/react/renderer/components/progressbar/android/react/renderer/components/progressbar/AndroidProgressBarMeasurementsManager.h b/ReactCommon/react/renderer/components/progressbar/android/react/renderer/components/progressbar/AndroidProgressBarMeasurementsManager.h new file mode 100644 index 00000000000000..c2eb8191f77214 --- /dev/null +++ b/ReactCommon/react/renderer/components/progressbar/android/react/renderer/components/progressbar/AndroidProgressBarMeasurementsManager.h @@ -0,0 +1,38 @@ +/* + * 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. + */ + +#pragma once + +#include +#include +#include +#include +#include + +namespace facebook { +namespace react { + +class AndroidProgressBarMeasurementsManager { + public: + AndroidProgressBarMeasurementsManager( + const ContextContainer::Shared &contextContainer) + : contextContainer_(contextContainer) {} + + Size measure( + SurfaceId surfaceId, + AndroidProgressBarProps props, + LayoutConstraints layoutConstraints) const; + + private: + const ContextContainer::Shared contextContainer_; + mutable std::mutex mutex_; + mutable bool hasBeenMeasured_ = false; + mutable Size cachedMeasurement_{}; +}; + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/react/renderer/components/progressbar/android/react/renderer/components/progressbar/AndroidProgressBarShadowNode.cpp b/ReactCommon/react/renderer/components/progressbar/android/react/renderer/components/progressbar/AndroidProgressBarShadowNode.cpp new file mode 100644 index 00000000000000..0ab3970a71fd37 --- /dev/null +++ b/ReactCommon/react/renderer/components/progressbar/android/react/renderer/components/progressbar/AndroidProgressBarShadowNode.cpp @@ -0,0 +1,35 @@ +/* + * 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. + */ + +#include "AndroidProgressBarShadowNode.h" + +#include +#include + +namespace facebook { +namespace react { + +extern const char AndroidProgressBarComponentName[] = "AndroidProgressBar"; + +void AndroidProgressBarShadowNode::setAndroidProgressBarMeasurementsManager( + const std::shared_ptr + &measurementsManager) { + ensureUnsealed(); + measurementsManager_ = measurementsManager; +} + +#pragma mark - LayoutableShadowNode + +Size AndroidProgressBarShadowNode::measureContent( + LayoutContext const &layoutContext, + LayoutConstraints const &layoutConstraints) const { + return measurementsManager_->measure( + getSurfaceId(), getConcreteProps(), layoutConstraints); +} + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/react/renderer/components/progressbar/android/react/renderer/components/progressbar/AndroidProgressBarShadowNode.h b/ReactCommon/react/renderer/components/progressbar/android/react/renderer/components/progressbar/AndroidProgressBarShadowNode.h new file mode 100644 index 00000000000000..e13f547eb6632c --- /dev/null +++ b/ReactCommon/react/renderer/components/progressbar/android/react/renderer/components/progressbar/AndroidProgressBarShadowNode.h @@ -0,0 +1,46 @@ +/* + * 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. + */ + +#pragma once + +#include +#include +#include +#include + +namespace facebook { +namespace react { + +extern const char AndroidProgressBarComponentName[]; + +/* + * `ShadowNode` for component. + */ +class AndroidProgressBarShadowNode final : public ConcreteViewShadowNode< + AndroidProgressBarComponentName, + AndroidProgressBarProps, + AndroidProgressBarEventEmitter> { + public: + using ConcreteViewShadowNode::ConcreteViewShadowNode; + + // Associates a shared `AndroidProgressBarMeasurementsManager` with the node. + void setAndroidProgressBarMeasurementsManager( + const std::shared_ptr + &measurementsManager); + +#pragma mark - LayoutableShadowNode + + Size measureContent( + LayoutContext const &layoutContext, + LayoutConstraints const &layoutConstraints) const override; + + private: + std::shared_ptr measurementsManager_; +}; + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/react/renderer/components/progressbar/android/react/renderer/components/progressbar/conversions.h b/ReactCommon/react/renderer/components/progressbar/android/react/renderer/components/progressbar/conversions.h new file mode 100644 index 00000000000000..cb70dc61169fb4 --- /dev/null +++ b/ReactCommon/react/renderer/components/progressbar/android/react/renderer/components/progressbar/conversions.h @@ -0,0 +1,30 @@ +/* + * 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. + */ + +#include +#include +#include + +namespace facebook { +namespace react { + +#ifdef ANDROID +inline folly::dynamic toDynamic(AndroidProgressBarProps const &props) { + folly::dynamic serializedProps = folly::dynamic::object(); + serializedProps["styleAttr"] = props.styleAttr; + serializedProps["typeAttr"] = props.typeAttr; + serializedProps["indeterminate"] = props.indeterminate; + serializedProps["progress"] = props.progress; + serializedProps["animating"] = props.animating; + serializedProps["color"] = toDynamic(props.color); + serializedProps["testID"] = props.testID; + return serializedProps; +} +#endif + +} // namespace react +} // namespace facebook From 1aaa3d95c0af7298c4515aa81555989a2c189300 Mon Sep 17 00:00:00 2001 From: David Vacca Date: Sat, 22 Aug 2020 01:43:55 -0700 Subject: [PATCH 0021/1238] Integrate AndroidProgressBarComponent into RN Tester OSS Android app Summary: This diff integratess AndroidProgressBarComponent into RN Tester OSS android app changeLog: [internal] internal Reviewed By: fkgozali Differential Revision: D23227859 fbshipit-source-id: a916c90486ec4f9664be79608a8a8f907e2634a7 --- .../com/facebook/react/fabric/jni/Android.mk | 3 +- .../java/com/facebook/react/fabric/jni/BUCK | 1 + .../fabric/jni/CoreComponentsRegistry.cpp | 4 +- .../components/progressbar/Android.mk | 38 +++++++++++++++++++ 4 files changed, 44 insertions(+), 2 deletions(-) create mode 100644 ReactCommon/react/renderer/components/progressbar/Android.mk diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Android.mk b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Android.mk index 6ee21a2d0224ed..593a8cf30815b3 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Android.mk +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Android.mk @@ -11,7 +11,7 @@ LOCAL_MODULE := fabricjni LOCAL_SRC_FILES := $(wildcard $(LOCAL_PATH)/*.cpp) -LOCAL_SHARED_LIBRARIES := libreactconfig libreact_render_components_slider libreact_render_components_switch libreact_render_components_modal libyoga libglog libfb libfbjni libglog_init libfolly_json libfolly_futures libreact_render_mounting libreactnativeutilsjni libreact_utils libreact_render_debug libreact_render_graphics libreact_render_core libreact_render_mapbuffer react_render_componentregistry libreact_render_components_view libreact_render_components_unimplementedview libreact_render_components_root libreact_render_components_scrollview libbetter libreact_render_attributedstring libreact_render_uimanager libreact_render_templateprocessor libreact_render_scheduler libreact_render_animations libreact_render_imagemanager libreact_render_textlayoutmanager libreact_render_viewmanagers react_render_components_text libreact_render_components_image react_render_components_textinput react_render_components_picker +LOCAL_SHARED_LIBRARIES := libreactconfig libreact_render_components_slider libreact_render_components_progressbar libreact_render_components_switch libreact_render_components_modal libyoga libglog libfb libfbjni libglog_init libfolly_json libfolly_futures libreact_render_mounting libreactnativeutilsjni libreact_utils libreact_render_debug libreact_render_graphics libreact_render_core libreact_render_mapbuffer react_render_componentregistry libreact_render_components_view libreact_render_components_unimplementedview libreact_render_components_root libreact_render_components_scrollview libbetter libreact_render_attributedstring libreact_render_uimanager libreact_render_templateprocessor libreact_render_scheduler libreact_render_animations libreact_render_imagemanager libreact_render_textlayoutmanager libreact_render_viewmanagers react_render_components_text libreact_render_components_image react_render_components_textinput react_render_components_picker LOCAL_STATIC_LIBRARIES := @@ -43,6 +43,7 @@ $(call import-module,react/renderer/components/image) $(call import-module,react/renderer/components/modal) $(call import-module,react/renderer/components/root) $(call import-module,react/renderer/components/picker) +$(call import-module,react/renderer/components/progressbar) $(call import-module,react/renderer/components/scrollview) $(call import-module,react/renderer/components/slider) $(call import-module,react/renderer/components/switch) diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/BUCK b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/BUCK index 92380fa7168bc1..0d6dd21aaaaef3 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/BUCK +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/BUCK @@ -50,6 +50,7 @@ rn_xplat_cxx_library( react_native_xplat_target("react/renderer/components/picker:androidpicker"), react_native_xplat_target("react/renderer/components/slider:slider"), react_native_xplat_target("react/renderer/components/switch:androidswitch"), + react_native_xplat_target("react/renderer/components/progressbar:androidprogressbar"), react_native_xplat_target("react/renderer/components/text:text"), react_native_xplat_target("react/renderer/components/textinput:androidtextinput"), ], diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/CoreComponentsRegistry.cpp b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/CoreComponentsRegistry.cpp index fa4802913b8a17..560b8eaaa70fb2 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/CoreComponentsRegistry.cpp +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/CoreComponentsRegistry.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -39,6 +40,8 @@ CoreComponentsRegistry::sharedProviderRegistry() { auto providerRegistry = std::make_shared(); + providerRegistry->add(concreteComponentDescriptorProvider< + AndroidProgressBarComponentDescriptor>()); providerRegistry->add(concreteComponentDescriptorProvider< AndroidSwipeRefreshLayoutComponentDescriptor>()); providerRegistry->add(concreteComponentDescriptorProvider< @@ -90,7 +93,6 @@ CoreComponentsRegistry::initHybrid( auto registry = CoreComponentsRegistry::sharedProviderRegistry() ->createComponentDescriptorRegistry( {eventDispatcher, contextContainer}); - auto mutableRegistry = std::const_pointer_cast(registry); mutableRegistry->setFallbackComponentDescriptor( diff --git a/ReactCommon/react/renderer/components/progressbar/Android.mk b/ReactCommon/react/renderer/components/progressbar/Android.mk new file mode 100644 index 00000000000000..f17cb34c809c55 --- /dev/null +++ b/ReactCommon/react/renderer/components/progressbar/Android.mk @@ -0,0 +1,38 @@ +# 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. + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := react_render_components_progressbar + +LOCAL_SRC_FILES := $(wildcard $(LOCAL_PATH)/android/react/renderer/components/progressbar/*.cpp) + +LOCAL_C_INCLUDES := $(LOCAL_PATH)/android/ +LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/android/ + +LOCAL_CFLAGS := \ + -DLOG_TAG=\"Fabric\" + +LOCAL_CFLAGS += -fexceptions -frtti -std=c++14 -Wall + +LOCAL_STATIC_LIBRARIES := + +LOCAL_SHARED_LIBRARIES := libfbjni libreact_render_viewmanagers libreactnativeutilsjni libreact_render_componentregistry libreact_render_uimanager libyoga libfolly_futures glog libfolly_json libglog_init libreact_render_core libreact_render_debug libreact_render_graphics libreact_render_components_view + +include $(BUILD_SHARED_LIBRARY) + +$(call import-module,fbjni) +$(call import-module,folly) +$(call import-module,fbgloginit) +$(call import-module,glog) +$(call import-module,react/renderer/componentregistry) +$(call import-module,react/renderer/core) +$(call import-module,react/renderer/debug) +$(call import-module,react/renderer/graphics) +$(call import-module,react/renderer/components/view) +$(call import-module,react/renderer/uimanager) +$(call import-module,yogajni) From b0fbbe54426859fa194d8bcc483ff98d047b4ff7 Mon Sep 17 00:00:00 2001 From: Kevin Gozali Date: Sat, 22 Aug 2020 11:32:42 -0700 Subject: [PATCH 0022/1238] Codegen: execute JavaGenerator only after tasks are evaluated Summary: Instead of invoking JavaGenerator when the task is registered, do it when the task actually executes. This way, it will wait until the other task it depends on to finish executing. Changelog: [Internal] Reviewed By: mdvacca Differential Revision: D23276359 fbshipit-source-id: 6aea98d97121f2dcfd83b299e38debc767f08240 --- .../facebook/react/codegen/plugin/CodegenPlugin.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/plugin/CodegenPlugin.java b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/plugin/CodegenPlugin.java index 055bcff1b6fa72..4ea0a13e09f6f3 100644 --- a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/plugin/CodegenPlugin.java +++ b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/plugin/CodegenPlugin.java @@ -98,10 +98,13 @@ public void apply(final Project project) { task.getOutputs().dir(outputDir); if (extension.useJavaGenerator) { - generateJavaFromSchemaWithJavaGenerator( - generatedSchemaFile, - extension.codegenJavaPackageName, - new File(generatedSrcDir, "java")); + task.doLast( + s -> { + generateJavaFromSchemaWithJavaGenerator( + generatedSchemaFile, + extension.codegenJavaPackageName, + new File(generatedSrcDir, "java")); + }); // TODO: generate JNI C++ files. task.commandLine("echo"); } else { From 39689bd9691a861aab3d740910ca828f715ebb0a Mon Sep 17 00:00:00 2001 From: Joshua Gross Date: Sat, 22 Aug 2020 22:39:48 -0700 Subject: [PATCH 0023/1238] Add additional verbose logging to MountingManager.java Summary: In MountingManager.java in Fabric, if we drop a view with any attached views, we also drop all children. If verbose logging is turned on, log all instances of that happening. This has no impact unless you switch the flag on manually in debug mode. Changelog: [Internal] Differential Revision: D23257749 fbshipit-source-id: fce4476aa47cc1b7137cd9fd2fd0241af1593288 --- .../facebook/react/fabric/mounting/MountingManager.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountingManager.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountingManager.java index bd7f4ec3c0a1c0..0e951ed4db67ff 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountingManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountingManager.java @@ -120,6 +120,15 @@ private void dropView(@NonNull View view) { for (int i = viewGroupManager.getChildCount(viewGroup) - 1; i >= 0; i--) { View child = viewGroupManager.getChildAt(viewGroup, i); if (getNullableViewState(child.getId()) != null) { + if (SHOW_CHANGED_VIEW_HIERARCHIES) { + FLog.e( + TAG, + "Automatically dropping view that is still attached to a parent being dropped. Parent: [" + + reactTag + + "] child: [" + + child.getId() + + "]"); + } dropView(child); } viewGroupManager.removeViewAt(viewGroup, i); From 1d05d46e6447372580bb6ea81fb340bb2fe46d13 Mon Sep 17 00:00:00 2001 From: Joshua Gross Date: Sat, 22 Aug 2020 22:39:48 -0700 Subject: [PATCH 0024/1238] Add square brackets around tags in logs in FabricUIManager Summary: See title. Changelog: [Internal] Differential Revision: D23257809 fbshipit-source-id: b8e519971603506e8ae2b327582d3e3e7d65fddf --- .../react/fabric/mounting/mountitems/InsertMountItem.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/InsertMountItem.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/InsertMountItem.java index a29de03ec2ef43..edfc46ac7109cf 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/InsertMountItem.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/InsertMountItem.java @@ -39,9 +39,9 @@ public int getIndex() { public String toString() { return "InsertMountItem [" + mReactTag - + "] - parentTag: " + + "] - parentTag: [" + mParentReactTag - + " - index: " + + "] - index: " + mIndex; } } From 19c45ba70907e7ecd6e8d52f34869c90d319c290 Mon Sep 17 00:00:00 2001 From: Joshua Gross Date: Mon, 24 Aug 2020 01:18:56 -0700 Subject: [PATCH 0025/1238] NativeAnimatedModule: allow JS to control queueing of Animated operations (JS Side) Summary: This is the JS side of D23010844 (https://github.com/facebook/react-native/commit/73242b45a9f7f9ecce8f5124ac3d1665f575be74). In the past I tried a few heuristics to guess when a batch of Animated Operations were ready, and none of these were super reliable. But it turns out we can safely allow JS to manage that explicitly. Non-Fabric still uses the old behavior which seems fine. Changelog: [Internal] Reviewed By: mdvacca Differential Revision: D23010937 fbshipit-source-id: 4a513672c166ceaa8b6daa387e46a2a95b60ce53 --- Libraries/Animated/src/NativeAnimatedHelper.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Libraries/Animated/src/NativeAnimatedHelper.js b/Libraries/Animated/src/NativeAnimatedHelper.js index 7cf0ca7cd8297c..9e1b2cb400802d 100644 --- a/Libraries/Animated/src/NativeAnimatedHelper.js +++ b/Libraries/Animated/src/NativeAnimatedHelper.js @@ -74,10 +74,16 @@ const API = { invariant(NativeAnimatedModule, 'Native animated module is not available'); queueConnections = false; if (!queueOperations) { + if (Platform.OS === 'android') { + NativeAnimatedModule.startOperationBatch(); + } for (let q = 0, l = queue.length; q < l; q++) { queue[q](); } queue.length = 0; + if (Platform.OS === 'android') { + NativeAnimatedModule.finishOperationBatch(); + } } }, queueConnection: (fn: () => void): void => { From 6c1ee871c07795546acd0a14fb88513bdebe9615 Mon Sep 17 00:00:00 2001 From: Samuel Susla Date: Mon, 24 Aug 2020 01:41:39 -0700 Subject: [PATCH 0026/1238] Calling `ConcreteShadowNode::setStateData` sets mostReventState Summary: Changelog: [Internal] If `ConcreteShadowNode::setStateData` is called and the node is cloned before it is mounted, the cloned node will have old state before `setStateData` was called. To solve this, simply call `setMostRecentState` on the family inside `ConcreteShadowNode::setStateData`. Reviewed By: JoshuaGross Differential Revision: D23283560 fbshipit-source-id: f9822fb69e4234f776d512fc02fe13ea7de64897 --- .../react/renderer/core/ConcreteShadowNode.h | 1 + .../core/tests/ConcreteShadowNodeTest.cpp | 44 +++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 ReactCommon/react/renderer/core/tests/ConcreteShadowNodeTest.cpp diff --git a/ReactCommon/react/renderer/core/ConcreteShadowNode.h b/ReactCommon/react/renderer/core/ConcreteShadowNode.h index bafe8e23946120..754194b01b93e5 100644 --- a/ReactCommon/react/renderer/core/ConcreteShadowNode.h +++ b/ReactCommon/react/renderer/core/ConcreteShadowNode.h @@ -132,6 +132,7 @@ class ConcreteShadowNode : public BaseShadowNodeT { Sealable::ensureUnsealed(); state_ = std::make_shared( std::make_shared(std::move(data)), *state_); + BaseShadowNodeT::getFamily().setMostRecentState(state_); } }; diff --git a/ReactCommon/react/renderer/core/tests/ConcreteShadowNodeTest.cpp b/ReactCommon/react/renderer/core/tests/ConcreteShadowNodeTest.cpp new file mode 100644 index 00000000000000..44d2ad76783c8d --- /dev/null +++ b/ReactCommon/react/renderer/core/tests/ConcreteShadowNodeTest.cpp @@ -0,0 +1,44 @@ +/* + * 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. + */ + +#include + +#include +#include +#include +#include +#include + +#include "TestComponent.h" + +using namespace facebook::react; + +TEST(ConcreteShadowNodeTest, testSetStateData) { + auto builder = simpleComponentBuilder(); + + auto childShadowNode = std::shared_ptr{}; + + auto element = Element(); + + auto shadowNode = builder.build(element); + + shadowNode->setStateData({{10, 11}, {{21, 22}, {301, 302}}}); + + EXPECT_EQ( + shadowNode->getState(), shadowNode->getFamily().getMostRecentState()); + + auto stateData = shadowNode->getStateData(); + + EXPECT_EQ(stateData.contentOffset.x, 10); + EXPECT_EQ(stateData.contentOffset.y, 11); + + EXPECT_EQ(stateData.contentBoundingRect.origin.x, 21); + EXPECT_EQ(stateData.contentBoundingRect.origin.y, 22); + + EXPECT_EQ(stateData.contentBoundingRect.size.width, 301); + EXPECT_EQ(stateData.contentBoundingRect.size.height, 302); +} From 464293f64eb783bb3c092fda14653769f0d653d7 Mon Sep 17 00:00:00 2001 From: benjaminhr Date: Mon, 24 Aug 2020 01:49:55 -0700 Subject: [PATCH 0027/1238] Update Metro packages to v0.63.0 Summary: `js1 upgrade metro -v 0.63.0` Newest Metro release: https://github.com/facebook/metro/releases/tag/v0.63.0 Changelog: [Internal] Reviewed By: cpojer Differential Revision: D23266107 fbshipit-source-id: 1afcb8a1f5bac7f4d489e5af62df7d27e24da8f8 --- package.json | 8 ++--- template/package.json | 2 +- yarn.lock | 78 +++++++++++++++++++++---------------------- 3 files changed, 44 insertions(+), 44 deletions(-) diff --git a/package.json b/package.json index d1db234a0ac755..74d9cbaac332b6 100644 --- a/package.json +++ b/package.json @@ -100,10 +100,10 @@ "hermes-engine": "~0.6.0", "invariant": "^2.2.4", "jsc-android": "^245459.0.0", - "metro-babel-register": "0.62.0", - "metro-react-native-babel-transformer": "0.62.0", - "metro-runtime": "0.62.0", - "metro-source-map": "0.62.0", + "metro-babel-register": "0.63.0", + "metro-react-native-babel-transformer": "0.63.0", + "metro-runtime": "0.63.0", + "metro-source-map": "0.63.0", "nullthrows": "^1.1.1", "pretty-format": "^26.0.1", "promise": "^8.0.3", diff --git a/template/package.json b/template/package.json index 60973f5a765cdc..c687aea151259d 100644 --- a/template/package.json +++ b/template/package.json @@ -20,7 +20,7 @@ "babel-jest": "^25.1.0", "eslint": "^6.5.1", "jest": "^25.1.0", - "metro-react-native-babel-preset": "^0.62.0", + "metro-react-native-babel-preset": "^0.63.0", "react-test-renderer": "16.13.1" }, "jest": { diff --git a/yarn.lock b/yarn.lock index b1d5ed65973bc1..8f632250127d47 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4954,10 +4954,10 @@ metro-babel-register@0.58.0: core-js "^2.2.2" escape-string-regexp "^1.0.5" -metro-babel-register@0.62.0: - version "0.62.0" - resolved "https://registry.yarnpkg.com/metro-babel-register/-/metro-babel-register-0.62.0.tgz#33b05f89282c75c7dc7d4c16c563f64936dc2738" - integrity sha512-6umr/Xy8hh7Lz0SXVWa21IH2ybQbqfFgdxrJ0eoRYSdOJVzse3CNWvn6u/ZEBn7FesCLCMSoK7Nd3yaetzdrfw== +metro-babel-register@0.63.0: + version "0.63.0" + resolved "https://registry.yarnpkg.com/metro-babel-register/-/metro-babel-register-0.63.0.tgz#8e196535d4c77ff3103a681e8217f8661f5850c9" + integrity sha512-y1XBXtHX3Wp25a5+Yfx0oxmjDR4aIzjOy5ywfRaz+2GLUkT6JngRQ2inyQ66wWDj8fjifPpH74j8vf7LGfyICQ== dependencies: "@babel/core" "^7.0.0" "@babel/plugin-proposal-class-properties" "^7.0.0" @@ -4976,13 +4976,13 @@ metro-babel-transformer@0.58.0: "@babel/core" "^7.0.0" metro-source-map "0.58.0" -metro-babel-transformer@0.62.0: - version "0.62.0" - resolved "https://registry.yarnpkg.com/metro-babel-transformer/-/metro-babel-transformer-0.62.0.tgz#f3d84a34c3d5aa8d952364969bd6ac562caa3e1b" - integrity sha512-f27+r5oi8oZWmxOU+BxE/c7itJlBYVXt5+HP16iWndu3HxCI8YF9KO9zKQB8QEkg3h6NGoZVo/g8Bp6uVk2VVA== +metro-babel-transformer@0.63.0: + version "0.63.0" + resolved "https://registry.yarnpkg.com/metro-babel-transformer/-/metro-babel-transformer-0.63.0.tgz#0fe7dd2d58fba8a64917d431ba0dcbbdd874f076" + integrity sha512-u8s6wKua9G0P/uLcw6hwPA1RCTKwlauvxMUoceci8HrK6FQyZamYbAM4fGxMSgjb2ogqKG7oGfBneTIrAn9HvA== dependencies: "@babel/core" "^7.0.0" - metro-source-map "0.62.0" + metro-source-map "0.63.0" metro-cache@0.58.0: version "0.58.0" @@ -5075,10 +5075,10 @@ metro-react-native-babel-preset@0.58.0: "@babel/template" "^7.0.0" react-refresh "^0.4.0" -metro-react-native-babel-preset@0.62.0: - version "0.62.0" - resolved "https://registry.yarnpkg.com/metro-react-native-babel-preset/-/metro-react-native-babel-preset-0.62.0.tgz#f97ba108e289bddf40bb76cde9f9ccfac7ce5586" - integrity sha512-TznN3fyzo68A7TsO5paUsvKY4bXEk0BreVVXY/hKUXxv8p0Ts7gOB9ciXX2QT+8Egcs6+T4z/S06bONUYlWFJg== +metro-react-native-babel-preset@0.63.0: + version "0.63.0" + resolved "https://registry.yarnpkg.com/metro-react-native-babel-preset/-/metro-react-native-babel-preset-0.63.0.tgz#bc67d4d251ac72f30b7f3d92a069aea825577751" + integrity sha512-iTM6V/hzqTd2dg0LHtD4f/TU+d4A7MFiMPUmIYDb0OZmCq6avfcxHQTXk/ZNbAr+eRoN/owx9OIkjt/CvG4vUA== dependencies: "@babel/core" "^7.0.0" "@babel/plugin-proposal-class-properties" "^7.0.0" @@ -5120,16 +5120,16 @@ metro-react-native-babel-preset@0.62.0: "@babel/template" "^7.0.0" react-refresh "^0.4.0" -metro-react-native-babel-transformer@0.62.0: - version "0.62.0" - resolved "https://registry.yarnpkg.com/metro-react-native-babel-transformer/-/metro-react-native-babel-transformer-0.62.0.tgz#925ec59e9310e24a72aae3423427a297d2628492" - integrity sha512-lgJtR2R6IVGkAOMVdIkP2C8Wv10txpoIQjNHtqPekKsLjLkZUb0uUTSfMyK9vOexex02dHttH26Q1CNKwPOUrg== +metro-react-native-babel-transformer@0.63.0: + version "0.63.0" + resolved "https://registry.yarnpkg.com/metro-react-native-babel-transformer/-/metro-react-native-babel-transformer-0.63.0.tgz#527e1e5ef7b63512189a5b5bb4cb06d1fdb57815" + integrity sha512-HbyGvCoGJZ2WrstyTgHg05O5UOYgkatRLpalAnhHjPt+1Wr0Z3vr33SesibHRlnT5ETUBZME+txukcnN9eSdIA== dependencies: "@babel/core" "^7.0.0" babel-preset-fbjs "^3.3.0" - metro-babel-transformer "0.62.0" - metro-react-native-babel-preset "0.62.0" - metro-source-map "0.62.0" + metro-babel-transformer "0.63.0" + metro-react-native-babel-preset "0.63.0" + metro-source-map "0.63.0" metro-react-native-babel-transformer@^0.58.0: version "0.58.0" @@ -5149,10 +5149,10 @@ metro-resolver@0.58.0, metro-resolver@^0.58.0: dependencies: absolute-path "^0.0.0" -metro-runtime@0.62.0: - version "0.62.0" - resolved "https://registry.yarnpkg.com/metro-runtime/-/metro-runtime-0.62.0.tgz#f4d5462b3b079465f2f7b11b9d65da8f775cd9ca" - integrity sha512-cukazDEFviGK7jgW0AeSCXE7cAlquS/ogSQpoV66DF7Nvyf6VJ9Lv+Sz/BVTos5VP5AStJ5pZDBzfRUvzVelHw== +metro-runtime@0.63.0: + version "0.63.0" + resolved "https://registry.yarnpkg.com/metro-runtime/-/metro-runtime-0.63.0.tgz#7cb397eb45b5f605886251cd2ccd40d0b9ad7a97" + integrity sha512-iE3B2zFQBtSomz73extpfS/qvd4iEc2zbCEnytThPBtHY9g/pBTeR+sVqVlkG2Vl3sVXgxKx+Pq0QXuLz1ipLg== metro-source-map@0.58.0: version "0.58.0" @@ -5167,16 +5167,16 @@ metro-source-map@0.58.0: source-map "^0.5.6" vlq "^1.0.0" -metro-source-map@0.62.0: - version "0.62.0" - resolved "https://registry.yarnpkg.com/metro-source-map/-/metro-source-map-0.62.0.tgz#9eb9f8a2616d965e86dfa77defabbb1f5eb476be" - integrity sha512-aZcS8NWTV5AY76nZuWTZbbapNpWtkV2N7pSd+C5W/XwxLGc7U7hdNrsYNDsD4ot3PhHfqcOEQFQU/Xg4uNOH1A== +metro-source-map@0.63.0: + version "0.63.0" + resolved "https://registry.yarnpkg.com/metro-source-map/-/metro-source-map-0.63.0.tgz#bbfdfd2ce317dcccb7d52999d30bdbca69c8086c" + integrity sha512-gDa91b9jeZJfzV3f9tq4++AEicrX95+cnvkpXx1f5X+VktQYDUhoTJ/WSCYAZOwoeE1+QC3+TfKpFKWNs1Siqw== dependencies: "@babel/traverse" "^7.0.0" "@babel/types" "^7.0.0" invariant "^2.2.4" - metro-symbolicate "0.62.0" - ob1 "0.62.0" + metro-symbolicate "0.63.0" + ob1 "0.63.0" source-map "^0.5.6" vlq "^1.0.0" @@ -5191,13 +5191,13 @@ metro-symbolicate@0.58.0: through2 "^2.0.1" vlq "^1.0.0" -metro-symbolicate@0.62.0: - version "0.62.0" - resolved "https://registry.yarnpkg.com/metro-symbolicate/-/metro-symbolicate-0.62.0.tgz#7564917fc3361c1331d2c38a656b3ccee8535cac" - integrity sha512-FPCfc/vu/43emCLafUnpQcEtpGppIAIFyJ0z7aJTP2lWjI5s8AVdodkqjZ/QMgx0UMcBoZWzUvW/bLLVhKwOMA== +metro-symbolicate@0.63.0: + version "0.63.0" + resolved "https://registry.yarnpkg.com/metro-symbolicate/-/metro-symbolicate-0.63.0.tgz#c099605f38a1ff1857712f49d15e7eab743bcc7d" + integrity sha512-bJtz+hpHNHtUib9OUzxj/wShRm6p3qG0MtkLJKzWPe9SwxeGUH1mV0IUec4cgJL9csQ2iPMB00OknVH8K1eDaw== dependencies: invariant "^2.2.4" - metro-source-map "0.62.0" + metro-source-map "0.63.0" source-map "^0.5.6" through2 "^2.0.1" vlq "^1.0.0" @@ -5642,10 +5642,10 @@ ob1@0.58.0: resolved "https://registry.yarnpkg.com/ob1/-/ob1-0.58.0.tgz#484a1e9a63a8b79d9ea6f3a83b2a42110faac973" integrity sha512-uZP44cbowAfHafP1k4skpWItk5iHCoRevMfrnUvYCfyNNPPJd3rfDCyj0exklWi2gDXvjlj2ObsfiqP/bs/J7Q== -ob1@0.62.0: - version "0.62.0" - resolved "https://registry.yarnpkg.com/ob1/-/ob1-0.62.0.tgz#db8dd08c05cd08796848fdb9197a11654ecdd249" - integrity sha512-QjAOau69V8bEDYkh/EejQssBTA7oB9dkpvQyxFYS2WCrQ00Ewt9q71q8DUaoQ3/eVHItd2k2jwmLlXQqdvk3nA== +ob1@0.63.0: + version "0.63.0" + resolved "https://registry.yarnpkg.com/ob1/-/ob1-0.63.0.tgz#2f34b178b5918028a0d76072a7b155b91f9cb6bd" + integrity sha512-y7AtRIuISHuA5sc0Alcw/Cj2azU1ruuAmJIKSKk//IryxmHtmyA/M5DFcmpDAisaIB255bBt/P9aqc8jr1ocsg== object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: version "4.1.1" From 549563e8ab5e822ed2b4c8a17fd6547093dc98be Mon Sep 17 00:00:00 2001 From: Martin Sherburn Date: Mon, 24 Aug 2020 06:05:15 -0700 Subject: [PATCH 0028/1238] Allow Hermes to be built as a DLL on Windows Summary: On windows it is required to explicitly specify what symbols need to be exported from a DLL to make them accessible (using `__declspec(dllexport)`). I have added and expanded on existing macros to do this and added exports that were previously missing. Changelog: [Internal][Changed] - Allow Hermes to be compiled to a single DLL on windows Reviewed By: mhorowitz Differential Revision: D23084343 fbshipit-source-id: 832cb17b9e637e4c04dad479aae6c1fc190f968e --- .gitignore | 2 ++ ReactCommon/hermes/inspector/Exceptions.h | 7 +++- ReactCommon/hermes/inspector/Inspector.h | 7 +++- ReactCommon/hermes/inspector/InspectorState.h | 7 +++- ReactCommon/hermes/inspector/RuntimeAdapter.h | 16 +++++++-- .../hermes/inspector/chrome/Connection.h | 9 +++-- ReactCommon/jsi/jsi/instrumentation.h | 2 +- ReactCommon/jsi/jsi/jsi.h | 34 +++++++++---------- ReactCommon/jsinspector/InspectorInterfaces.h | 18 ++++++++-- 9 files changed, 74 insertions(+), 28 deletions(-) diff --git a/.gitignore b/.gitignore index f1cbcd5e8df576..ad00da2eefa7e0 100644 --- a/.gitignore +++ b/.gitignore @@ -35,6 +35,8 @@ project.xcworkspace # Buck .buckd buck-out +/.lsp.buckd +/.lsp-buck-out /ReactAndroid/src/main/jni/prebuilt/lib/ /ReactAndroid/src/main/gen diff --git a/ReactCommon/hermes/inspector/Exceptions.h b/ReactCommon/hermes/inspector/Exceptions.h index 132af0eb46af4a..b47f45c83f93df 100644 --- a/ReactCommon/hermes/inspector/Exceptions.h +++ b/ReactCommon/hermes/inspector/Exceptions.h @@ -5,7 +5,10 @@ * LICENSE file in the root directory of this source tree. */ -#pragma once +// using include guards instead of #pragma once due to compile issues +// with MSVC and BUCK +#ifndef HERMES_INSPECTOR_EXCEPTIONS_H +#define HERMES_INSPECTOR_EXCEPTIONS_H #include @@ -47,3 +50,5 @@ class MultipleCommandsPendingException : public std::runtime_error { } // namespace inspector } // namespace hermes } // namespace facebook + +#endif // HERMES_INSPECTOR_EXCEPTIONS_H diff --git a/ReactCommon/hermes/inspector/Inspector.h b/ReactCommon/hermes/inspector/Inspector.h index 5d98588286d8c7..3e4612530ea869 100644 --- a/ReactCommon/hermes/inspector/Inspector.h +++ b/ReactCommon/hermes/inspector/Inspector.h @@ -5,7 +5,10 @@ * LICENSE file in the root directory of this source tree. */ -#pragma once +// using include guards instead of #pragma once due to compile issues +// with MSVC and BUCK +#ifndef HERMES_INSPECTOR_INSPECTOR_H +#define HERMES_INSPECTOR_INSPECTOR_H #include #include @@ -362,3 +365,5 @@ class Inspector : public facebook::hermes::debugger::EventObserver, } // namespace inspector } // namespace hermes } // namespace facebook + +#endif // HERMES_INSPECTOR_INSPECTOR_H diff --git a/ReactCommon/hermes/inspector/InspectorState.h b/ReactCommon/hermes/inspector/InspectorState.h index 827f3149f43bb4..67a8fbede47418 100644 --- a/ReactCommon/hermes/inspector/InspectorState.h +++ b/ReactCommon/hermes/inspector/InspectorState.h @@ -5,7 +5,10 @@ * LICENSE file in the root directory of this source tree. */ -#pragma once +// using include guards instead of #pragma once due to compile issues +// with MSVC and BUCK +#ifndef HERMES_INSPECTOR_INSPECTOR_STATE_H +#define HERMES_INSPECTOR_INSPECTOR_STATE_H #include #include @@ -405,3 +408,5 @@ class InspectorState::Paused : public InspectorState { } // namespace inspector } // namespace hermes } // namespace facebook + +#endif // HERMES_INSPECTOR_INSPECTOR_STATE_H diff --git a/ReactCommon/hermes/inspector/RuntimeAdapter.h b/ReactCommon/hermes/inspector/RuntimeAdapter.h index bfe32c983290a4..dcf8a008b88a22 100644 --- a/ReactCommon/hermes/inspector/RuntimeAdapter.h +++ b/ReactCommon/hermes/inspector/RuntimeAdapter.h @@ -11,6 +11,18 @@ #include +#ifndef INSPECTOR_EXPORT +#ifdef _MSC_VER +#ifdef CREATE_SHARED_LIBRARY +#define INSPECTOR_EXPORT __declspec(dllexport) +#else +#define INSPECTOR_EXPORT +#endif // CREATE_SHARED_LIBRARY +#else // _MSC_VER +#define INSPECTOR_EXPORT __attribute__((visibility("default"))) +#endif // _MSC_VER +#endif // !defined(INSPECTOR_EXPORT) + namespace facebook { namespace hermes { namespace inspector { @@ -20,7 +32,7 @@ namespace inspector { * runtime object should stay alive for at least as long as the RuntimeAdapter * is alive. */ -class RuntimeAdapter { +class INSPECTOR_EXPORT RuntimeAdapter { public: virtual ~RuntimeAdapter() = 0; @@ -49,7 +61,7 @@ class RuntimeAdapter { * uses shared_ptr to hold on to the runtime. It's generally only used in tests, * since it does not implement tickleJs. */ -class SharedRuntimeAdapter : public RuntimeAdapter { +class INSPECTOR_EXPORT SharedRuntimeAdapter : public RuntimeAdapter { public: SharedRuntimeAdapter( std::shared_ptr runtime, diff --git a/ReactCommon/hermes/inspector/chrome/Connection.h b/ReactCommon/hermes/inspector/chrome/Connection.h index d8c0fe3197e947..0e49e69e0b0d2c 100644 --- a/ReactCommon/hermes/inspector/chrome/Connection.h +++ b/ReactCommon/hermes/inspector/chrome/Connection.h @@ -5,7 +5,10 @@ * LICENSE file in the root directory of this source tree. */ -#pragma once +// using include guards instead of #pragma once due to compile issues +// with MSVC and BUCK +#ifndef HERMES_INSPECTOR_CONNECTION_H +#define HERMES_INSPECTOR_CONNECTION_H #include #include @@ -21,7 +24,7 @@ namespace inspector { namespace chrome { /// Connection is a duplex connection between the client and the debugger. -class Connection { +class INSPECTOR_EXPORT Connection { public: /// Connection constructor enables the debugger on the provided runtime. This /// should generally called before you start running any JS in the runtime. @@ -60,3 +63,5 @@ class Connection { } // namespace inspector } // namespace hermes } // namespace facebook + +#endif // HERMES_INSPECTOR_CONNECTION_H diff --git a/ReactCommon/jsi/jsi/instrumentation.h b/ReactCommon/jsi/jsi/instrumentation.h index 548a8c5cad8c7f..04c76ce2594d62 100644 --- a/ReactCommon/jsi/jsi/instrumentation.h +++ b/ReactCommon/jsi/jsi/instrumentation.h @@ -21,7 +21,7 @@ namespace jsi { /// controls the instrumentation of. /// None of these functions should return newly created jsi values, nor should /// it modify the values of any jsi values in the heap (although GCs are fine). -class Instrumentation { +class JSI_EXPORT Instrumentation { public: virtual ~Instrumentation() = default; diff --git a/ReactCommon/jsi/jsi/jsi.h b/ReactCommon/jsi/jsi/jsi.h index 67823488442ab8..25c152227e6d57 100644 --- a/ReactCommon/jsi/jsi/jsi.h +++ b/ReactCommon/jsi/jsi/jsi.h @@ -17,11 +17,11 @@ #ifndef JSI_EXPORT #ifdef _MSC_VER -#ifdef JSI_CREATE_SHARED_LIBRARY +#ifdef CREATE_SHARED_LIBRARY #define JSI_EXPORT __declspec(dllexport) #else #define JSI_EXPORT -#endif // JSI_CREATE_SHARED_LIBRARY +#endif // CREATE_SHARED_LIBRARY #else // _MSC_VER #define JSI_EXPORT __attribute__((visibility("default"))) #endif // _MSC_VER @@ -31,14 +31,14 @@ class FBJSRuntime; namespace facebook { namespace jsi { -class Buffer { +class JSI_EXPORT Buffer { public: virtual ~Buffer(); virtual size_t size() const = 0; virtual const uint8_t* data() const = 0; }; -class StringBuffer : public Buffer { +class JSI_EXPORT StringBuffer : public Buffer { public: StringBuffer(std::string s) : s_(std::move(s)) {} size_t size() const override { @@ -56,7 +56,7 @@ class StringBuffer : public Buffer { /// form optimized for execution, in a runtime-specific way. Construct one via /// jsi::Runtime::prepareJavaScript(). /// ** This is an experimental API that is subject to change. ** -class PreparedJavaScript { +class JSI_EXPORT PreparedJavaScript { protected: PreparedJavaScript() = default; @@ -145,7 +145,7 @@ class JSI_EXPORT HostObject { /// in a non-Runtime-managed object, and not clean it up before the Runtime /// is shut down. If your lifecycle is such that avoiding this is hard, /// you will probably need to do use your own locks. -class Runtime { +class JSI_EXPORT Runtime { public: virtual ~Runtime(); @@ -326,7 +326,7 @@ class Runtime { }; // Base class for pointer-storing types. -class Pointer { +class JSI_EXPORT Pointer { protected: explicit Pointer(Pointer&& other) : ptr_(other.ptr_) { other.ptr_ = nullptr; @@ -349,7 +349,7 @@ class Pointer { }; /// Represents something that can be a JS property key. Movable, not copyable. -class PropNameID : public Pointer { +class JSI_EXPORT PropNameID : public Pointer { public: using Pointer::Pointer; @@ -423,7 +423,7 @@ class PropNameID : public Pointer { /// the debugger not to crash when a Symbol is a property in an Object /// or element in an array. Complete support for creating will come /// later. -class Symbol : public Pointer { +class JSI_EXPORT Symbol : public Pointer { public: using Pointer::Pointer; @@ -446,7 +446,7 @@ class Symbol : public Pointer { }; /// Represents a JS String. Movable, not copyable. -class String : public Pointer { +class JSI_EXPORT String : public Pointer { public: using Pointer::Pointer; @@ -504,7 +504,7 @@ class Array; class Function; /// Represents a JS Object. Movable, not copyable. -class Object : public Pointer { +class JSI_EXPORT Object : public Pointer { public: using Pointer::Pointer; @@ -692,7 +692,7 @@ class Object : public Pointer { /// Represents a weak reference to a JS Object. If the only reference /// to an Object are these, the object is eligible for GC. Method /// names are inspired by C++ weak_ptr. Movable, not copyable. -class WeakObject : public Pointer { +class JSI_EXPORT WeakObject : public Pointer { public: using Pointer::Pointer; @@ -714,7 +714,7 @@ class WeakObject : public Pointer { /// Represents a JS Object which can be efficiently used as an array /// with integral indices. -class Array : public Object { +class JSI_EXPORT Array : public Object { public: Array(Array&&) = default; /// Creates a new Array instance, with \c length undefined elements. @@ -769,7 +769,7 @@ class Array : public Object { }; /// Represents a JSArrayBuffer -class ArrayBuffer : public Object { +class JSI_EXPORT ArrayBuffer : public Object { public: ArrayBuffer(ArrayBuffer&&) = default; ArrayBuffer& operator=(ArrayBuffer&&) = default; @@ -796,7 +796,7 @@ class ArrayBuffer : public Object { }; /// Represents a JS Object which is guaranteed to be Callable. -class Function : public Object { +class JSI_EXPORT Function : public Object { public: Function(Function&&) = default; Function& operator=(Function&&) = default; @@ -906,7 +906,7 @@ class Function : public Object { /// Represents any JS Value (undefined, null, boolean, number, symbol, /// string, or object). Movable, or explicitly copyable (has no copy /// ctor). -class Value { +class JSI_EXPORT Value { public: /// Default ctor creates an \c undefined JS value. Value() : Value(UndefinedKind) {} @@ -1178,7 +1178,7 @@ class Value { /// Instances of this class are intended to be created as automatic stack /// variables in which case destructor calls don't require any additional /// locking, provided that the lock (if any) is managed with RAII helpers. -class Scope { +class JSI_EXPORT Scope { public: explicit Scope(Runtime& rt) : rt_(rt), prv_(rt.pushScope()) {} ~Scope() { diff --git a/ReactCommon/jsinspector/InspectorInterfaces.h b/ReactCommon/jsinspector/InspectorInterfaces.h index 32178e7b9a0e37..345434be2f676d 100644 --- a/ReactCommon/jsinspector/InspectorInterfaces.h +++ b/ReactCommon/jsinspector/InspectorInterfaces.h @@ -12,6 +12,18 @@ #include #include +#ifndef JSINSPECTOR_EXPORT +#ifdef _MSC_VER +#ifdef CREATE_SHARED_LIBRARY +#define JSINSPECTOR_EXPORT __declspec(dllexport) +#else +#define JSINSPECTOR_EXPORT +#endif // CREATE_SHARED_LIBRARY +#else // _MSC_VER +#define JSINSPECTOR_EXPORT __attribute__((visibility("default"))) +#endif // _MSC_VER +#endif // !defined(JSINSPECTOR_EXPORT) + namespace facebook { namespace react { @@ -27,7 +39,7 @@ struct InspectorPage { }; /// IRemoteConnection allows the VM to send debugger messages to the client. -class IRemoteConnection : public IDestructible { +class JSINSPECTOR_EXPORT IRemoteConnection : public IDestructible { public: virtual ~IRemoteConnection() = 0; virtual void onMessage(std::string message) = 0; @@ -35,7 +47,7 @@ class IRemoteConnection : public IDestructible { }; /// ILocalConnection allows the client to send debugger messages to the VM. -class ILocalConnection : public IDestructible { +class JSINSPECTOR_EXPORT ILocalConnection : public IDestructible { public: virtual ~ILocalConnection() = 0; virtual void sendMessage(std::string message) = 0; @@ -43,7 +55,7 @@ class ILocalConnection : public IDestructible { }; /// IInspector tracks debuggable JavaScript targets (pages). -class IInspector : public IDestructible { +class JSINSPECTOR_EXPORT IInspector : public IDestructible { public: using ConnectFunc = std::function( std::unique_ptr)>; From 2bc8ce15494c5ea4304d6ce5cb0e081f41519fa6 Mon Sep 17 00:00:00 2001 From: Samuel Susla Date: Mon, 24 Aug 2020 06:39:29 -0700 Subject: [PATCH 0029/1238] Introduce ConcreteStateTeller Summary: Changelog: [internal] # What is Teller? Teller is a bank's employee who deals with the customer on behalf of the bank. In Fabric's scenario it is a class that on behalf of the view deals with State. # Why do we need it? Dealing with `ConcreteState` can be complicated and patterns are often repeated among different component views. `ConcreteStateTeller` aims to resolve these issues. Examples: - You can call teller's methods without checking for nullptr (we have had crashes because of this before). - Methods are save to be called on any thread. - Mechanism to retry state update if it fails is built in. It is designed to be used from ComponentView so views don't have to talk directly to `ConcreteState`. Reviewed By: JoshuaGross, shergin Differential Revision: D23216865 fbshipit-source-id: 90a50702e036eac084f89743ebab687a67182dc0 --- .../react/renderer/core/ConcreteShadowNode.h | 2 + .../react/renderer/core/ConcreteStateTeller.h | 152 ++++++++++++++++++ 2 files changed, 154 insertions(+) create mode 100644 ReactCommon/react/renderer/core/ConcreteStateTeller.h diff --git a/ReactCommon/react/renderer/core/ConcreteShadowNode.h b/ReactCommon/react/renderer/core/ConcreteShadowNode.h index 754194b01b93e5..e2c601a8858a1d 100644 --- a/ReactCommon/react/renderer/core/ConcreteShadowNode.h +++ b/ReactCommon/react/renderer/core/ConcreteShadowNode.h @@ -8,6 +8,7 @@ #pragma once #include +#include #include #include #include @@ -48,6 +49,7 @@ class ConcreteShadowNode : public BaseShadowNodeT { using SharedConcreteEventEmitter = std::shared_ptr; using SharedConcreteShadowNode = std::shared_ptr; using ConcreteState = ConcreteState; + using ConcreteStateTeller = ConcreteStateTeller; using ConcreteStateData = StateDataT; static ComponentName Name() { diff --git a/ReactCommon/react/renderer/core/ConcreteStateTeller.h b/ReactCommon/react/renderer/core/ConcreteStateTeller.h new file mode 100644 index 00000000000000..2354ae0daaf7ee --- /dev/null +++ b/ReactCommon/react/renderer/core/ConcreteStateTeller.h @@ -0,0 +1,152 @@ +/* + * 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. + */ + +#pragma once + +#include +#include +#include + +namespace facebook { +namespace react { + +/* + * Wrapper for `ConreteState` class designed to make interactions with + * ConcreteState easier. + */ +template +class ConcreteStateTeller { + public: + using Data = typename ConcreteStateT::Data; + + /* + * Sets backing `ConcreteState` on which all the methods will be called. + * Can be called from any thread. + */ + void setConcreteState(State::Shared const &state) { + std::lock_guard lock(mutex_); + concreteState_ = std::static_pointer_cast(state); + } + + /* + * Removes reference to `ConcreteState` previously set in `setConcreteState`. + * Can be called from any thread. + */ + void invalidate() { + std::lock_guard lock(mutex_); + concreteState_ = nullptr; + } + + /* + * Returns data if state isn't nullptr. + * Can be called from any thread. + */ + better::optional getData() const { + std::lock_guard lock(mutex_); + if (concreteState_) { + return concreteState_->getData(); + } else { + return {}; + } + } + + /* + * Returns true if backing state isn't nullptr, false otherwise. + * Can be called from any thread. + */ + bool isValid() const { + std::lock_guard lock(mutex_); + return concreteState_ != nullptr; + } + + /* + * Initiate a state update process with given new data and priority. + * This is a simplified convenience version of the method that receives a + * function for cases where a new value of data does not depend on an old + * value. + */ + void updateState( + Data &&newData, + EventPriority priority = EventPriority::AsynchronousUnbatched) const { + updateState( + [data = std::move(newData)](Data const &oldData) -> Data { + return std::move(data); + }, + priority); + } + + /* + * Initiate a state update process with a given function (that transforms an + * old data value to a new one) and priority. The update function can be + * called from any thread any moment later. The function can be called only + * once or not called at all (in the case where the node was already unmounted + * and updating makes no sense). The state update operation might fail in case + * of conflict. + */ + void updateState( + std::function callback, + EventPriority priority = EventPriority::AsynchronousBatched) const { + std::shared_ptr concreteState; + { + std::lock_guard lock(mutex_); + if (!concreteState_) { + return; + } + concreteState = concreteState_; + } + + concreteState->updateState( + callback, + [=]() { + updateStateRetryIfNecesarry_(concreteState, callback, priority, 1); + }, + priority); + } + + private: + /* + * Protected by `mutex_`. + */ + std::shared_ptr concreteState_; + + /* + * Protects `concreteState_`. + */ + std::mutex mutable mutex_; + + void updateStateRetryIfNecesarry_( + std::shared_ptr concreteState, + std::function callback, + EventPriority priority, + int retryCount) const { + { + std::lock_guard lock(mutex_); + + if (concreteState != concreteState_) { + LOG(WARNING) << "ConcreteState_ changed while retrying"; + return; + } + } + + if (retryCount > 60) { + LOG(ERROR) << "Exceeded 60 retries"; + assert(false); + return; + } + + concreteState->updateState( + callback, + [=] { + updateStateRetryIfNecesarry_( + concreteState, callback, priority, retryCount + 1); + }, + priority); + } +}; + +} // namespace react +} // namespace facebook From e454863bca5c2ddb321a511bfa96cb1f5029a9c5 Mon Sep 17 00:00:00 2001 From: Samuel Susla Date: Mon, 24 Aug 2020 06:39:29 -0700 Subject: [PATCH 0030/1238] Use ConcreteStateTeller in RCTTextInputComponentView Summary: Changelog: [Internal] Reviewed By: JoshuaGross Differential Revision: D23216864 fbshipit-source-id: 2b82e2d43cc694251a1873ad9059eff4abca4e73 --- .../TextInput/RCTTextInputComponentView.mm | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm b/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm index 1a461aa93f94ec..6652b065b03770 100644 --- a/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm +++ b/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm @@ -29,7 +29,7 @@ @interface RCTTextInputComponentView () *_backedTextInputView; NSUInteger _mostRecentEventCount; NSAttributedString *_lastStringStateWasUpdatedWith; @@ -214,21 +214,21 @@ - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const & - (void)updateState:(State::Shared const &)state oldState:(State::Shared const &)oldState { - _state = std::static_pointer_cast(state); + _stateTeller.setConcreteState(state); - if (!_state) { + if (!_stateTeller.isValid()) { assert(false && "State is `null` for component."); _backedTextInputView.attributedText = nil; return; } - auto data = _state->getData(); + auto data = _stateTeller.getData().value(); if (!oldState) { - _mostRecentEventCount = _state->getData().mostRecentEventCount; + _mostRecentEventCount = data.mostRecentEventCount; } - if (_mostRecentEventCount == _state->getData().mostRecentEventCount) { + if (_mostRecentEventCount == data.mostRecentEventCount) { _comingFromJS = YES; [self _setAttributedString:RCTNSAttributedStringFromAttributedStringBox(data.attributedStringBox)]; _comingFromJS = NO; @@ -251,7 +251,7 @@ - (void)prepareForRecycle [super prepareForRecycle]; _backedTextInputView.attributedText = nil; _mostRecentEventCount = 0; - _state.reset(); + _stateTeller.invalidate(); _comingFromJS = NO; _lastStringStateWasUpdatedWith = nil; _ignoreNextTextInputCall = NO; @@ -442,16 +442,17 @@ - (TextInputMetrics)_textInputMetrics - (void)_updateState { - if (!_state) { + if (!_stateTeller.isValid()) { return; } + NSAttributedString *attributedString = _backedTextInputView.attributedText; - auto data = _state->getData(); + auto data = _stateTeller.getData().value(); _lastStringStateWasUpdatedWith = attributedString; data.attributedStringBox = RCTAttributedStringBoxFromNSAttributedString(attributedString); _mostRecentEventCount += _comingFromJS ? 0 : 1; data.mostRecentEventCount = _mostRecentEventCount; - _state->updateState(std::move(data)); + _stateTeller.updateState(std::move(data)); } - (AttributedString::Range)_selectionRange From 724952e5d6326a5e5da878095b00825a2fbb2552 Mon Sep 17 00:00:00 2001 From: Samuel Susla Date: Mon, 24 Aug 2020 06:39:29 -0700 Subject: [PATCH 0031/1238] Use ConcreteStateTeller in RCTSafeAreaViewComponentView Summary: Changelog: [Internal] Reviewed By: JoshuaGross Differential Revision: D23238703 fbshipit-source-id: 67596194b599ce8d39a6e7403bf61dce0fd61434 --- .../SafeAreaView/RCTSafeAreaViewComponentView.mm | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/React/Fabric/Mounting/ComponentViews/SafeAreaView/RCTSafeAreaViewComponentView.mm b/React/Fabric/Mounting/ComponentViews/SafeAreaView/RCTSafeAreaViewComponentView.mm index b3ef229906db3d..c54ea89bcac19f 100644 --- a/React/Fabric/Mounting/ComponentViews/SafeAreaView/RCTSafeAreaViewComponentView.mm +++ b/React/Fabric/Mounting/ComponentViews/SafeAreaView/RCTSafeAreaViewComponentView.mm @@ -17,7 +17,7 @@ using namespace facebook::react; @implementation RCTSafeAreaViewComponentView { - SafeAreaViewShadowNode::ConcreteState::Shared _state; + SafeAreaViewShadowNode::ConcreteStateTeller _stateTeller; EdgeInsets _lastPaddingStateWasUpdatedWith; } @@ -50,10 +50,6 @@ - (void)safeAreaInsetsDidChange - (void)_updateStateIfNecessary { - if (!_state) { - return; - } - UIEdgeInsets insets = [self _safeAreaInsets]; insets.left = RCTRoundPixelValue(insets.left); insets.top = RCTRoundPixelValue(insets.top); @@ -70,22 +66,21 @@ - (void)_updateStateIfNecessary } _lastPaddingStateWasUpdatedWith = newPadding; - _state->updateState(SafeAreaViewState{newPadding}); + _stateTeller.updateState(SafeAreaViewState{newPadding}); } #pragma mark - RCTComponentViewProtocol -- (void)updateState:(facebook::react::State::Shared const &)state - oldState:(facebook::react::State::Shared const &)oldState +- (void)updateState:(State::Shared const &)state oldState:(State::Shared const &)oldState { - _state = std::static_pointer_cast(state); + _stateTeller.setConcreteState(state); [self _updateStateIfNecessary]; } - (void)prepareForRecycle { [super prepareForRecycle]; - _state.reset(); + _stateTeller.invalidate(); _lastPaddingStateWasUpdatedWith = {}; } From ca091b009ad6870de94cc318d86f6afb66efd632 Mon Sep 17 00:00:00 2001 From: Samuel Susla Date: Mon, 24 Aug 2020 06:39:29 -0700 Subject: [PATCH 0032/1238] Use ConcreteStateTeller in RCTScrollViewComponentView Summary: Changelog: [Internal] Reviewed By: JoshuaGross Differential Revision: D23238812 fbshipit-source-id: 8c777ae1264cfade507bfd336eefbe86ffb94b8f --- .../ScrollView/RCTScrollViewComponentView.mm | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm b/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm index 438145381f3cee..859b4582980e8a 100644 --- a/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm +++ b/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm @@ -48,7 +48,7 @@ @interface RCTScrollViewComponentView () (state)); - _state = std::static_pointer_cast(state); - auto &data = _state->getData(); + _stateTeller.setConcreteState(state); + auto data = _stateTeller.getData().value(); auto contentOffset = RCTCGPointFromPoint(data.contentOffset); if (!oldState && !CGPointEqualToPoint(contentOffset, CGPointZero)) { @@ -284,11 +284,8 @@ - (ScrollViewMetrics)_scrollViewMetrics - (void)_updateStateWithContentOffset { - if (!_state) { - return; - } auto contentOffset = RCTPointFromCGPoint(_scrollView.contentOffset); - _state->updateState([contentOffset](ScrollViewShadowNode::ConcreteState::Data const &data) { + _stateTeller.updateState([contentOffset](ScrollViewShadowNode::ConcreteState::Data const &data) { auto newData = data; newData.contentOffset = contentOffset; return newData; @@ -299,7 +296,7 @@ - (void)prepareForRecycle { const auto &props = *std::static_pointer_cast(_props); _scrollView.contentOffset = RCTCGPointFromPoint(props.contentOffset); - _state.reset(); + _stateTeller.invalidate(); _isUserTriggeredScrolling = NO; [super prepareForRecycle]; } From c2dab01c62fa271174eae7d9e71c72c1b26cb3be Mon Sep 17 00:00:00 2001 From: Samuel Susla Date: Mon, 24 Aug 2020 06:39:29 -0700 Subject: [PATCH 0033/1238] Use ConcreteStateTeller in RCTModalHostViewComponentView Summary: Changelog: [Internal] Reviewed By: JoshuaGross Differential Revision: D23239096 fbshipit-source-id: b82301e5db48861d6d241abd681df38701e3ac44 --- .../Modal/RCTModalHostViewComponentView.mm | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/React/Fabric/Mounting/ComponentViews/Modal/RCTModalHostViewComponentView.mm b/React/Fabric/Mounting/ComponentViews/Modal/RCTModalHostViewComponentView.mm index a1df5a6d0cc8a3..dfe980c3679de5 100644 --- a/React/Fabric/Mounting/ComponentViews/Modal/RCTModalHostViewComponentView.mm +++ b/React/Fabric/Mounting/ComponentViews/Modal/RCTModalHostViewComponentView.mm @@ -100,7 +100,7 @@ @interface RCTModalHostViewComponentView () onOrientationChange(onOrientationChangeStruct(newBounds)); } - if (_state != nullptr) { - auto newState = ModalHostViewState{RCTSizeFromCGSize(newBounds.size)}; - _state->updateState(std::move(newState)); - } + auto newState = ModalHostViewState{RCTSizeFromCGSize(newBounds.size)}; + _stateTeller.updateState(std::move(newState)); } #pragma mark - RCTComponentViewProtocol @@ -198,7 +196,7 @@ + (ComponentDescriptorProvider)componentDescriptorProvider - (void)prepareForRecycle { [super prepareForRecycle]; - _state.reset(); + _stateTeller.invalidate(); _isPresented = NO; } @@ -219,10 +217,9 @@ - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const & [super updateProps:props oldProps:oldProps]; } -- (void)updateState:(facebook::react::State::Shared const &)state - oldState:(facebook::react::State::Shared const &)oldState +- (void)updateState:(State::Shared const &)state oldState:(State::Shared const &)oldState { - _state = std::static_pointer_cast(state); + _stateTeller.setConcreteState(state); } - (void)mountChildComponentView:(UIView *)childComponentView index:(NSInteger)index From 9a5807162c286abf7fddeaf7bafc3130813d3f9c Mon Sep 17 00:00:00 2001 From: Samuel Susla Date: Mon, 24 Aug 2020 06:39:29 -0700 Subject: [PATCH 0034/1238] Use ConcreteStateTeller in RCTParagraphComponentView Summary: Changelog: [Internal] Reviewed By: JoshuaGross Differential Revision: D23239100 fbshipit-source-id: 10d10a369cb7ec82d2f6118a21ec70c2cc20abb3 --- .../Text/RCTParagraphComponentView.mm | 47 ++++++++++--------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/React/Fabric/Mounting/ComponentViews/Text/RCTParagraphComponentView.mm b/React/Fabric/Mounting/ComponentViews/Text/RCTParagraphComponentView.mm index 7756a7761545d3..438e513c7aadbf 100644 --- a/React/Fabric/Mounting/ComponentViews/Text/RCTParagraphComponentView.mm +++ b/React/Fabric/Mounting/ComponentViews/Text/RCTParagraphComponentView.mm @@ -25,7 +25,7 @@ using namespace facebook::react; @implementation RCTParagraphComponentView { - ParagraphShadowNode::ConcreteState::Shared _state; + ParagraphShadowNode::ConcreteStateTeller _stateTeller; ParagraphAttributes _paragraphAttributes; RCTParagraphComponentAccessibilityProvider *_accessibilityProvider; } @@ -58,11 +58,12 @@ - (NSString *)description - (NSAttributedString *_Nullable)attributedText { - if (!_state) { + auto data = _stateTeller.getData(); + if (!data.hasValue()) { return nil; } - return RCTNSAttributedStringFromAttributedString(_state->getData().attributedString); + return RCTNSAttributedStringFromAttributedString(data.value().attributedString); } #pragma mark - RCTComponentViewProtocol @@ -90,23 +91,24 @@ - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const & - (void)updateState:(State::Shared const &)state oldState:(State::Shared const &)oldState { - _state = std::static_pointer_cast(state); + _stateTeller.setConcreteState(state); [self setNeedsDisplay]; } - (void)prepareForRecycle { [super prepareForRecycle]; - _state.reset(); + _stateTeller.invalidate(); } - (void)drawRect:(CGRect)rect { - if (!_state) { + auto data = _stateTeller.getData(); + if (!data.hasValue()) { return; } - auto textLayoutManager = _state->getData().layoutManager; + auto textLayoutManager = data.value().layoutManager; assert(textLayoutManager && "TextLayoutManager must not be `nullptr`."); if (!textLayoutManager) { @@ -118,7 +120,7 @@ - (void)drawRect:(CGRect)rect CGRect frame = RCTCGRectFromRect(_layoutMetrics.getContentFrame()); - [nativeTextLayoutManager drawAttributedString:_state->getData().attributedString + [nativeTextLayoutManager drawAttributedString:data.value().attributedString paragraphAttributes:_paragraphAttributes frame:frame]; } @@ -132,25 +134,27 @@ - (NSString *)accessibilityLabel return superAccessibilityLabel; } - if (!_state) { + auto data = _stateTeller.getData(); + + if (!data.hasValue()) { return nil; } - return RCTNSStringFromString(_state->getData().attributedString.getString()); + return RCTNSStringFromString(data.value().attributedString.getString()); } - (NSArray *)accessibilityElements { - if (![_accessibilityProvider isUpToDate:_state->getData().attributedString]) { + auto data = _stateTeller.getData().value(); + if (![_accessibilityProvider isUpToDate:data.attributedString]) { RCTTextLayoutManager *textLayoutManager = - (RCTTextLayoutManager *)unwrapManagedObject(_state->getData().layoutManager->getNativeTextLayoutManager()); + (RCTTextLayoutManager *)unwrapManagedObject(data.layoutManager->getNativeTextLayoutManager()); CGRect frame = RCTCGRectFromRect(_layoutMetrics.getContentFrame()); - _accessibilityProvider = - [[RCTParagraphComponentAccessibilityProvider alloc] initWithString:_state->getData().attributedString - layoutManager:textLayoutManager - paragraphAttributes:_state->getData().paragraphAttributes - frame:frame - view:self]; + _accessibilityProvider = [[RCTParagraphComponentAccessibilityProvider alloc] initWithString:data.attributedString + layoutManager:textLayoutManager + paragraphAttributes:data.paragraphAttributes + frame:frame + view:self]; } self.isAccessibilityElement = NO; @@ -164,11 +168,12 @@ - (UIAccessibilityTraits)accessibilityTraits - (SharedTouchEventEmitter)touchEventEmitterAtPoint:(CGPoint)point { - if (!_state) { + auto data = _stateTeller.getData(); + if (!data.hasValue()) { return _eventEmitter; } - auto textLayoutManager = _state->getData().layoutManager; + auto textLayoutManager = data.value().layoutManager; assert(textLayoutManager && "TextLayoutManager must not be `nullptr`."); @@ -180,7 +185,7 @@ - (SharedTouchEventEmitter)touchEventEmitterAtPoint:(CGPoint)point (RCTTextLayoutManager *)unwrapManagedObject(textLayoutManager->getNativeTextLayoutManager()); CGRect frame = RCTCGRectFromRect(_layoutMetrics.getContentFrame()); - auto eventEmitter = [nativeTextLayoutManager getEventEmitterWithAttributeString:_state->getData().attributedString + auto eventEmitter = [nativeTextLayoutManager getEventEmitterWithAttributeString:data.value().attributedString paragraphAttributes:_paragraphAttributes frame:frame atPoint:point]; From 0b532e1be71b956423855355dc9178f5bee589d0 Mon Sep 17 00:00:00 2001 From: Samuel Susla Date: Mon, 24 Aug 2020 06:39:29 -0700 Subject: [PATCH 0035/1238] Use ConcreteStateTeller in RCTLegacyViewManagerInteropComponentView Summary: Changelog: [Internal] Reviewed By: JoshuaGross Differential Revision: D23239097 fbshipit-source-id: 4c0d7b24917509d3d9660098349c226ad42e832e --- .../RCTLegacyViewManagerInteropComponentView.mm | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/React/Fabric/Mounting/ComponentViews/LegacyViewManagerInterop/RCTLegacyViewManagerInteropComponentView.mm b/React/Fabric/Mounting/ComponentViews/LegacyViewManagerInterop/RCTLegacyViewManagerInteropComponentView.mm index 7db1533ca73e46..2bb5ef0168e930 100644 --- a/React/Fabric/Mounting/ComponentViews/LegacyViewManagerInterop/RCTLegacyViewManagerInteropComponentView.mm +++ b/React/Fabric/Mounting/ComponentViews/LegacyViewManagerInterop/RCTLegacyViewManagerInteropComponentView.mm @@ -22,7 +22,7 @@ @implementation RCTLegacyViewManagerInteropComponentView { NSMutableArray *_viewsToBeMounted; NSMutableArray *_viewsToBeUnmounted; RCTLegacyViewManagerInteropCoordinatorAdapter *_adapter; - LegacyViewManagerInteropShadowNode::ConcreteState::Shared _state; + LegacyViewManagerInteropShadowNode::ConcreteStateTeller _stateTeller; } - (instancetype)initWithFrame:(CGRect)frame @@ -64,9 +64,9 @@ + (void)supportLegacyViewManagerWithName:(NSString *)componentName - (RCTLegacyViewManagerInteropCoordinator *)coordinator { - if (_state != nullptr) { - const auto &state = _state->getData(); - return unwrapManagedObject(state.coordinator); + auto data = _stateTeller.getData(); + if (data.hasValue()) { + return unwrapManagedObject(data.value().coordinator); } else { return nil; } @@ -74,9 +74,7 @@ - (RCTLegacyViewManagerInteropCoordinator *)coordinator - (NSString *)componentViewName_DO_NOT_USE_THIS_IS_BROKEN { - const auto &state = _state->getData(); - RCTLegacyViewManagerInteropCoordinator *coordinator = unwrapManagedObject(state.coordinator); - return coordinator.componentViewName; + return self.coordinator.componentViewName; } #pragma mark - RCTComponentViewProtocol @@ -86,7 +84,7 @@ - (void)prepareForRecycle _adapter = nil; [_viewsToBeMounted removeAllObjects]; [_viewsToBeUnmounted removeAllObjects]; - _state.reset(); + _stateTeller.invalidate(); self.contentView = nil; [super prepareForRecycle]; } @@ -111,7 +109,7 @@ + (ComponentDescriptorProvider)componentDescriptorProvider - (void)updateState:(State::Shared const &)state oldState:(State::Shared const &)oldState { - _state = std::static_pointer_cast(state); + _stateTeller.setConcreteState(state); } - (void)finalizeUpdates:(RNComponentViewUpdateMask)updateMask From 0f7a1145fffe9d9c21cef1f8576f6545b887c426 Mon Sep 17 00:00:00 2001 From: Samuel Susla Date: Mon, 24 Aug 2020 06:39:29 -0700 Subject: [PATCH 0036/1238] Use ConcreteStateTeller in RCTInputAccessoryComponentView Summary: Changelog: [Internal] Reviewed By: JoshuaGross Differential Revision: D23239095 fbshipit-source-id: a3324b5df6e6bd7508d74b66de9235852d828bbd --- .../RCTInputAccessoryComponentView.mm | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/React/Fabric/Mounting/ComponentViews/InputAccessory/RCTInputAccessoryComponentView.mm b/React/Fabric/Mounting/ComponentViews/InputAccessory/RCTInputAccessoryComponentView.mm index 7ee2f208932540..a403b45bd9d264 100644 --- a/React/Fabric/Mounting/ComponentViews/InputAccessory/RCTInputAccessoryComponentView.mm +++ b/React/Fabric/Mounting/ComponentViews/InputAccessory/RCTInputAccessoryComponentView.mm @@ -40,7 +40,7 @@ } @implementation RCTInputAccessoryComponentView { - InputAccessoryShadowNode::ConcreteState::Shared _state; + InputAccessoryShadowNode::ConcreteStateTeller _stateTeller; RCTInputAccessoryContentView *_contentView; RCTSurfaceTouchHandler *_touchHandler; UIView __weak *_textInput; @@ -117,16 +117,15 @@ - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const & self.hidden = true; } -- (void)updateState:(const facebook::react::State::Shared &)state - oldState:(const facebook::react::State::Shared &)oldState +- (void)updateState:(State::Shared const &)state oldState:(State::Shared const &)oldState { - _state = std::static_pointer_cast(state); - CGSize oldScreenSize = RCTCGSizeFromSize(_state->getData().screenSize); + _stateTeller.setConcreteState(state); + CGSize oldScreenSize = RCTCGSizeFromSize(_stateTeller.getData().value().screenSize); CGSize screenSize = [[UIScreen mainScreen] bounds].size; screenSize.height = std::nan(""); if (oldScreenSize.width != screenSize.width) { auto stateData = InputAccessoryState{RCTSizeFromCGSize(screenSize)}; - _state->updateState(std::move(stateData)); + _stateTeller.updateState(std::move(stateData)); } } @@ -141,7 +140,7 @@ - (void)updateLayoutMetrics:(const facebook::react::LayoutMetrics &)layoutMetric - (void)prepareForRecycle { [super prepareForRecycle]; - _state.reset(); + _stateTeller.invalidate(); _textInput = nil; } From 1704a725c5ec1e3d53c39b0830fb79e3597d818e Mon Sep 17 00:00:00 2001 From: Samuel Susla Date: Mon, 24 Aug 2020 06:39:29 -0700 Subject: [PATCH 0037/1238] Use ConcreteStateTeller in RCTImageComponentView Summary: Changelog: [Internal] Reviewed By: JoshuaGross Differential Revision: D23239098 fbshipit-source-id: fa558e705e121f3d3fbded80ae99e5f51c80ae4a --- .../Image/RCTImageComponentView.mm | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/React/Fabric/Mounting/ComponentViews/Image/RCTImageComponentView.mm b/React/Fabric/Mounting/ComponentViews/Image/RCTImageComponentView.mm index e617f20b72c702..0de4b95a59235a 100644 --- a/React/Fabric/Mounting/ComponentViews/Image/RCTImageComponentView.mm +++ b/React/Fabric/Mounting/ComponentViews/Image/RCTImageComponentView.mm @@ -26,7 +26,7 @@ @interface RCTImageComponentView () @implementation RCTImageComponentView { UIImageView *_imageView; - ImageShadowNode::ConcreteState::Shared _state; + ImageShadowNode::ConcreteStateTeller _stateTeller; ImageResponseObserverCoordinator const *_coordinator; RCTImageResponseObserverProxy _imageResponseObserverProxy; } @@ -84,9 +84,9 @@ - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const & - (void)updateState:(State::Shared const &)state oldState:(State::Shared const &)oldState { - _state = std::static_pointer_cast(state); + _stateTeller.setConcreteState(state); auto _oldState = std::static_pointer_cast(oldState); - auto data = _state->getData(); + auto data = _stateTeller.getData().value(); // This call (setting `coordinator`) must be unconditional (at the same block as setting `State`) // because the setter stores a raw pointer to object that `State` owns. @@ -120,7 +120,7 @@ - (void)prepareForRecycle [super prepareForRecycle]; self.coordinator = nullptr; _imageView.image = nil; - _state.reset(); + _stateTeller.invalidate(); } - (void)dealloc @@ -132,7 +132,7 @@ - (void)dealloc - (void)didReceiveImage:(UIImage *)image fromObserver:(void const *)observer { - if (!_eventEmitter || !_state) { + if (!_eventEmitter || !_stateTeller.isValid()) { // Notifications are delivered asynchronously and might arrive after the view is already recycled. // In the future, we should incorporate an `EventEmitter` into a separate object owned by `ImageRequest` or `State`. // See for more info: T46311063. @@ -158,12 +158,12 @@ - (void)didReceiveImage:(UIImage *)image fromObserver:(void const *)observer } void (^didSetImage)() = ^() { - if (!self->_state) { + auto data = self->_stateTeller.getData(); + if (!data.hasValue()) { return; } - auto data = self->_state->getData(); auto instrumentation = std::static_pointer_cast( - data.getImageRequest().getSharedImageInstrumentation()); + data.value().getImageRequest().getSharedImageInstrumentation()); if (instrumentation) { instrumentation->didSetImage(); } From 00563575bae4957469a11a6a1b2001fcfdd1d888 Mon Sep 17 00:00:00 2001 From: Samuel Susla Date: Mon, 24 Aug 2020 10:31:21 -0700 Subject: [PATCH 0038/1238] Fix native command dispatch from RCTLegacyViewManagerInteropComponentView Summary: Changelog: [Internal] # Problem In D22274782 (https://github.com/facebook/react-native/commit/fb2b49d2982399f26b93ac02b2197c0b3813a4a9) I removed integration between Paper and Fabric. However this integration was still used by `RCTLegacyViewManagerInteropComponentView` for view commands dispatch. Fix is to use `[RCTUIManager viewForReactTag:viewTag]` instead of viewRegistry. Reviewed By: shergin Differential Revision: D23291567 fbshipit-source-id: 35c50716fd8b86ae25b1534e4d8aa688c8e6e129 --- React/Views/RCTDatePickerManager.m | 6 +++--- React/Views/RCTPickerManager.m | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/React/Views/RCTDatePickerManager.m b/React/Views/RCTDatePickerManager.m index 1eca489f963230..198a4ef77ef772 100644 --- a/React/Views/RCTDatePickerManager.m +++ b/React/Views/RCTDatePickerManager.m @@ -55,13 +55,13 @@ - (UIView *)view [(RCTDatePicker *)view setDate:date]; } else { // This component is used in Fabric through LegacyInteropLayer. - // `RCTPicker` view is subview of `RCTLegacyViewManagerInteropComponentView`. + // `RCTDatePicker` view is subview of `RCTLegacyViewManagerInteropComponentView`. // `viewTag` passed as parameter to this method is tag of the `RCTLegacyViewManagerInteropComponentView`. - UIView *subview = view.subviews.firstObject; + UIView *subview = [uiManager viewForReactTag:viewTag].subviews.firstObject; if ([subview isKindOfClass:[RCTDatePicker class]]) { [(RCTDatePicker *)subview setDate:date]; } else { - RCTLogError(@"view type must be RCTPicker"); + RCTLogError(@"view type must be RCTDatePicker"); } } }]; diff --git a/React/Views/RCTPickerManager.m b/React/Views/RCTPickerManager.m index 7127656cce414d..a883f54aaccdc3 100644 --- a/React/Views/RCTPickerManager.m +++ b/React/Views/RCTPickerManager.m @@ -55,7 +55,7 @@ - (UIView *)view // This component is used in Fabric through LegacyInteropLayer. // `RCTPicker` view is subview of `RCTLegacyViewManagerInteropComponentView`. // `viewTag` passed as parameter to this method is tag of the `RCTLegacyViewManagerInteropComponentView`. - UIView *subview = view.subviews.firstObject; + UIView *subview = [uiManager viewForReactTag:viewTag].subviews.firstObject; if ([subview isKindOfClass:[RCTPicker class]]) { [(RCTPicker *)subview setSelectedIndex:index.integerValue]; } else { From d602c51996a1d9cf1ebdb51a943d89b337f76c00 Mon Sep 17 00:00:00 2001 From: Joshua Gross Date: Mon, 24 Aug 2020 11:57:11 -0700 Subject: [PATCH 0039/1238] Simplify TextInput measurements Summary: Simplify the TextInput measurement mechanism. Now, data only flows from JS->C++->Java and from Java->JS. C++ passes along AttributedStrings from JS if JS updates, and otherwise Java maintains the only source of truth. Previously we tried to keep all three in sync. This was complicated, slow, and even lead to some crashes. This feels a bit hacky but I believe it's the simplest way to achieve this short-term. Ideally, we would use something like `AttributedStringBox` and pass that to State from Java, but currently everything passed through the State system from Java must be serializable as `folly::dynamic`. So, instead, we just cache one Spannable per TextInput component and use ReactTag as the cache identifier for lookup. An interesting side-effect is that `measure` could race with TextInput updates, but the race condition favors measuring the latest text, not outdated values. Followups: - Can we do this without copying the EditText Spannable on every keystroke? Maybe this approach is too aggressive, but I don't want a background thread measuring a Spannable as it's being mutated. - Do we need to support measuring Attachments? - How can we clean up this API? It should work for now, but feels a little hacky. Changelog: [Internal] Reviewed By: mdvacca Differential Revision: D23290230 fbshipit-source-id: 832d2f397d30dfb17b77958af970d9c52a37e88b --- .../react/views/text/TextLayoutManager.java | 28 +++++- .../react/views/textinput/ReactEditText.java | 23 +++-- .../textinput/ReactTextInputManager.java | 99 ++----------------- .../AndroidTextInputShadowNode.cpp | 11 ++- .../AndroidTextInputState.cpp | 9 +- .../androidtextinput/AndroidTextInputState.h | 64 +++--------- .../textlayoutmanager/TextLayoutManager.cpp | 60 ++++++++++- .../textlayoutmanager/TextLayoutManager.h | 9 ++ 8 files changed, 149 insertions(+), 154 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManager.java index 8bde57f62d7c10..ce32acc099d816 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManager.java @@ -21,6 +21,7 @@ import android.util.LayoutDirection; import android.util.LruCache; import android.view.View; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.facebook.common.logging.FLog; import com.facebook.react.bridge.ReadableArray; @@ -33,6 +34,7 @@ import com.facebook.yoga.YogaMeasureOutput; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.ConcurrentHashMap; /** Class responsible of creating {@link Spanned} object for the JS representation of Text */ public class TextLayoutManager { @@ -57,7 +59,10 @@ public class TextLayoutManager { private static final String INCLUDE_FONT_PADDING_KEY = "includeFontPadding"; private static final String TEXT_BREAK_STRATEGY_KEY = "textBreakStrategy"; private static final String MAXIMUM_NUMBER_OF_LINES_KEY = "maximumNumberOfLines"; - private static LruCache sSpannableCache = new LruCache<>(spannableCacheSize); + private static final LruCache sSpannableCache = + new LruCache<>(spannableCacheSize); + private static final ConcurrentHashMap sTagToSpannableCache = + new ConcurrentHashMap<>(); public static boolean isRTL(ReadableMap attributedString) { ReadableArray fragments = attributedString.getArray("fragments"); @@ -70,6 +75,14 @@ public static boolean isRTL(ReadableMap attributedString) { return false; } + public static void setCachedSpannabledForTag(int reactTag, @NonNull Spannable sp) { + sTagToSpannableCache.put(reactTag, sp); + } + + public static void deleteCachedSpannableForTag(int reactTag) { + sTagToSpannableCache.remove(reactTag); + } + private static void buildSpannableFromFragment( Context context, ReadableArray fragments, @@ -227,8 +240,17 @@ public static long measureText( // TODO(5578671): Handle text direction (see View#getTextDirectionHeuristic) TextPaint textPaint = sTextPaintInstance; - Spannable text = - getOrCreateSpannableForText(context, attributedString, reactTextViewManagerCallback); + Spannable text; + if (attributedString.hasKey("cacheId")) { + int cacheId = attributedString.getInt("cacheId"); + if (sTagToSpannableCache.containsKey(cacheId)) { + text = sTagToSpannableCache.get(attributedString.getInt("cacheId")); + } else { + return 0; + } + } else { + text = getOrCreateSpannableForText(context, attributedString, reactTextViewManagerCallback); + } int textBreakStrategy = TextAttributeProps.getTextBreakStrategy( diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java index 5350aa5364a5dd..cbda60c185b8a8 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java @@ -17,6 +17,7 @@ import android.os.Bundle; import android.text.Editable; import android.text.InputType; +import android.text.SpannableString; import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.TextUtils; @@ -37,7 +38,6 @@ import androidx.core.view.AccessibilityDelegateCompat; import androidx.core.view.ViewCompat; import com.facebook.infer.annotation.Assertions; -import com.facebook.react.bridge.JavaOnlyMap; import com.facebook.react.bridge.ReactContext; import com.facebook.react.uimanager.FabricViewStateManager; import com.facebook.react.uimanager.UIManagerModule; @@ -46,6 +46,7 @@ import com.facebook.react.views.text.ReactTypefaceUtils; import com.facebook.react.views.text.TextAttributes; import com.facebook.react.views.text.TextInlineImageSpan; +import com.facebook.react.views.text.TextLayoutManager; import com.facebook.react.views.view.ReactViewBackgroundManager; import java.util.ArrayList; @@ -100,7 +101,6 @@ public class ReactEditText extends AppCompatEditText private ReactViewBackgroundManager mReactBackgroundManager; - protected @Nullable JavaOnlyMap mAttributedString = null; private final FabricViewStateManager mFabricViewStateManager = new FabricViewStateManager(); protected boolean mDisableTextDiffing = false; @@ -152,6 +152,11 @@ public boolean performAccessibilityAction(View host, int action, Bundle args) { }); } + @Override + protected void finalize() { + TextLayoutManager.deleteCachedSpannableForTag(getId()); + } + // After the text changes inside an EditText, TextView checks if a layout() has been requested. // If it has, it will not scroll the text to the end of the new text inserted, but wait for the // next layout() to be called. However, we do not perform a layout() after a requestLayout(), so @@ -481,16 +486,13 @@ public void maybeSetText(ReactTextUpdate reactTextUpdate) { return; } - if (reactTextUpdate.mAttributedString != null) { - mAttributedString = JavaOnlyMap.deepClone(reactTextUpdate.mAttributedString); - } - // The current text gets replaced with the text received from JS. However, the spans on the // current text need to be adapted to the new text. Since TextView#setText() will remove or // reset some of these spans even if they are set directly, SpannableStringBuilder#replace() is // used instead (this is also used by the keyboard implementation underneath the covers). SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(reactTextUpdate.getText()); + manageSpans(spannableStringBuilder); mContainsImages = reactTextUpdate.containsImages(); @@ -516,6 +518,11 @@ public void maybeSetText(ReactTextUpdate reactTextUpdate) { setBreakStrategy(reactTextUpdate.getTextBreakStrategy()); } } + + // Update cached spans (in Fabric only) + if (this.getFabricViewStateManager() != null) { + TextLayoutManager.setCachedSpannabledForTag(getId(), spannableStringBuilder); + } } /** @@ -848,6 +855,10 @@ public void onTextChanged(CharSequence s, int start, int before, int count) { } } + if (getFabricViewStateManager() != null) { + TextLayoutManager.setCachedSpannabledForTag(getId(), new SpannableString(getText())); + } + onContentSizeChange(); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java index c322d6e02f207c..ec3bb9a4010acc 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java @@ -35,17 +35,13 @@ import com.facebook.infer.annotation.Assertions; import com.facebook.react.bridge.Dynamic; import com.facebook.react.bridge.JSApplicationIllegalArgumentException; -import com.facebook.react.bridge.JavaOnlyArray; -import com.facebook.react.bridge.JavaOnlyMap; import com.facebook.react.bridge.ReactContext; import com.facebook.react.bridge.ReactSoftException; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.bridge.ReadableMap; import com.facebook.react.bridge.ReadableNativeMap; import com.facebook.react.bridge.ReadableType; -import com.facebook.react.bridge.WritableArray; import com.facebook.react.bridge.WritableMap; -import com.facebook.react.bridge.WritableNativeArray; import com.facebook.react.bridge.WritableNativeMap; import com.facebook.react.common.MapBuilder; import com.facebook.react.module.annotations.ReactModule; @@ -250,8 +246,6 @@ public void receiveCommand( } } - // TODO: if we're able to fill in all these values and call maybeSetText when appropriate - // I think this is all that's needed to fully support TextInput in Fabric private ReactTextUpdate getReactTextUpdate( String text, int mostRecentEventCount, int start, int end) { SpannableStringBuilder sb = new SpannableStringBuilder(); @@ -920,69 +914,12 @@ public void onTextChanged(CharSequence s, int start, int before, int count) { } // Fabric: update representation of AttributedString - final JavaOnlyMap attributedString = mEditText.mAttributedString; - if (attributedString != null && attributedString.hasKey("fragments")) { - String changedText = s.subSequence(start, start + count).toString(); - - String completeStr = attributedString.getString("string"); - String newCompleteStr = - completeStr.substring(0, start) - + changedText - + (completeStr.length() > start + before - ? completeStr.substring(start + before) - : ""); - attributedString.putString("string", newCompleteStr); - - // Loop through all fragments and change them in-place - JavaOnlyArray fragments = (JavaOnlyArray) attributedString.getArray("fragments"); - int positionInAttributedString = 0; - boolean found = false; - for (int i = 0; i < fragments.size() && !found; i++) { - JavaOnlyMap fragment = (JavaOnlyMap) fragments.getMap(i); - String fragmentStr = fragment.getString("string"); - int positionBefore = positionInAttributedString; - positionInAttributedString += fragmentStr.length(); - if (positionInAttributedString < start) { - continue; - } - - int relativePosition = start - positionBefore; - found = true; - - // Does the change span multiple Fragments? - // If so, we put any new text entirely in the first - // Fragment that we edit. For example, if you select two words - // across Fragment boundaries, "one | two", and replace them with a - // character "x", the first Fragment will replace "one " with "x", and the - // second Fragment will replace "two" with an empty string. - int remaining = fragmentStr.length() - relativePosition; - - String newString = - fragmentStr.substring(0, relativePosition) - + changedText - + (fragmentStr.substring(relativePosition + Math.min(before, remaining))); - fragment.putString("string", newString); - - // If we're changing 10 characters (before=10) and remaining=3, - // we want to remove 3 characters from this fragment (`Math.min(before, remaining)`) - // and 7 from the next Fragment (`before = 10 - 3`) - if (remaining < before) { - changedText = ""; - start += remaining; - before = before - remaining; - found = false; - } - } - } - - // Fabric: communicate to C++ layer that text has changed - // We need to call `incrementAndGetEventCounter` here explicitly because this - // update may race with other updates. - // TODO: currently WritableNativeMaps/WritableNativeArrays cannot be reused so - // we must recreate these data structures every time. It would be nice to have a - // reusable data-structure to use for TextInput because constructing these and copying - // on every keystroke is very expensive. - if (mEditText.getFabricViewStateManager().hasStateWrapper() && attributedString != null) { + if (mEditText.getFabricViewStateManager().hasStateWrapper()) { + // Fabric: communicate to C++ layer that text has changed + // We need to call `incrementAndGetEventCounter` here explicitly because this + // update may race with other updates. + // We simply pass in the cache ID, which never changes, but UpdateState will still be called + // on the native side, triggering a measure. mEditText .getFabricViewStateManager() .setState( @@ -990,24 +927,8 @@ public void onTextChanged(CharSequence s, int start, int before, int count) { @Override public WritableMap getStateUpdate() { WritableMap map = new WritableNativeMap(); - WritableMap newAttributedString = new WritableNativeMap(); - - WritableArray fragments = new WritableNativeArray(); - - for (int i = 0; i < attributedString.getArray("fragments").size(); i++) { - ReadableMap readableFragment = - attributedString.getArray("fragments").getMap(i); - WritableMap fragment = new WritableNativeMap(); - fragment.putDouble("reactTag", readableFragment.getInt("reactTag")); - fragment.putString("string", readableFragment.getString("string")); - fragments.pushMap(fragment); - } - - newAttributedString.putString("string", attributedString.getString("string")); - newAttributedString.putArray("fragments", fragments); - map.putInt("mostRecentEventCount", mEditText.incrementAndGetEventCounter()); - map.putMap("textChanged", newAttributedString); + map.putInt("opaqueCacheId", mEditText.getId()); return map; } }); @@ -1247,11 +1168,11 @@ public Object updateState( view.getFabricViewStateManager().setStateWrapper(stateWrapper); - if (stateWrapper == null) { - throw new IllegalArgumentException("Unable to update a NULL state."); - } ReadableNativeMap state = stateWrapper.getState(); + if (!state.hasKey("attributedString")) { + return null; + } ReadableMap attributedString = state.getMap("attributedString"); ReadableMap paragraphAttributes = state.getMap("paragraphAttributes"); diff --git a/ReactCommon/react/renderer/components/textinput/androidtextinput/react/renderer/components/androidtextinput/AndroidTextInputShadowNode.cpp b/ReactCommon/react/renderer/components/textinput/androidtextinput/react/renderer/components/androidtextinput/AndroidTextInputShadowNode.cpp index ca3a97dc96a9aa..42b47276bf024c 100644 --- a/ReactCommon/react/renderer/components/textinput/androidtextinput/react/renderer/components/androidtextinput/AndroidTextInputShadowNode.cpp +++ b/ReactCommon/react/renderer/components/textinput/androidtextinput/react/renderer/components/androidtextinput/AndroidTextInputShadowNode.cpp @@ -168,6 +168,15 @@ void AndroidTextInputShadowNode::updateStateIfNeeded() { Size AndroidTextInputShadowNode::measureContent( LayoutContext const &layoutContext, LayoutConstraints const &layoutConstraints) const { + if (getStateData().cachedAttributedStringId != 0) { + return textLayoutManager_ + ->measureCachedSpannableById( + getStateData().cachedAttributedStringId, + getConcreteProps().paragraphAttributes, + layoutConstraints) + .size; + } + // Layout is called right after measure. // Measure is marked as `const`, and `layout` is not; so State can be updated // during layout, but not during `measure`. If State is out-of-date in layout, @@ -179,7 +188,7 @@ Size AndroidTextInputShadowNode::measureContent( attributedString = getPlaceholderAttributedString(); } - if (attributedString.isEmpty()) { + if (attributedString.isEmpty() && getStateData().mostRecentEventCount != 0) { return {0, 0}; } diff --git a/ReactCommon/react/renderer/components/textinput/androidtextinput/react/renderer/components/androidtextinput/AndroidTextInputState.cpp b/ReactCommon/react/renderer/components/textinput/androidtextinput/react/renderer/components/androidtextinput/AndroidTextInputState.cpp index d5106ef5fed786..156835079994f7 100644 --- a/ReactCommon/react/renderer/components/textinput/androidtextinput/react/renderer/components/androidtextinput/AndroidTextInputState.cpp +++ b/ReactCommon/react/renderer/components/textinput/androidtextinput/react/renderer/components/androidtextinput/AndroidTextInputState.cpp @@ -18,9 +18,12 @@ folly::dynamic AndroidTextInputState::getDynamic() const { // Java doesn't need all fields, so we don't pass them along. folly::dynamic newState = folly::dynamic::object(); newState["mostRecentEventCount"] = mostRecentEventCount; - newState["attributedString"] = toDynamic(attributedString); - newState["paragraphAttributes"] = toDynamic(paragraphAttributes); - newState["hash"] = newState["attributedString"]["hash"]; + if (mostRecentEventCount != 0) { + newState["attributedString"] = toDynamic(attributedString); + newState["hash"] = newState["attributedString"]["hash"]; + } + newState["paragraphAttributes"] = + toDynamic(paragraphAttributes); // TODO: can we memoize this in Java? return newState; } #endif diff --git a/ReactCommon/react/renderer/components/textinput/androidtextinput/react/renderer/components/androidtextinput/AndroidTextInputState.h b/ReactCommon/react/renderer/components/textinput/androidtextinput/react/renderer/components/androidtextinput/AndroidTextInputState.h index 3f60eb0bbab342..2c039ab8a3f92c 100644 --- a/ReactCommon/react/renderer/components/textinput/androidtextinput/react/renderer/components/androidtextinput/AndroidTextInputState.h +++ b/ReactCommon/react/renderer/components/textinput/androidtextinput/react/renderer/components/androidtextinput/AndroidTextInputState.h @@ -19,15 +19,21 @@ namespace facebook { namespace react { /* - * State for component. - * Represents what to render and how to render. + * State for component. */ class AndroidTextInputState final { public: int64_t mostRecentEventCount{0}; + /** + * Stores an opaque cache ID used on the Java side to refer to a specific + * AttributedString for measurement purposes only. + */ + int cachedAttributedStringId{0}; + /* * All content of component represented as an `AttributedString`. + * Only set if changed from the React tree's perspective. */ AttributedString attributedString{}; @@ -76,49 +82,6 @@ class AndroidTextInputState final { float defaultThemePaddingTop{NAN}; float defaultThemePaddingBottom{NAN}; -#ifdef ANDROID - AttributedString updateAttributedString( - TextAttributes const &defaultTextAttributes, - ShadowView const &defaultParentShadowView, - AttributedString const &original, - folly::dynamic const &data) { - if (data["textChanged"].empty()) { - return original; - } - - // TODO: parse other attributes besides just string? - // on the other hand, not much should be driven from Java - // TODO: it'd be really nice to treat these as operational transforms - // instead of having to pass the whole string across. - // Unfortunately we don't have a good way of communicating from Java to C++ - // *which* version of the State changes should be applied to; and if there's - // a conflict, we don't have any recourse of any way to bail out of a - // commit. - - auto str = AttributedString{}; - - int i = 0; - folly::dynamic fragments = data["textChanged"]["fragments"]; - for (auto const &fragment : original.getFragments()) { - str.appendFragment(AttributedString::Fragment{ - fragments.size() > i ? fragments[i]["string"].getString() : "", - fragment.textAttributes, - fragment.parentShadowView}); - i++; - } - - if (fragments.size() > original.getFragments().size()) { - for (; i < fragments.size(); i++) { - str.appendFragment( - AttributedString::Fragment{fragments[i]["string"].getString(), - defaultTextAttributes, - defaultParentShadowView}); - } - } - - return str; - } - AndroidTextInputState( int64_t mostRecentEventCount, AttributedString const &attributedString, @@ -132,6 +95,7 @@ class AndroidTextInputState final { float defaultThemePaddingTop, float defaultThemePaddingBottom) : mostRecentEventCount(mostRecentEventCount), + cachedAttributedStringId(0), attributedString(attributedString), reactTreeAttributedString(reactTreeAttributedString), paragraphAttributes(paragraphAttributes), @@ -150,11 +114,10 @@ class AndroidTextInputState final { "mostRecentEventCount", previousState.mostRecentEventCount) .getInt()), - attributedString(updateAttributedString( - previousState.defaultTextAttributes, - previousState.defaultParentShadowView, - previousState.attributedString, - data)), + cachedAttributedStringId( + data.getDefault("cacheId", previousState.cachedAttributedStringId) + .getInt()), + attributedString(previousState.attributedString), reactTreeAttributedString(previousState.reactTreeAttributedString), paragraphAttributes(previousState.paragraphAttributes), defaultTextAttributes(previousState.defaultTextAttributes), @@ -178,7 +141,6 @@ class AndroidTextInputState final { previousState.defaultThemePaddingBottom) .getDouble()){}; folly::dynamic getDynamic() const; -#endif }; } // namespace react diff --git a/ReactCommon/react/renderer/textlayoutmanager/platform/android/react/renderer/textlayoutmanager/TextLayoutManager.cpp b/ReactCommon/react/renderer/textlayoutmanager/platform/android/react/renderer/textlayoutmanager/TextLayoutManager.cpp index 9d7bc047540f95..86b26366874f35 100644 --- a/ReactCommon/react/renderer/textlayoutmanager/platform/android/react/renderer/textlayoutmanager/TextLayoutManager.cpp +++ b/ReactCommon/react/renderer/textlayoutmanager/platform/android/react/renderer/textlayoutmanager/TextLayoutManager.cpp @@ -36,6 +36,64 @@ TextMeasurement TextLayoutManager::measure( }); } +TextMeasurement TextLayoutManager::measureCachedSpannableById( + int cacheId, + ParagraphAttributes paragraphAttributes, + LayoutConstraints layoutConstraints) const { + const jni::global_ref &fabricUIManager = + contextContainer_->at>("FabricUIManager"); + + auto env = Environment::current(); + auto attachmentPositions = env->NewFloatArray(0); + + static auto measure = + jni::findClassStatic("com/facebook/react/fabric/FabricUIManager") + ->getMethod("measure"); + + auto minimumSize = layoutConstraints.minimumSize; + auto maximumSize = layoutConstraints.maximumSize; + + local_ref componentName = make_jstring("RCTText"); + folly::dynamic cacheIdMap; + cacheIdMap["cacheId"] = cacheId; + local_ref attributedStringRNM = + ReadableNativeMap::newObjectCxxArgs(cacheIdMap); + local_ref paragraphAttributesRNM = + ReadableNativeMap::newObjectCxxArgs(toDynamic(paragraphAttributes)); + + local_ref attributedStringRM = make_local( + reinterpret_cast(attributedStringRNM.get())); + local_ref paragraphAttributesRM = make_local( + reinterpret_cast(paragraphAttributesRNM.get())); + auto size = yogaMeassureToSize(measure( + fabricUIManager, + -1, // TODO: we should pass rootTag in + componentName.get(), + attributedStringRM.get(), + paragraphAttributesRM.get(), + nullptr, + minimumSize.width, + maximumSize.width, + minimumSize.height, + maximumSize.height, + attachmentPositions)); + + // TODO: currently we do not support attachments for cached IDs - should we? + auto attachments = TextMeasurement::Attachments{}; + + return TextMeasurement{size, attachments}; +} + TextMeasurement TextLayoutManager::doMeasure( AttributedString attributedString, ParagraphAttributes paragraphAttributes, @@ -82,7 +140,7 @@ TextMeasurement TextLayoutManager::doMeasure( reinterpret_cast(paragraphAttributesRNM.get())); auto size = yogaMeassureToSize(measure( fabricUIManager, - -1, + -1, // TODO: we should pass rootTag in componentName.get(), attributedStringRM.get(), paragraphAttributesRM.get(), diff --git a/ReactCommon/react/renderer/textlayoutmanager/platform/android/react/renderer/textlayoutmanager/TextLayoutManager.h b/ReactCommon/react/renderer/textlayoutmanager/platform/android/react/renderer/textlayoutmanager/TextLayoutManager.h index 0136e7084baed7..926a9498f289b6 100644 --- a/ReactCommon/react/renderer/textlayoutmanager/platform/android/react/renderer/textlayoutmanager/TextLayoutManager.h +++ b/ReactCommon/react/renderer/textlayoutmanager/platform/android/react/renderer/textlayoutmanager/TextLayoutManager.h @@ -37,6 +37,15 @@ class TextLayoutManager { ParagraphAttributes paragraphAttributes, LayoutConstraints layoutConstraints) const; + /** + * Measures an AttributedString on the platform, as identified by some + * opaque cache ID. + */ + TextMeasurement measureCachedSpannableById( + int cacheId, + ParagraphAttributes paragraphAttributes, + LayoutConstraints layoutConstraints) const; + /* * Returns an opaque pointer to platform-specific TextLayoutManager. * Is used on a native views layer to delegate text rendering to the manager. From f4fa79a2e3dd63a4919b94eb3451f9c73b68748a Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Mon, 24 Aug 2020 12:39:27 -0700 Subject: [PATCH 0040/1238] Fabric: Fixed dangling pointer issue in UIManager::getRelativeLayoutMetrics Summary: The same as D21464834 (https://github.com/facebook/react-native/commit/604402678bb0c0c1dc8e55a07da86dee0a53da23). It should help with T71784916. Changelog: [Internal] Fabric-specific internal change. Reviewed By: JoshuaGross Differential Revision: D23297325 fbshipit-source-id: 6f14f9b1d1e7d251e53819207bac26dde5afe020 --- ReactCommon/react/renderer/uimanager/UIManager.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/ReactCommon/react/renderer/uimanager/UIManager.cpp b/ReactCommon/react/renderer/uimanager/UIManager.cpp index 91827e3fb94fd7..cb0cccb1676102 100644 --- a/ReactCommon/react/renderer/uimanager/UIManager.cpp +++ b/ReactCommon/react/renderer/uimanager/UIManager.cpp @@ -207,6 +207,7 @@ LayoutMetrics UIManager::getRelativeLayoutMetrics( shadowNode.getSurfaceId(), [&](ShadowTree const &shadowTree) { shadowTree.tryCommit( [&](RootShadowNode::Shared const &oldRootShadowNode) { + owningAncestorShadowNode = oldRootShadowNode; ancestorShadowNode = oldRootShadowNode.get(); return nullptr; }, From dd05ec38010d1a95284afcefaad9bce489e3b605 Mon Sep 17 00:00:00 2001 From: Joshua Gross Date: Mon, 24 Aug 2020 13:06:36 -0700 Subject: [PATCH 0041/1238] StubViewTree: add additional verbose logging, make slightly more resilient Summary: 1. When testing major changes to the differ, it can be useful to have more verbose logging. 2. On Android, since asserts don't fire yet, I log which asserts are failing. Should have no impact on any builds unless you manually set the macro here, and it will have no impact on production builds regardless. Changelog: [Internal] Reviewed By: shergin Differential Revision: D23257859 fbshipit-source-id: 94a8e74ece8023064de0f2203db6074975f8f1f0 --- .../renderer/debug/DebugStringConvertible.h | 3 + .../react/renderer/mounting/StubViewTree.cpp | 93 +++++++++++++++---- .../react/renderer/mounting/StubViewTree.h | 4 +- ReactCommon/react/renderer/mounting/stubs.cpp | 2 +- 4 files changed, 82 insertions(+), 20 deletions(-) diff --git a/ReactCommon/react/renderer/debug/DebugStringConvertible.h b/ReactCommon/react/renderer/debug/DebugStringConvertible.h index ccdfef0189acf5..de8ce9c6e5385f 100644 --- a/ReactCommon/react/renderer/debug/DebugStringConvertible.h +++ b/ReactCommon/react/renderer/debug/DebugStringConvertible.h @@ -29,6 +29,9 @@ namespace react { // To Debug introspection of RN Shadow tree, uncomment the following line: // #define RN_SHADOW_TREE_INTROSPECTION 1 +// To enable asserts (crashing) when checking stub trees +// #define RN_VALIDATE_SHADOW_TREE_STUB 1 + #if RN_DEBUG_STRING_CONVERTIBLE class DebugStringConvertible; diff --git a/ReactCommon/react/renderer/mounting/StubViewTree.cpp b/ReactCommon/react/renderer/mounting/StubViewTree.cpp index 1f50a374db8cf2..1fc9ba9c748f6a 100644 --- a/ReactCommon/react/renderer/mounting/StubViewTree.cpp +++ b/ReactCommon/react/renderer/mounting/StubViewTree.cpp @@ -7,6 +7,23 @@ #include "StubViewTree.h" +#include + +// Uncomment to enable verbose StubViewTree debug logs +// #define STUB_VIEW_TREE_VERBOSE 1 + +#define STUB_VIEW_ASSERT(cond) \ + if (!(cond)) { \ + LOG(ERROR) << "ASSERT FAILURE: " << #cond; \ + } \ + assert(cond); + +#ifdef STUB_VIEW_TREE_VERBOSE +#define STUB_VIEW_LOG(code) code +#else +#define STUB_VIEW_LOG(code) +#endif + namespace facebook { namespace react { @@ -21,35 +38,56 @@ StubView const &StubViewTree::getRootStubView() const { return *registry.at(rootTag); } -void StubViewTree::mutate(ShadowViewMutationList const &mutations) { +/** + * ignoreDuplicateCreates: when stubs generates "fake" mutation instructions, in + * some cases it can produce too many "create" instructions. We ignore + * duplicates and treat them as noops. In the case of verifying actual diffing, + * that assert is left on. + * + * @param mutations + * @param ignoreDuplicateCreates + */ +void StubViewTree::mutate( + ShadowViewMutationList const &mutations, + bool ignoreDuplicateCreates) { + STUB_VIEW_LOG({ LOG(ERROR) << "StubView: Mutating Begin"; }); for (auto const &mutation : mutations) { switch (mutation.type) { case ShadowViewMutation::Create: { - assert(mutation.parentShadowView == ShadowView{}); - assert(mutation.oldChildShadowView == ShadowView{}); + STUB_VIEW_ASSERT(mutation.parentShadowView == ShadowView{}); + STUB_VIEW_ASSERT(mutation.oldChildShadowView == ShadowView{}); auto stubView = std::make_shared(); auto tag = mutation.newChildShadowView.tag; - assert(registry.find(tag) == registry.end()); + STUB_VIEW_LOG({ LOG(ERROR) << "StubView: Create: " << tag; }); + if (!ignoreDuplicateCreates) { + STUB_VIEW_ASSERT(registry.find(tag) == registry.end()); + } registry[tag] = stubView; break; } case ShadowViewMutation::Delete: { - assert(mutation.parentShadowView == ShadowView{}); - assert(mutation.newChildShadowView == ShadowView{}); + STUB_VIEW_LOG( + { LOG(ERROR) << "Delete " << mutation.oldChildShadowView.tag; }); + STUB_VIEW_ASSERT(mutation.parentShadowView == ShadowView{}); + STUB_VIEW_ASSERT(mutation.newChildShadowView == ShadowView{}); auto tag = mutation.oldChildShadowView.tag; - assert(registry.find(tag) != registry.end()); + STUB_VIEW_ASSERT(registry.find(tag) != registry.end()); registry.erase(tag); break; } case ShadowViewMutation::Insert: { - assert(mutation.oldChildShadowView == ShadowView{}); + STUB_VIEW_ASSERT(mutation.oldChildShadowView == ShadowView{}); auto parentTag = mutation.parentShadowView.tag; - assert(registry.find(parentTag) != registry.end()); + STUB_VIEW_ASSERT(registry.find(parentTag) != registry.end()); auto parentStubView = registry[parentTag]; auto childTag = mutation.newChildShadowView.tag; - assert(registry.find(childTag) != registry.end()); + STUB_VIEW_LOG({ + LOG(ERROR) << "StubView: Insert: " << childTag << " into " + << parentTag << " at " << mutation.index; + }); + STUB_VIEW_ASSERT(registry.find(childTag) != registry.end()); auto childStubView = registry[childTag]; childStubView->update(mutation.newChildShadowView); parentStubView->children.insert( @@ -58,25 +96,43 @@ void StubViewTree::mutate(ShadowViewMutationList const &mutations) { } case ShadowViewMutation::Remove: { - assert(mutation.newChildShadowView == ShadowView{}); + STUB_VIEW_ASSERT(mutation.newChildShadowView == ShadowView{}); auto parentTag = mutation.parentShadowView.tag; - assert(registry.find(parentTag) != registry.end()); + STUB_VIEW_ASSERT(registry.find(parentTag) != registry.end()); auto parentStubView = registry[parentTag]; auto childTag = mutation.oldChildShadowView.tag; - assert(registry.find(childTag) != registry.end()); + STUB_VIEW_LOG({ + LOG(ERROR) << "StubView: Remove: " << childTag << " from " + << parentTag << " at index " << mutation.index << " with " + << parentStubView->children.size() << " children"; + }); + STUB_VIEW_ASSERT(registry.find(childTag) != registry.end()); auto childStubView = registry[childTag]; - assert( - parentStubView->children[mutation.index]->tag == - childStubView->tag); + bool childIsCorrect = + parentStubView->children.size() > mutation.index && + parentStubView->children[mutation.index]->tag == childStubView->tag; + STUB_VIEW_LOG({ + std::string strChildList = ""; + for (auto const &child : parentStubView->children) { + strChildList.append(std::to_string(child->tag)); + strChildList.append(", "); + } + LOG(ERROR) << "StubView: BEFORE REMOVE: Children of " << parentTag << ": " + << strChildList; + }); + STUB_VIEW_ASSERT(childIsCorrect); parentStubView->children.erase( parentStubView->children.begin() + mutation.index); break; } case ShadowViewMutation::Update: { - assert( + STUB_VIEW_LOG({ + LOG(ERROR) << "StubView: Update: " << mutation.newChildShadowView.tag; + }); + STUB_VIEW_ASSERT( mutation.newChildShadowView.tag == mutation.oldChildShadowView.tag); - assert( + STUB_VIEW_ASSERT( registry.find(mutation.newChildShadowView.tag) != registry.end()); auto stubView = registry[mutation.newChildShadowView.tag]; stubView->update(mutation.newChildShadowView); @@ -84,6 +140,7 @@ void StubViewTree::mutate(ShadowViewMutationList const &mutations) { } } } + STUB_VIEW_LOG({ LOG(ERROR) << "StubView: Mutating End"; }); } bool operator==(StubViewTree const &lhs, StubViewTree const &rhs) { diff --git a/ReactCommon/react/renderer/mounting/StubViewTree.h b/ReactCommon/react/renderer/mounting/StubViewTree.h index 6ffb00e63ce96a..3dceaba3dc7e97 100644 --- a/ReactCommon/react/renderer/mounting/StubViewTree.h +++ b/ReactCommon/react/renderer/mounting/StubViewTree.h @@ -21,7 +21,9 @@ class StubViewTree { StubViewTree() = default; StubViewTree(ShadowView const &shadowView); - void mutate(ShadowViewMutationList const &mutations); + void mutate( + ShadowViewMutationList const &mutations, + bool ignoreDuplicateCreates = false); StubView const &getRootStubView() const; diff --git a/ReactCommon/react/renderer/mounting/stubs.cpp b/ReactCommon/react/renderer/mounting/stubs.cpp index 370989a21a8d7a..47ce20e9e2c400 100644 --- a/ReactCommon/react/renderer/mounting/stubs.cpp +++ b/ReactCommon/react/renderer/mounting/stubs.cpp @@ -54,7 +54,7 @@ StubViewTree stubViewTreeFromShadowNode(ShadowNode const &rootShadowNode) { ShadowNode::emptySharedShadowNodeSharedList()}); auto stubViewTree = StubViewTree(ShadowView(*emptyRootShadowNode)); - stubViewTree.mutate(mutations); + stubViewTree.mutate(mutations, true); return stubViewTree; } From 92091b8b316eb37c9ed4ac56c97a6cf56786b499 Mon Sep 17 00:00:00 2001 From: Joshua Gross Date: Mon, 24 Aug 2020 13:06:36 -0700 Subject: [PATCH 0042/1238] New Flattening Differ Summary: # What is this? For a very long time, we've discussed the possibility of detecting Node Reparenting in the Fabric Differ. Practically, from the developer perspective, ReactJS and React Native do not allow reparenting: nodes cannot be reparented, only deleted and then recreated with entirely new tags. However, Fabric introduced the idea of View Flattening where views deemed unnecessary would be removed from the View hierarchy entirely. This is great and improves memory usage, except for one issue: if a View becomes unflattened, or becomes flattened, the entire tree underneath it must be rebuilt. In a past diff we introduced a mechanism to detect sibling reordering cleverly, and produce a minimal instruction set. This diff is very similar: we know the invariants around flattening and unflattening of views and we take advantage of them to produce an optimal set of instructions efficiently. # What's different from previous attempts? No global maps! Those are slow! This seems to work and (hopefully) might even improve performance, since way less work is being done on the UI thread in cases when views are (un)flattened. This *only* does extra work when flattening/unflattening happens, which gives product engineers a little more control over perf. # So, how's it work? This algorithm is intuitively simple (I think) but tricky to pull off, because there are lots of edge-cases. In short: In the past, that information was hidden from the Differ: the differ didn't know if views were being reparented, it would see them as entirely new views or as views being deleted if a View was flattened or unflattened. We very subtly change the information given to the differ: all nodes are visible to the differ, but marked as Flattened or Unflattened. Thus, when the differ compares two nodes in the "old" and "new" tree, it can tell not just if there are updates to the node but if it has been unflattened or flattened as well. For example, take this tree, where * indicates that a View is flattened: ``` A + +----+---+ B* X + + | | +---+--+ + E F Y ``` When the Differ asks for the children of A, in the past it would get a list `[E, F, X]`. That is, B* and X are both its children, but since B is flattened, it is omitted entirely from the list and its children are substituted. Now, when the Differ asks for the children of A, we give it this list instead: `[B*, E, F, X]`. That is: we give it a list which includes B, but B is marked as flattened. Another wrinkle: A node `X` could have its children flattened, but still be a concrete view: so flattening/unflattening is a different operation from making a view "concrete" or "unconcrete", which can change independently of flattening. There is one additional wrinkle: because of zIndex/stacking order, the children of `B` might not actually appear after `B` in the list. Depending on zIndex, a tree that looks like this: ``` A + +------+------+ B* C* + + | | +--+--+ +--+--+ D E F G ``` Could actually be linearized as: `[D G B* F C* E]` (as an extreme example; but basically all permutations as possible). This is the reason, and the *only* reason that the inner Flattener/Unflattener ## The cases we need to handle There are 7 cases/edge-cases of flattening and unflattening that we need to handle. Practically, all cases of reordering + flattening/unflattening, and taking recursive cases into account: 1. View A and A' (A in the old tree, A' in the new tree) are matched in the differ, and A* has been flattened or unflattened. These two cases are the easiest to handle. 2. View A' has been reordered with its siblings, and has been flattened or unflattened. These cases are slightly trickier to handle. 3. While flattening or unflattening, we encounter a child that has also been unflattened or flattened. So we need to handle four cases here in total: Flatten-Flatten, Flatten-Unflatten, Unflatten-Flatten, and Unflatten-Unflatten. Other things to think about, also covered above: 1. Ordering. Views can be reordered and flattened/unflattened at the same time. 2. zIndex ordering: children in a certain order from the ShadowNode perspective may be stacked differently from a View perspective. We use the zIndex ordering for everything in the differ, and this prevents us from performing certain optimizations (see above: we cannot assume that children come after their parent in a list; they may come before, may be interwoven with children from other parents, etc). # Perf Implications? Practically, there should be very little negative overhead. There is some overhead in actually performing a flattening/unflattening operation, but... not much more than before. We don't use global maps, so the cost of flattening/unflattening is basically `O(number of nodes reparented)` - note that that's direct nodes reparented, *not* descendants. tl;dr the perf hit should be similar to reordering, which is non-zero, but close to zero, and zero-cost for any diff operations on parts of the tree that don't involve flattening/unflattening. AFAICT this is very close to an ideal solution for that reason (but I wish it was simpler overall). # In Summary? I hope this works out and I think it could improve a number of things downstream: perf, LayoutAnimations, Bindings, certain crashes because of platform assumptions about mutations, etc. Is it worth it? This new implementation is substantially harder to reason about, harder to read, and harder to understand. This is an important consideration. All I can say there is that I trust the test suite I've been using, but the decreased readability is a big negative. Hopefully we can improve this in the future. The rest is fiddly implementation details that I sincerely hope can be improved and simplified in the future. # Followups? The part that makes this algorithm the most expensive is that because of zIndex ordering, we cannot assume that children are linearized after their parents and so we rely more heavily on maps for the flattening/unflattening. Our TinyMap implementation should make these `find` operations fast enough unless trees' children are constantly being reordered, but it's still worth thinking of ways to make this even faster. Changelog: [Internal] Reviewed By: shergin, mdvacca Differential Revision: D23259341 fbshipit-source-id: 35d9b90caf262d601a31996ea2cb37e329c61ffc --- .../com/facebook/react/fabric/jni/Binding.cpp | 7 +- .../renderer/mounting/Differentiator.cpp | 1284 ++++++++++++++++- .../react/renderer/mounting/Differentiator.h | 11 +- .../react/renderer/mounting/ShadowView.h | 9 + .../renderer/mounting/tests/MountingTest.cpp | 331 +++++ .../tests/ShadowTreeLifeCycleTest.cpp | 40 +- 6 files changed, 1652 insertions(+), 30 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp index 3d2d7c3b037354..37b995cf52fb14 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp @@ -262,8 +262,11 @@ void Binding::installFabricUIManager( // Keep reference to config object and cache some feature flags here reactNativeConfig_ = config; - collapseDeleteCreateMountingInstructions_ = reactNativeConfig_->getBool( - "react_fabric:enabled_collapse_delete_create_mounting_instructions"); + collapseDeleteCreateMountingInstructions_ = + reactNativeConfig_->getBool( + "react_fabric:enabled_collapse_delete_create_mounting_instructions") && + !reactNativeConfig_->getBool( + "react_fabric:enable_reparenting_detection_android"); disablePreallocateViews_ = reactNativeConfig_->getBool( "react_fabric:disabled_view_preallocation_android"); diff --git a/ReactCommon/react/renderer/mounting/Differentiator.cpp b/ReactCommon/react/renderer/mounting/Differentiator.cpp index 50c55d12d9308c..58c7dad749ba74 100644 --- a/ReactCommon/react/renderer/mounting/Differentiator.cpp +++ b/ReactCommon/react/renderer/mounting/Differentiator.cpp @@ -15,7 +15,8 @@ #include "ShadowView.h" // Uncomment this to enable verbose diffing logs, which can be useful for -// debugging. #define DEBUG_LOGS_DIFFER +// debugging. +// #define DEBUG_LOGS_DIFFER #ifdef DEBUG_LOGS_DIFFER #include @@ -192,7 +193,7 @@ static void reorderInPlaceIfNeeded(ShadowViewNodePair::List &pairs) noexcept { pairs.begin(), pairs.end(), &shouldFirstPairComesBeforeSecondOne); } -static void sliceChildShadowNodeViewPairsRecursively( +static void sliceChildShadowNodeViewPairsRecursivelyV2( ShadowViewNodePair::List &pairList, Point layoutOffset, ShadowNode const &shadowNode) { @@ -214,32 +215,46 @@ static void sliceChildShadowNodeViewPairsRecursively( shadowView.layoutMetrics.frame.origin += layoutOffset; } - if (childShadowNode.getTraits().check( + // This might not be a FormsView, or a FormsStackingContext. We let the + // differ handle removal of flattened views from the Mounting layer and + // shuffling their children around. + bool isConcreteView = + childShadowNode.getTraits().check(ShadowNodeTraits::Trait::FormsView); + bool areChildrenFlattened = !childShadowNode.getTraits().check( + ShadowNodeTraits::Trait::FormsStackingContext); + pairList.push_back( + {shadowView, &childShadowNode, areChildrenFlattened, isConcreteView}); + + if (!childShadowNode.getTraits().check( ShadowNodeTraits::Trait::FormsStackingContext)) { - pairList.push_back({shadowView, &childShadowNode}); - } else { - if (childShadowNode.getTraits().check( - ShadowNodeTraits::Trait::FormsView)) { - pairList.push_back({shadowView, &childShadowNode}); - } - - sliceChildShadowNodeViewPairsRecursively( + sliceChildShadowNodeViewPairsRecursivelyV2( pairList, origin, childShadowNode); } } } -ShadowViewNodePair::List sliceChildShadowNodeViewPairs( - ShadowNode const &shadowNode) { +ShadowViewNodePair::List sliceChildShadowNodeViewPairsV2( + ShadowNode const &shadowNode, + bool allowFlattened) { auto pairList = ShadowViewNodePair::List{}; if (!shadowNode.getTraits().check( ShadowNodeTraits::Trait::FormsStackingContext) && - shadowNode.getTraits().check(ShadowNodeTraits::Trait::FormsView)) { + shadowNode.getTraits().check(ShadowNodeTraits::Trait::FormsView) && + !allowFlattened) { return pairList; } - sliceChildShadowNodeViewPairsRecursively(pairList, {0, 0}, shadowNode); + sliceChildShadowNodeViewPairsRecursivelyV2(pairList, {0, 0}, shadowNode); + + // Sorting pairs based on `orderIndex` if needed. + reorderInPlaceIfNeeded(pairList); + + // Set list and mountIndex for each after reordering + int mountIndex = 0; + for (auto &child : pairList) { + child.mountIndex = (child.isConcreteView ? mountIndex++ : -1); + } return pairList; } @@ -274,6 +289,1219 @@ static_assert( std::is_move_assignable::value, "`ShadowViewNodePair::List` must be `move assignable`."); +// Forward declaration +static void calculateShadowViewMutationsV2( + ShadowViewMutation::List &mutations, + ShadowView const &parentShadowView, + ShadowViewNodePair::List &&oldChildPairs, + ShadowViewNodePair::List &&newChildPairs); + +struct OrderedMutationInstructionContainer { + ShadowViewMutation::List &createMutations; + ShadowViewMutation::List &deleteMutations; + ShadowViewMutation::List &insertMutations; + ShadowViewMutation::List &removeMutations; + ShadowViewMutation::List &updateMutations; + ShadowViewMutation::List &downwardMutations; + ShadowViewMutation::List &destructiveDownwardMutations; +}; + +static void calculateShadowViewMutationsFlattener( + ReparentMode reparentMode, + OrderedMutationInstructionContainer &mutationInstructionContainer, + ShadowView const &parentShadowView, + TinyMap &unvisitedFlattenedNodes, + ShadowViewNodePair const &node, + TinyMap *parentSubVisitedOtherNewNodes = nullptr, + TinyMap *parentSubVisitedOtherOldNodes = + nullptr); + +/** + * Here we flatten or unflatten a subtree, given an unflattened node in either + * the old or new tree, and a list of flattened nodes in the other tree. + * + * For example: if you are Flattening, the node will be in the old tree and the + * list will be from the new tree. If you are Unflattening, the opposite is + true. + + * It is currently not possible for ReactJS, and therefore React Native, to move + * a node *from* one parent to another without an entirely new subtree being + * created. When we "reparent" in React Native here it is only because + intermediate + * ShadowNodes/ShadowViews, which *always* exist, are flattened or unflattened + away. + * Thus, this algorithm handles the very specialized cases of the tree + collapsing or + * expanding vertically in that way. + + * Sketch of algorithm: + * 0. Create a map of nodes in the flattened list. This should be done *before* + * calling this function. + * 1. Traverse the Node Subtree; remove elements from the map as they are + * visited in the tree. + * Perform a Remove/Insert depending on if we're flattening or unflattening + * If Tree node is not in Map/List, perform Delete/Create. + * 2. Traverse the list. + * Perform linear remove from the old View, or insert into the new parent + * View if we're flattening. + * If a node is in the list but not the map, it means it's been visited and + * Update has already been + * performed in the subtree. If it *is* in the map, it means the node is not + * * in the Tree, and should be Deleted/Created + * **after this function is called**, by the caller. + */ +static void calculateShadowViewMutationsFlattener( + ReparentMode reparentMode, + OrderedMutationInstructionContainer &mutationInstructionContainer, + ShadowView const &parentShadowView, + TinyMap &unvisitedOtherNodes, + ShadowViewNodePair const &node, + TinyMap *parentSubVisitedOtherNewNodes, + TinyMap *parentSubVisitedOtherOldNodes) { + DEBUG_LOGS({ + LOG(ERROR) << "Differ Flattener 1: " + << (reparentMode == ReparentMode::Unflatten ? "Unflattening" + : "Flattening") + << " [" << node.shadowView.tag << "]"; + }); + + // Step 1: iterate through entire tree + ShadowViewNodePair::List treeChildren = + sliceChildShadowNodeViewPairsV2(*node.shadowNode); + + DEBUG_LOGS({ + LOG(ERROR) << "Differ Flattener 1.4: " + << (reparentMode == ReparentMode::Unflatten ? "Unflattening" + : "Flattening") + << " [" << node.shadowView.tag << "]"; + LOG(ERROR) << "Differ Flattener Entry: Child Pairs: "; + std::string strTreeChildPairs; + for (int k = 0; k < treeChildren.size(); k++) { + strTreeChildPairs.append(std::to_string(treeChildren[k].shadowView.tag)); + strTreeChildPairs.append(treeChildren[k].isConcreteView ? "" : "'"); + strTreeChildPairs.append(treeChildren[k].flattened ? "*" : ""); + strTreeChildPairs.append(", "); + } + std::string strListChildPairs; + for (auto &unvisitedNode : unvisitedOtherNodes) { + strListChildPairs.append( + std::to_string(unvisitedNode.second->shadowView.tag)); + strListChildPairs.append(unvisitedNode.second->isConcreteView ? "" : "'"); + strListChildPairs.append(unvisitedNode.second->flattened ? "*" : ""); + strListChildPairs.append(", "); + } + LOG(ERROR) << "Differ Flattener Entry: Tree Child Pairs: " + << strTreeChildPairs; + LOG(ERROR) << "Differ Flattener Entry: List Child Pairs: " + << strListChildPairs; + }); + + // Views in other tree that are visited by sub-flattening or sub-unflattening + TinyMap subVisitedOtherNewNodes{}; + TinyMap subVisitedOtherOldNodes{}; + auto subVisitedNewMap = + (parentSubVisitedOtherNewNodes != nullptr ? parentSubVisitedOtherNewNodes + : &subVisitedOtherNewNodes); + auto subVisitedOldMap = + (parentSubVisitedOtherOldNodes != nullptr ? parentSubVisitedOtherOldNodes + : &subVisitedOtherOldNodes); + + // Candidates for full tree creation or deletion at the end of this function + auto deletionCreationCandidatePairs = + TinyMap{}; + + for (int index = 0; + index < treeChildren.size() && index < treeChildren.size(); + index++) { + // First, remove all children of the tree being flattened, or insert + // children into parent tree if they're being unflattened. Then, look up + // each node in the "unvisited" list and update the nodes and subtrees if + // appropriate. + auto &treeChildPair = treeChildren[index]; + + // Caller will take care of the corresponding action in the other tree. + if (treeChildPair.isConcreteView) { + if (reparentMode == ReparentMode::Flatten) { + mutationInstructionContainer.removeMutations.push_back( + ShadowViewMutation::RemoveMutation( + node.shadowView, + treeChildPair.shadowView, + treeChildPair.mountIndex)); + } else { + mutationInstructionContainer.insertMutations.push_back( + ShadowViewMutation::InsertMutation( + node.shadowView, + treeChildPair.shadowView, + treeChildPair.mountIndex)); + } + } + + // Try to find node in other tree + auto unvisitedIt = unvisitedOtherNodes.find(treeChildPair.shadowView.tag); + auto subVisitedOtherNewIt = + (unvisitedIt == unvisitedOtherNodes.end() + ? subVisitedNewMap->find(treeChildPair.shadowView.tag) + : subVisitedNewMap->end()); + auto subVisitedOtherOldIt = + (unvisitedIt == unvisitedOtherNodes.end() + ? subVisitedOldMap->find(treeChildPair.shadowView.tag) + : subVisitedOldMap->end()); + + // Find in other tree + if (unvisitedIt != unvisitedOtherNodes.end() || + subVisitedOtherNewIt != subVisitedNewMap->end() || + subVisitedOtherOldIt != subVisitedOldMap->end()) { + // If we've already done updates on this node, don't repeat. + if (reparentMode == ReparentMode::Flatten && + unvisitedIt == unvisitedOtherNodes.end() && + subVisitedOtherOldIt != subVisitedOldMap->end()) { + continue; + } else if ( + reparentMode == ReparentMode::Unflatten && + unvisitedIt == unvisitedOtherNodes.end() && + subVisitedOtherNewIt != subVisitedNewMap->end()) { + continue; + } + + auto &otherTreeNodePair = + *(unvisitedIt != unvisitedOtherNodes.end() + ? unvisitedIt->second + : (subVisitedOtherNewIt != subVisitedNewMap->end() + ? subVisitedOtherNewIt->second + : subVisitedOtherOldIt->second)); + + // If we've already done updates, don't repeat it. + if (treeChildPair.inOtherTree || otherTreeNodePair.inOtherTree) { + continue; + } + + auto &newTreeNodePair = + (reparentMode == ReparentMode::Flatten ? otherTreeNodePair + : treeChildPair); + auto &oldTreeNodePair = + (reparentMode == ReparentMode::Flatten ? treeChildPair + : otherTreeNodePair); + + if (newTreeNodePair.shadowView != oldTreeNodePair.shadowView && + newTreeNodePair.isConcreteView && oldTreeNodePair.isConcreteView) { + mutationInstructionContainer.updateMutations.push_back( + ShadowViewMutation::UpdateMutation( + parentShadowView, + oldTreeNodePair.shadowView, + newTreeNodePair.shadowView, + newTreeNodePair.mountIndex)); + } + + // Update children if appropriate. + if (!oldTreeNodePair.flattened && !newTreeNodePair.flattened) { + if (oldTreeNodePair.shadowNode != newTreeNodePair.shadowNode) { + calculateShadowViewMutationsV2( + mutationInstructionContainer.downwardMutations, + newTreeNodePair.shadowView, + sliceChildShadowNodeViewPairsV2(*oldTreeNodePair.shadowNode), + sliceChildShadowNodeViewPairsV2(*newTreeNodePair.shadowNode)); + } + } else if (oldTreeNodePair.flattened != newTreeNodePair.flattened) { + // We need to handle one of the children being flattened or unflattened, + // in the context of a parent flattening or unflattening. + ReparentMode childReparentMode = + (oldTreeNodePair.flattened ? ReparentMode::Unflatten + : ReparentMode::Flatten); + + // Case 1: child mode is the same as parent. + // This is a flatten-flatten, or unflatten-unflatten. + if (childReparentMode == reparentMode) { + calculateShadowViewMutationsFlattener( + childReparentMode, + mutationInstructionContainer, + (reparentMode == ReparentMode::Flatten + ? parentShadowView + : newTreeNodePair.shadowView), + unvisitedOtherNodes, + treeChildPair, + subVisitedNewMap, + subVisitedOldMap); + } else { + // Unflatten parent, flatten child + if (childReparentMode == ReparentMode::Flatten) { + // Construct unvisited nodes map + auto unvisitedNewChildPairs = TinyMap{}; + // Memory note: these oldFlattenedNodes all disappear at the end of + // this "else" block, including any annotations we put on them. + auto newFlattenedNodes = sliceChildShadowNodeViewPairsV2( + *newTreeNodePair.shadowNode, true); + for (int i = 0; i < newFlattenedNodes.size(); i++) { + auto &newChild = newFlattenedNodes[i]; + + auto unvisitedOtherNodesIt = + unvisitedOtherNodes.find(newChild.shadowView.tag); + if (unvisitedOtherNodesIt != unvisitedOtherNodes.end()) { + auto &unvisitedItPair = *unvisitedOtherNodesIt->second; + unvisitedNewChildPairs.insert( + {unvisitedItPair.shadowView.tag, &unvisitedItPair}); + } else { + unvisitedNewChildPairs.insert( + {newChild.shadowView.tag, &newChild}); + } + } + + // Flatten old tree into new list + // At the end of this loop we still want to know which of these + // children are visited, so we reuse the `newRemainingPairs` map. + calculateShadowViewMutationsFlattener( + ReparentMode::Flatten, + mutationInstructionContainer, + (reparentMode == ReparentMode::Flatten + ? parentShadowView + : newTreeNodePair.shadowView), + unvisitedNewChildPairs, + oldTreeNodePair, + subVisitedNewMap, + subVisitedOldMap); + + for (auto &newFlattenedNode : newFlattenedNodes) { + auto unvisitedOldChildPairIt = + unvisitedNewChildPairs.find(newFlattenedNode.shadowView.tag); + + if (unvisitedOldChildPairIt == unvisitedNewChildPairs.end()) { + // Node was visited. + + auto deleteCreateIt = deletionCreationCandidatePairs.find( + newFlattenedNode.shadowView.tag); + if (deleteCreateIt != deletionCreationCandidatePairs.end()) { + deletionCreationCandidatePairs.erase(deleteCreateIt); + } + } + } + } + // Flatten parent, unflatten child + else { + // Construct unvisited nodes map + auto unvisitedOldChildPairs = TinyMap{}; + // Memory note: these oldFlattenedNodes all disappear at the end of + // this "else" block, including any annotations we put on them. + auto oldFlattenedNodes = sliceChildShadowNodeViewPairsV2( + *oldTreeNodePair.shadowNode, true); + for (int i = 0; i < oldFlattenedNodes.size(); i++) { + auto &oldChild = oldFlattenedNodes[i]; + + auto unvisitedOtherNodesIt = + unvisitedOtherNodes.find(oldChild.shadowView.tag); + if (unvisitedOtherNodesIt != unvisitedOtherNodes.end()) { + auto &unvisitedItPair = *unvisitedOtherNodesIt->second; + unvisitedOldChildPairs.insert( + {unvisitedItPair.shadowView.tag, &unvisitedItPair}); + } else { + unvisitedOldChildPairs.insert( + {oldChild.shadowView.tag, &oldChild}); + } + } + + // Unflatten old list into new tree + calculateShadowViewMutationsFlattener( + ReparentMode::Unflatten, + mutationInstructionContainer, + (reparentMode == ReparentMode::Flatten + ? parentShadowView + : newTreeNodePair.shadowView), + unvisitedOldChildPairs, + newTreeNodePair, + subVisitedNewMap, + subVisitedOldMap); + + // If old nodes were not visited, we know that we can delete them + // now. They will be removed from the hierarchy by the outermost + // loop of this function. + for (auto &oldFlattenedNode : oldFlattenedNodes) { + auto unvisitedOldChildPairIt = + unvisitedOldChildPairs.find(oldFlattenedNode.shadowView.tag); + if (unvisitedOldChildPairIt != unvisitedOldChildPairs.end()) { + // Node unvisited - mark the entire subtree for deletion + if (oldFlattenedNode.isConcreteView) { + auto tag = oldFlattenedNode.shadowView.tag; + auto oldRemainingChildInListIt = std::find_if( + treeChildren.begin(), + treeChildren.end(), + [&tag](ShadowViewNodePair &nodePair) { + return nodePair.shadowView.tag == tag; + }); + if (oldRemainingChildInListIt != treeChildren.end()) { + auto deleteCreateIt = deletionCreationCandidatePairs.find( + oldFlattenedNode.shadowView.tag); + if (deleteCreateIt == + deletionCreationCandidatePairs.end()) { + deletionCreationCandidatePairs.insert( + {tag, &*oldRemainingChildInListIt}); + } + } else { + // TODO: we might want to remove this block. It seems + // impossible to hit this logically (and empirically, after + // testing on lots of randomized and pathologically + // constructed trees) but I'm leaving this here out of an + // abundance of caution. + mutationInstructionContainer.deleteMutations.push_back( + ShadowViewMutation::DeleteMutation( + oldFlattenedNode.shadowView)); + + calculateShadowViewMutationsV2( + mutationInstructionContainer + .destructiveDownwardMutations, + oldFlattenedNode.shadowView, + sliceChildShadowNodeViewPairsV2( + *oldFlattenedNode.shadowNode), + {}); + } + } + } else { + // Node was visited - make sure to remove it from + // "newRemainingPairs" map + auto newRemainingIt = + unvisitedOtherNodes.find(oldFlattenedNode.shadowView.tag); + if (newRemainingIt != unvisitedOtherNodes.end()) { + unvisitedOtherNodes.erase(newRemainingIt); + } + + // We also remove it from delete/creation candidates + auto deleteCreateIt = deletionCreationCandidatePairs.find( + oldFlattenedNode.shadowView.tag); + if (deleteCreateIt != deletionCreationCandidatePairs.end()) { + deletionCreationCandidatePairs.erase(deleteCreateIt); + } + } + } + } + } + } + + // Mark that node exists in another tree, but only if the tree node is a + // concrete view. Removing the node from the unvisited list prevents the + // caller from taking further action on this node, so make sure to + // delete/create if the Concreteness of the node has changed. + if (newTreeNodePair.isConcreteView != oldTreeNodePair.isConcreteView && + !newTreeNodePair.inOtherTree) { + if (newTreeNodePair.isConcreteView) { + mutationInstructionContainer.createMutations.push_back( + ShadowViewMutation::CreateMutation(newTreeNodePair.shadowView)); + } else { + mutationInstructionContainer.deleteMutations.push_back( + ShadowViewMutation::DeleteMutation(newTreeNodePair.shadowView)); + } + } + + treeChildPair.inOtherTree = true; + otherTreeNodePair.inOtherTree = true; + + if (parentSubVisitedOtherNewNodes != nullptr) { + parentSubVisitedOtherNewNodes->insert( + {newTreeNodePair.shadowView.tag, &newTreeNodePair}); + } + if (parentSubVisitedOtherOldNodes != nullptr) { + parentSubVisitedOtherOldNodes->insert( + {oldTreeNodePair.shadowView.tag, &oldTreeNodePair}); + } + + if (unvisitedIt != unvisitedOtherNodes.end()) { + unvisitedOtherNodes.erase(unvisitedIt); + } + } else { + // Node does not in exist in other tree. + if (treeChildPair.isConcreteView && !treeChildPair.inOtherTree) { + auto deletionCreationIt = + deletionCreationCandidatePairs.find(treeChildPair.shadowView.tag); + if (deletionCreationIt == deletionCreationCandidatePairs.end()) { + deletionCreationCandidatePairs.insert( + {treeChildPair.shadowView.tag, &treeChildPair}); + } + } + } + } + + // Final step: go through creation/deletion candidates and delete/create + // subtrees if they were never visited during the execution of the above loop + // and recursions. + for (auto it = deletionCreationCandidatePairs.begin(); + it != deletionCreationCandidatePairs.end(); + it++) { + if (it->first == 0) { + continue; + } + auto &treeChildPair = *it->second; + + // If node was visited during a flattening/unflattening recursion. + if (treeChildPair.inOtherTree) { + continue; + } + + if (reparentMode == ReparentMode::Flatten) { + mutationInstructionContainer.deleteMutations.push_back( + ShadowViewMutation::DeleteMutation(treeChildPair.shadowView)); + + if (!treeChildPair.flattened) { + calculateShadowViewMutationsV2( + mutationInstructionContainer.destructiveDownwardMutations, + treeChildPair.shadowView, + sliceChildShadowNodeViewPairsV2(*treeChildPair.shadowNode), + {}); + } + } else { + mutationInstructionContainer.createMutations.push_back( + ShadowViewMutation::CreateMutation(treeChildPair.shadowView)); + + if (!treeChildPair.flattened) { + calculateShadowViewMutationsV2( + mutationInstructionContainer.downwardMutations, + treeChildPair.shadowView, + {}, + sliceChildShadowNodeViewPairsV2(*treeChildPair.shadowNode)); + } + } + } +} + +static void calculateShadowViewMutationsV2( + ShadowViewMutation::List &mutations, + ShadowView const &parentShadowView, + ShadowViewNodePair::List &&oldChildPairs, + ShadowViewNodePair::List &&newChildPairs) { + if (oldChildPairs.empty() && newChildPairs.empty()) { + return; + } + + auto index = int{0}; + + // Lists of mutations + auto createMutations = ShadowViewMutation::List{}; + auto deleteMutations = ShadowViewMutation::List{}; + auto insertMutations = ShadowViewMutation::List{}; + auto removeMutations = ShadowViewMutation::List{}; + auto updateMutations = ShadowViewMutation::List{}; + auto downwardMutations = ShadowViewMutation::List{}; + auto destructiveDownwardMutations = ShadowViewMutation::List{}; + auto mutationInstructionContainer = + OrderedMutationInstructionContainer{createMutations, + deleteMutations, + insertMutations, + removeMutations, + updateMutations, + downwardMutations, + destructiveDownwardMutations}; + + DEBUG_LOGS({ + LOG(ERROR) << "Differ Entry: Child Pairs of node: [" << parentShadowView.tag + << "]"; + std::string strOldChildPairs; + for (int oldIndex = 0; oldIndex < oldChildPairs.size(); oldIndex++) { + strOldChildPairs.append( + std::to_string(oldChildPairs[oldIndex].shadowView.tag)); + strOldChildPairs.append( + oldChildPairs[oldIndex].isConcreteView ? "" : "'"); + strOldChildPairs.append(oldChildPairs[oldIndex].flattened ? "*" : ""); + strOldChildPairs.append(", "); + } + std::string strNewChildPairs; + for (int newIndex = 0; newIndex < newChildPairs.size(); newIndex++) { + strNewChildPairs.append( + std::to_string(newChildPairs[newIndex].shadowView.tag)); + strNewChildPairs.append( + newChildPairs[newIndex].isConcreteView ? "" : "'"); + strNewChildPairs.append(newChildPairs[newIndex].flattened ? "*" : ""); + strNewChildPairs.append(", "); + } + LOG(ERROR) << "Differ Entry: Old Child Pairs: " << strOldChildPairs; + LOG(ERROR) << "Differ Entry: New Child Pairs: " << strNewChildPairs; + }); + + // Stage 1: Collecting `Update` mutations + for (index = 0; index < oldChildPairs.size() && index < newChildPairs.size(); + index++) { + auto &oldChildPair = oldChildPairs[index]; + auto &newChildPair = newChildPairs[index]; + + if (oldChildPair.shadowView.tag != newChildPair.shadowView.tag) { + DEBUG_LOGS({ + LOG(ERROR) << "Differ Branch 1.1: Tags Different: [" + << oldChildPair.shadowView.tag << "] [" + << newChildPair.shadowView.tag << "]" + << " with parent: [" << parentShadowView.tag << "]"; + }); + + // Totally different nodes, updating is impossible. + break; + } + + // If either view was flattened, and that has changed this frame, don't try + // to update + if (oldChildPair.flattened != newChildPair.flattened || + oldChildPair.isConcreteView != newChildPair.isConcreteView) { + break; + } + + DEBUG_LOGS({ + LOG(ERROR) << "Differ Branch 1.2: Same tags, update and recurse: [" + << oldChildPair.shadowView.tag << "]" + << (oldChildPair.flattened ? " (flattened)" : "") + << (oldChildPair.isConcreteView ? " (concrete)" : "") << "[" + << newChildPair.shadowView.tag << "]" + << (newChildPair.flattened ? " (flattened)" : "") + << (newChildPair.isConcreteView ? " (concrete)" : "") + << " with parent: [" << parentShadowView.tag << "]"; + }); + + if (newChildPair.isConcreteView && + oldChildPair.shadowView != newChildPair.shadowView) { + updateMutations.push_back(ShadowViewMutation::UpdateMutation( + parentShadowView, + oldChildPair.shadowView, + newChildPair.shadowView, + newChildPair.mountIndex)); + } + + // Recursively update tree if ShadowNode pointers are not equal + if (!oldChildPair.flattened && + oldChildPair.shadowNode != newChildPair.shadowNode) { + auto oldGrandChildPairs = + sliceChildShadowNodeViewPairsV2(*oldChildPair.shadowNode); + auto newGrandChildPairs = + sliceChildShadowNodeViewPairsV2(*newChildPair.shadowNode); + calculateShadowViewMutationsV2( + *(newGrandChildPairs.size() ? &downwardMutations + : &destructiveDownwardMutations), + oldChildPair.shadowView, + std::move(oldGrandChildPairs), + std::move(newGrandChildPairs)); + } + } + + int lastIndexAfterFirstStage = index; + + if (index == newChildPairs.size()) { + // We've reached the end of the new children. We can delete+remove the + // rest. + for (; index < oldChildPairs.size(); index++) { + auto const &oldChildPair = oldChildPairs[index]; + + DEBUG_LOGS({ + LOG(ERROR) << "Differ Branch 2: Deleting Tag/Tree: [" + << oldChildPair.shadowView.tag << "]" + << " with parent: [" << parentShadowView.tag << "]"; + }); + + if (!oldChildPair.isConcreteView) { + continue; + } + + deleteMutations.push_back( + ShadowViewMutation::DeleteMutation(oldChildPair.shadowView)); + removeMutations.push_back(ShadowViewMutation::RemoveMutation( + parentShadowView, oldChildPair.shadowView, oldChildPair.mountIndex)); + + // We also have to call the algorithm recursively to clean up the entire + // subtree starting from the removed view. + calculateShadowViewMutationsV2( + destructiveDownwardMutations, + oldChildPair.shadowView, + sliceChildShadowNodeViewPairsV2(*oldChildPair.shadowNode), + {}); + } + } else if (index == oldChildPairs.size()) { + // If we don't have any more existing children we can choose a fast path + // since the rest will all be create+insert. + for (; index < newChildPairs.size(); index++) { + auto const &newChildPair = newChildPairs[index]; + + DEBUG_LOGS({ + LOG(ERROR) << "Differ Branch 3: Creating Tag/Tree: [" + << newChildPair.shadowView.tag << "]" + << " with parent: [" << parentShadowView.tag << "]"; + }); + + if (!newChildPair.isConcreteView) { + continue; + } + + insertMutations.push_back(ShadowViewMutation::InsertMutation( + parentShadowView, newChildPair.shadowView, newChildPair.mountIndex)); + createMutations.push_back( + ShadowViewMutation::CreateMutation(newChildPair.shadowView)); + + calculateShadowViewMutationsV2( + downwardMutations, + newChildPair.shadowView, + {}, + sliceChildShadowNodeViewPairsV2(*newChildPair.shadowNode)); + } + } else { + // Collect map of tags in the new list + auto newRemainingPairs = TinyMap{}; + auto newInsertedPairs = TinyMap{}; + auto deletionCandidatePairs = TinyMap{}; + for (; index < newChildPairs.size(); index++) { + auto &newChildPair = newChildPairs[index]; + newRemainingPairs.insert({newChildPair.shadowView.tag, &newChildPair}); + } + + // Walk through both lists at the same time + // We will perform updates, create+insert, remove+delete, remove+insert + // (move) here. + int oldIndex = lastIndexAfterFirstStage, + newIndex = lastIndexAfterFirstStage, newSize = newChildPairs.size(), + oldSize = oldChildPairs.size(); + while (newIndex < newSize || oldIndex < oldSize) { + bool haveNewPair = newIndex < newSize; + bool haveOldPair = oldIndex < oldSize; + + // Advance both pointers if pointing to the same element + if (haveNewPair && haveOldPair) { + auto const &oldChildPair = oldChildPairs[oldIndex]; + auto const &newChildPair = newChildPairs[newIndex]; + + int newTag = newChildPair.shadowView.tag; + int oldTag = oldChildPair.shadowView.tag; + + if (newTag == oldTag) { + DEBUG_LOGS({ + LOG(ERROR) << "Differ Branch 5: Matched Tags at indices: " + << oldIndex << " " << newIndex << ": [" + << oldChildPair.shadowView.tag << "]" + << (oldChildPair.flattened ? "(flattened)" : "") + << (oldChildPair.isConcreteView ? "(concrete)" : "") + << " [" << newChildPair.shadowView.tag << "]" + << (newChildPair.flattened ? "(flattened)" : "") + << (newChildPair.isConcreteView ? "(concrete)" : "") + << " with parent: [" << parentShadowView.tag << "]"; + }); + + // Check concrete-ness of views + // Create/Delete and Insert/Remove if necessary + if (oldChildPair.isConcreteView != newChildPair.isConcreteView) { + if (newChildPair.isConcreteView) { + insertMutations.push_back(ShadowViewMutation::InsertMutation( + parentShadowView, + newChildPair.shadowView, + newChildPair.mountIndex)); + createMutations.push_back( + ShadowViewMutation::CreateMutation(newChildPair.shadowView)); + } else { + removeMutations.push_back(ShadowViewMutation::RemoveMutation( + parentShadowView, + oldChildPair.shadowView, + oldChildPair.mountIndex)); + deleteMutations.push_back( + ShadowViewMutation::DeleteMutation(oldChildPair.shadowView)); + } + } else if ( + oldChildPair.isConcreteView && newChildPair.isConcreteView) { + // Even if node's children are flattened, it might still be a + // concrete view. The case where they're different is handled above. + if (oldChildPair.shadowView != newChildPair.shadowView) { + updateMutations.push_back(ShadowViewMutation::UpdateMutation( + parentShadowView, + oldChildPair.shadowView, + newChildPair.shadowView, + newChildPair.mountIndex)); + } + + // Remove from newRemainingPairs + auto newRemainingPairIt = newRemainingPairs.find(oldTag); + if (newRemainingPairIt != newRemainingPairs.end()) { + newRemainingPairs.erase(newRemainingPairIt); + } + } + + // Are we flattening or unflattening either one? If node was flattened + // in both trees, there's no change, just continue. + if (oldChildPair.flattened && newChildPair.flattened) { + newIndex++; + oldIndex++; + continue; + } + // We are either flattening or unflattening this node. + if (oldChildPair.flattened != newChildPair.flattened) { + DEBUG_LOGS({ + LOG(ERROR) << "Differ: flattening or unflattening at branch 6: [" + << oldChildPair.shadowView.tag << "] [" + << newChildPair.shadowView.tag << "] " + << oldChildPair.flattened << " " + << newChildPair.flattened << " with parent: [" + << parentShadowView.tag << "]"; + }); + + // Flattening + if (!oldChildPair.flattened) { + // Flatten old tree into new list + // At the end of this loop we still want to know which of these + // children are visited, so we reuse the `newRemainingPairs` map. + calculateShadowViewMutationsFlattener( + ReparentMode::Flatten, + mutationInstructionContainer, + parentShadowView, + newRemainingPairs, + oldChildPair); + } + // Unflattening + else { + // Construct unvisited nodes map + auto unvisitedOldChildPairs = + TinyMap{}; + // We don't know where all the children of oldChildPair are within + // oldChildPairs, but we know that they're in the same relative + // order. The reason for this is because of flattening + zIndex: + // the children could be listed before the parent, interwoven with + // children from other nodes, etc. + auto oldFlattenedNodes = sliceChildShadowNodeViewPairsV2( + *oldChildPair.shadowNode, true); + for (int i = 0, j = 0; + i < oldChildPairs.size() && j < oldFlattenedNodes.size(); + i++) { + auto &oldChild = oldChildPairs[i]; + if (oldChild.shadowView.tag == + oldFlattenedNodes[j].shadowView.tag) { + unvisitedOldChildPairs.insert( + {oldChild.shadowView.tag, &oldChild}); + j++; + } + } + + // Unflatten old list into new tree + calculateShadowViewMutationsFlattener( + ReparentMode::Unflatten, + mutationInstructionContainer, + parentShadowView, + unvisitedOldChildPairs, + newChildPair); + + // If old nodes were not visited, we know that we can delete them + // now. They will be removed from the hierarchy by the outermost + // loop of this function. + for (auto &oldFlattenedNode : oldFlattenedNodes) { + auto unvisitedOldChildPairIt = unvisitedOldChildPairs.find( + oldFlattenedNode.shadowView.tag); + if (unvisitedOldChildPairIt != unvisitedOldChildPairs.end()) { + // Node unvisited - delete it entirely + deleteMutations.push_back(ShadowViewMutation::DeleteMutation( + oldFlattenedNode.shadowView)); + } else { + // Node was visited - make sure to remove it from + // "newRemainingPairs" map + auto newRemainingIt = + newRemainingPairs.find(oldFlattenedNode.shadowView.tag); + if (newRemainingIt != newRemainingPairs.end()) { + newRemainingPairs.erase(newRemainingIt); + } + } + } + } + + newIndex++; + oldIndex++; + continue; + } + + // Update subtrees if View is not flattened, and if node addresses are + // not equal + if (oldChildPair.shadowNode != newChildPair.shadowNode) { + auto oldGrandChildPairs = + sliceChildShadowNodeViewPairsV2(*oldChildPair.shadowNode); + auto newGrandChildPairs = + sliceChildShadowNodeViewPairsV2(*newChildPair.shadowNode); + calculateShadowViewMutationsV2( + *(newGrandChildPairs.size() ? &downwardMutations + : &destructiveDownwardMutations), + oldChildPair.shadowView, + std::move(oldGrandChildPairs), + std::move(newGrandChildPairs)); + } + + newIndex++; + oldIndex++; + continue; + } + } + + // We have an old pair, but we either don't have any remaining new pairs + // or we have one but it's not matched up with the old pair + if (haveOldPair) { + auto const &oldChildPair = oldChildPairs[oldIndex]; + + int oldTag = oldChildPair.shadowView.tag; + + // Was oldTag already inserted? This indicates a reordering, not just + // a move. The new node has already been inserted, we just need to + // remove the node from its old position now, and update the node's + // subtree. + auto const insertedIt = newInsertedPairs.find(oldTag); + if (insertedIt != newInsertedPairs.end()) { + auto const &newChildPair = *insertedIt->second; + + // The node has been reordered and we are also flattening or + // unflattening + if (oldChildPair.flattened != newChildPair.flattened) { + DEBUG_LOGS({ + LOG(ERROR) + << "Differ: branch 7: Flattening or unflattening already-inserted node upon remove (move/reorder operation)." + << oldChildPair.shadowView.tag << " " + << oldChildPair.flattened << " // " + << newChildPair.shadowView.tag << " " + << newChildPair.flattened; + }); + + // Unflattening. + // The node in question was already inserted and we are + // *unflattening* it, so we just need to update the subtree nodes + // and remove them from the view hierarchy. Any of the unvisited + // nodes in the old tree will be deleted. + // TODO: can we consolidate this code? It's identical to the first + // block above. + if (!oldChildPair.flattened) { + // Flatten old tree into new list + // At the end of this loop we still want to know which of these + // children are visited, so we reuse the `newRemainingPairs` map. + calculateShadowViewMutationsFlattener( + ReparentMode::Flatten, + mutationInstructionContainer, + parentShadowView, + newRemainingPairs, + oldChildPair); + } + // Unflattening + else { + // Construct unvisited nodes map + auto unvisitedOldChildPairs = + TinyMap{}; + // We don't know where all the children of oldChildPair are within + // oldChildPairs, but we know that they're in the same relative + // order. The reason for this is because of flattening + zIndex: + // the children could be listed before the parent, interwoven with + // children from other nodes, etc. + auto oldFlattenedNodes = sliceChildShadowNodeViewPairsV2( + *oldChildPair.shadowNode, true); + for (int i = 0, j = 0; + i < oldChildPairs.size() && j < oldFlattenedNodes.size(); + i++) { + auto &oldChild = oldChildPairs[i]; + if (oldChild.shadowView.tag == + oldFlattenedNodes[j].shadowView.tag) { + unvisitedOldChildPairs.insert( + {oldChild.shadowView.tag, &oldChild}); + j++; + } + } + + // Unflatten old list into new tree + calculateShadowViewMutationsFlattener( + ReparentMode::Unflatten, + mutationInstructionContainer, + parentShadowView, + unvisitedOldChildPairs, + newChildPair); + + // If old nodes were not visited, we know that we can delete them + // now. They will be removed from the hierarchy by the outermost + // loop of this function. TODO: delete recursively? create + // recursively? + for (auto &oldFlattenedNode : oldFlattenedNodes) { + auto unvisitedOldChildPairIt = unvisitedOldChildPairs.find( + oldFlattenedNode.shadowView.tag); + if (unvisitedOldChildPairIt != unvisitedOldChildPairs.end()) { + // Node unvisited - delete it entirely + deleteMutations.push_back(ShadowViewMutation::DeleteMutation( + oldFlattenedNode.shadowView)); + } else { + // Node was visited - make sure to remove it from + // "newRemainingPairs" map + auto newRemainingIt = + newRemainingPairs.find(oldFlattenedNode.shadowView.tag); + if (newRemainingIt != newRemainingPairs.end()) { + newRemainingPairs.erase(newRemainingIt); + } + } + } + } + } + + // Check concrete-ness of views + // Create/Delete and Insert/Remove if necessary + // TODO: document: Insert should already be handled by outermost loop, + // but not Remove + if (oldChildPair.isConcreteView != newChildPair.isConcreteView) { + if (newChildPair.isConcreteView) { + createMutations.push_back( + ShadowViewMutation::CreateMutation(newChildPair.shadowView)); + } else { + removeMutations.push_back(ShadowViewMutation::RemoveMutation( + parentShadowView, + oldChildPair.shadowView, + oldChildPair.mountIndex)); + deleteMutations.push_back( + ShadowViewMutation::DeleteMutation(oldChildPair.shadowView)); + } + } + + // We handled this case above. We fall through to check concreteness + // of old/new view to remove/insert create/delete above, and then bail + // out here. + if (oldChildPair.flattened != newChildPair.flattened) { + newInsertedPairs.erase(insertedIt); + oldIndex++; + continue; + } + + // old and new child pairs are both either flattened or unflattened at + // this point. If they're not views, we don't need to update subtrees. + if (oldChildPair.isConcreteView) { + // TODO: do we always want to remove here? There are cases where we + // might be able to remove this to prevent unnecessary + // removes/inserts in cases of (un)flattening + reorders? + removeMutations.push_back(ShadowViewMutation::RemoveMutation( + parentShadowView, + oldChildPair.shadowView, + oldChildPair.mountIndex)); + + if (oldChildPair.shadowView != newChildPair.shadowView) { + updateMutations.push_back(ShadowViewMutation::UpdateMutation( + parentShadowView, + oldChildPair.shadowView, + newChildPair.shadowView, + newChildPair.mountIndex)); + } + } + if (!oldChildPair.flattened && + oldChildPair.shadowNode != newChildPair.shadowNode) { + // Update subtrees + auto oldGrandChildPairs = + sliceChildShadowNodeViewPairsV2(*oldChildPair.shadowNode); + auto newGrandChildPairs = + sliceChildShadowNodeViewPairsV2(*newChildPair.shadowNode); + calculateShadowViewMutationsV2( + *(newGrandChildPairs.size() ? &downwardMutations + : &destructiveDownwardMutations), + oldChildPair.shadowView, + std::move(oldGrandChildPairs), + std::move(newGrandChildPairs)); + } + + newInsertedPairs.erase(insertedIt); + oldIndex++; + continue; + } + + // Should we generate a delete+remove instruction for the old node? + // If there's an old node and it's not found in the "new" list, we + // generate remove+delete for this node and its subtree. + auto const newIt = newRemainingPairs.find(oldTag); + if (newIt == newRemainingPairs.end()) { + DEBUG_LOGS({ + LOG(ERROR) + << "Differ Branch 9: Removing tag that was not reinserted: " + << oldIndex << ": [" << oldChildPair.shadowView.tag << "]" + << (oldChildPair.flattened ? " (flattened)" : "") + << (oldChildPair.isConcreteView ? " (concrete)" : "") + << " with parent: [" << parentShadowView.tag << "]"; + }); + + if (oldChildPair.isConcreteView) { + removeMutations.push_back(ShadowViewMutation::RemoveMutation( + parentShadowView, + oldChildPair.shadowView, + oldChildPair.mountIndex)); + + deletionCandidatePairs.insert( + {oldChildPair.shadowView.tag, &oldChildPair}); + } + + oldIndex++; + continue; + } + } + + // At this point, oldTag is -1 or is in the new list, and hasn't been + // inserted or matched yet. We're not sure yet if the new node is in the + // old list - generate an insert instruction for the new node. + auto &newChildPair = newChildPairs[newIndex]; + DEBUG_LOGS({ + LOG(ERROR) + << "Differ Branch 10: Inserting tag/tree that was not (yet?) removed from hierarchy: " + << newIndex << "/" << newSize << ": [" + << newChildPair.shadowView.tag << "]" + << (newChildPair.flattened ? " (flattened)" : "") + << (newChildPair.isConcreteView ? " (concrete)" : "") + << " with parent: [" << parentShadowView.tag << "]"; + }); + if (newChildPair.isConcreteView) { + insertMutations.push_back(ShadowViewMutation::InsertMutation( + parentShadowView, + newChildPair.shadowView, + newChildPair.mountIndex)); + } + if (!newChildPair.inOtherTree) { + newInsertedPairs.insert({newChildPair.shadowView.tag, &newChildPair}); + } + newIndex++; + } + + // Penultimate step: generate Delete instructions for entirely deleted + // subtrees/nodes. We do this here because we need to traverse the entire + // list to make sure that a node was not reparented into an unflattened node + // that occurs *after* it in the hierarchy, due to zIndex ordering. + for (auto it = deletionCandidatePairs.begin(); + it != deletionCandidatePairs.end(); + it++) { + if (it->first == 0) { + continue; + } + + auto const &oldChildPair = *it->second; + + DEBUG_LOGS({ + LOG(ERROR) + << "Differ Branch 11: Deleting tag/tree that was not in new hierarchy: " + << "[" << oldChildPair.shadowView.tag << "]" + << (oldChildPair.flattened ? "(flattened)" : "") + << (oldChildPair.isConcreteView ? "(concrete)" : "") + << (oldChildPair.inOtherTree ? "(in other tree)" : "") + << " with parent: [" << parentShadowView.tag << "]"; + }); + + // This can happen when the parent is unflattened + if (!oldChildPair.inOtherTree) { + deleteMutations.push_back( + ShadowViewMutation::DeleteMutation(oldChildPair.shadowView)); + + // We also have to call the algorithm recursively to clean up the + // entire subtree starting from the removed view. + calculateShadowViewMutationsV2( + destructiveDownwardMutations, + oldChildPair.shadowView, + sliceChildShadowNodeViewPairsV2(*oldChildPair.shadowNode), + {}); + } + } + + // Final step: generate Create instructions for entirely new subtrees/nodes + // that are not the result of flattening or unflattening. + for (auto it = newInsertedPairs.begin(); it != newInsertedPairs.end(); + it++) { + // Erased elements of a TinyMap will have a Tag/key of 0 - skip those + // These *should* be removed by the map; there are currently no KNOWN + // cases where TinyMap will do the wrong thing, but there are not yet + // any unit tests explicitly for TinyMap, so this is safer for now. + if (it->first == 0) { + continue; + } + + auto const &newChildPair = *it->second; + + DEBUG_LOGS({ + LOG(ERROR) + << "Differ Branch 12: Inserting tag/tree that was not in old hierarchy: " + << "[" << newChildPair.shadowView.tag << "]" + << (newChildPair.flattened ? "(flattened)" : "") + << (newChildPair.isConcreteView ? "(concrete)" : "") + << (newChildPair.inOtherTree ? "(in other tree)" : "") + << " with parent: [" << parentShadowView.tag << "]"; + }); + + if (!newChildPair.isConcreteView) { + continue; + } + if (newChildPair.inOtherTree) { + continue; + } + + createMutations.push_back( + ShadowViewMutation::CreateMutation(newChildPair.shadowView)); + + calculateShadowViewMutationsV2( + downwardMutations, + newChildPair.shadowView, + {}, + sliceChildShadowNodeViewPairsV2(*newChildPair.shadowNode)); + } + } + + // All mutations in an optimal order: + std::move( + destructiveDownwardMutations.begin(), + destructiveDownwardMutations.end(), + std::back_inserter(mutations)); + std::move( + updateMutations.begin(), + updateMutations.end(), + std::back_inserter(mutations)); + std::move( + removeMutations.rbegin(), + removeMutations.rend(), + std::back_inserter(mutations)); + std::move( + deleteMutations.begin(), + deleteMutations.end(), + std::back_inserter(mutations)); + std::move( + createMutations.begin(), + createMutations.end(), + std::back_inserter(mutations)); + std::move( + downwardMutations.begin(), + downwardMutations.end(), + std::back_inserter(mutations)); + std::move( + insertMutations.begin(), + insertMutations.end(), + std::back_inserter(mutations)); +} + +static void sliceChildShadowNodeViewPairsRecursively( + ShadowViewNodePair::List &pairList, + Point layoutOffset, + ShadowNode const &shadowNode) { + for (auto const &sharedChildShadowNode : shadowNode.getChildren()) { + auto &childShadowNode = *sharedChildShadowNode; + +#ifndef ANDROID + // Temporary disabled on Android because the mounting infrastructure + // is not fully ready yet. + if (childShadowNode.getTraits().check(ShadowNodeTraits::Trait::Hidden)) { + continue; + } +#endif + + auto shadowView = ShadowView(childShadowNode); + auto origin = layoutOffset; + if (shadowView.layoutMetrics != EmptyLayoutMetrics) { + origin += shadowView.layoutMetrics.frame.origin; + shadowView.layoutMetrics.frame.origin += layoutOffset; + } + + if (childShadowNode.getTraits().check( + ShadowNodeTraits::Trait::FormsStackingContext)) { + pairList.push_back({shadowView, &childShadowNode}); + } else { + if (childShadowNode.getTraits().check( + ShadowNodeTraits::Trait::FormsView)) { + pairList.push_back({shadowView, &childShadowNode}); + } + + sliceChildShadowNodeViewPairsRecursively( + pairList, origin, childShadowNode); + } + } +} + +ShadowViewNodePair::List sliceChildShadowNodeViewPairs( + ShadowNode const &shadowNode) { + auto pairList = ShadowViewNodePair::List{}; + + if (!shadowNode.getTraits().check( + ShadowNodeTraits::Trait::FormsStackingContext) && + shadowNode.getTraits().check(ShadowNodeTraits::Trait::FormsView)) { + return pairList; + } + + sliceChildShadowNodeViewPairsRecursively(pairList, {0, 0}, shadowNode); + + return pairList; +} + static void calculateShadowViewMutations( ShadowViewMutation::List &mutations, ShadowView const &parentShadowView, @@ -317,8 +1545,12 @@ static void calculateShadowViewMutations( DEBUG_LOGS({ LOG(ERROR) << "Differ Branch 1.2: Same tags, update and recurse: [" - << oldChildPair.shadowView.tag << "] [" - << newChildPair.shadowView.tag << "]"; + << oldChildPair.shadowView.tag << "]" + << (oldChildPair.flattened ? " (flattened)" : "") + << (oldChildPair.isConcreteView ? " (concrete)" : "") << "[" + << newChildPair.shadowView.tag << "]" + << (newChildPair.flattened ? " (flattened)" : "") + << (newChildPair.isConcreteView ? " (concrete)" : ""); }); if (oldChildPair.shadowView != newChildPair.shadowView) { @@ -634,11 +1866,19 @@ ShadowViewMutation::List calculateShadowViewMutations( ShadowView(), oldRootShadowView, newRootShadowView, -1)); } - calculateShadowViewMutations( - mutations, - ShadowView(oldRootShadowNode), - sliceChildShadowNodeViewPairs(oldRootShadowNode), - sliceChildShadowNodeViewPairs(newRootShadowNode)); + if (enableReparentingDetection) { + calculateShadowViewMutationsV2( + mutations, + ShadowView(oldRootShadowNode), + sliceChildShadowNodeViewPairsV2(oldRootShadowNode), + sliceChildShadowNodeViewPairsV2(newRootShadowNode)); + } else { + calculateShadowViewMutations( + mutations, + ShadowView(oldRootShadowNode), + sliceChildShadowNodeViewPairs(oldRootShadowNode), + sliceChildShadowNodeViewPairs(newRootShadowNode)); + } return mutations; } diff --git a/ReactCommon/react/renderer/mounting/Differentiator.h b/ReactCommon/react/renderer/mounting/Differentiator.h index c68809ddac8c4f..762bb43ae6bedd 100644 --- a/ReactCommon/react/renderer/mounting/Differentiator.h +++ b/ReactCommon/react/renderer/mounting/Differentiator.h @@ -13,7 +13,7 @@ namespace facebook { namespace react { -enum class DifferentiatorMode { Classic, OptimizedMoves }; +enum class ReparentMode { Flatten, Unflatten }; /* * Calculates a list of view mutations which describes how the old @@ -32,5 +32,14 @@ ShadowViewMutationList calculateShadowViewMutations( ShadowViewNodePair::List sliceChildShadowNodeViewPairs( ShadowNode const &shadowNode); +/** + * Generates a list of `ShadowViewNodePair`s that represents a layer of a + * flattened view hierarchy. The V2 version preserves nodes even if they do + * not form views and their children are flattened. + */ +ShadowViewNodePair::List sliceChildShadowNodeViewPairsV2( + ShadowNode const &shadowNode, + bool allowFlattened = false); + } // namespace react } // namespace facebook diff --git a/ReactCommon/react/renderer/mounting/ShadowView.h b/ReactCommon/react/renderer/mounting/ShadowView.h index 55027683bec0c6..a481941d7eba2f 100644 --- a/ReactCommon/react/renderer/mounting/ShadowView.h +++ b/ReactCommon/react/renderer/mounting/ShadowView.h @@ -20,6 +20,7 @@ namespace react { /* * Describes a view that can be mounted. + * This is exposed to the mounting layer. */ struct ShadowView final { ShadowView() = default; @@ -57,6 +58,8 @@ std::vector getDebugProps( /* * Describes pair of a `ShadowView` and a `ShadowNode`. + * This is not exposed to the mounting layer. + * */ struct ShadowViewNodePair final { using List = better:: @@ -64,6 +67,12 @@ struct ShadowViewNodePair final { ShadowView shadowView; ShadowNode const *shadowNode; + bool flattened{false}; + bool isConcreteView{true}; + + int mountIndex{0}; + + bool inOtherTree{false}; /* * The stored pointer to `ShadowNode` represents an identity of the pair. diff --git a/ReactCommon/react/renderer/mounting/tests/MountingTest.cpp b/ReactCommon/react/renderer/mounting/tests/MountingTest.cpp index 2a09d8b1064e4f..172134fa39c5e6 100644 --- a/ReactCommon/react/renderer/mounting/tests/MountingTest.cpp +++ b/ReactCommon/react/renderer/mounting/tests/MountingTest.cpp @@ -361,5 +361,336 @@ TEST(MountingTest, testReorderingInstructionGeneration) { } } +/** + * Test reparenting mutation instruction generation. + * We cannot practically handle all possible use-cases here. + * It would be helpful to do verification with randomized trees, but it's + * much easier to do that in JS. + */ +TEST(MountingTest, testViewReparentingInstructionGeneration) { + auto eventDispatcher = EventDispatcher::Shared{}; + auto contextContainer = std::make_shared(); + auto componentDescriptorParameters = + ComponentDescriptorParameters{eventDispatcher, contextContainer, nullptr}; + auto viewComponentDescriptor = + ViewComponentDescriptor(componentDescriptorParameters); + auto rootComponentDescriptor = + RootComponentDescriptor(componentDescriptorParameters); + + auto rootFamily = rootComponentDescriptor.createFamily( + {Tag(1), SurfaceId(1), nullptr}, nullptr); + + // Creating an initial root shadow node. + auto emptyRootNode = std::const_pointer_cast( + std::static_pointer_cast( + rootComponentDescriptor.createShadowNode( + ShadowNodeFragment{RootShadowNode::defaultSharedProps()}, + rootFamily))); + + // Applying size constraints. + emptyRootNode = emptyRootNode->clone( + LayoutConstraints{Size{512, 0}, + Size{512, std::numeric_limits::infinity()}}, + LayoutContext{}); + + auto childA = makeNode(viewComponentDescriptor, 100, {}); + auto childB = makeNode(viewComponentDescriptor, 101, {}); + auto childC = makeNode(viewComponentDescriptor, 102, {}); + auto childD = makeNode(viewComponentDescriptor, 103, {}); + auto childE = makeNode(viewComponentDescriptor, 104, {}); + auto childF = makeNode(viewComponentDescriptor, 105, {}); + + auto childG = makeNode(viewComponentDescriptor, 106, {}); + auto childH = makeNode(viewComponentDescriptor, 107, {}); + auto childI = makeNode(viewComponentDescriptor, 108, {}); + auto childJ = makeNode(viewComponentDescriptor, 109, {}); + auto childK = makeNode(viewComponentDescriptor, 110, {}); + + auto family = viewComponentDescriptor.createFamily( + {10, SurfaceId(1), nullptr}, nullptr); + + auto reparentedViewA = makeNode( + viewComponentDescriptor, + 1000, + SharedShadowNodeList{ + childC->clone({}), childA->clone({}), childB->clone({})}); + auto reparentedViewB = makeNode( + viewComponentDescriptor, + 2000, + SharedShadowNodeList{ + childF->clone({}), childE->clone({}), childD->clone({})}); + + // Root -> G* -> H -> I -> J -> A* [nodes with * are _not_ flattened] + auto shadowNodeV1 = viewComponentDescriptor.createShadowNode( + ShadowNodeFragment{ + generateDefaultProps(viewComponentDescriptor), + std::make_shared( + SharedShadowNodeList{childG->clone(ShadowNodeFragment{ + nonFlattenedDefaultProps(viewComponentDescriptor), + std::make_shared( + SharedShadowNodeList{childH->clone(ShadowNodeFragment{ + generateDefaultProps(viewComponentDescriptor), + std::make_shared< + SharedShadowNodeList>(SharedShadowNodeList{ + childI->clone(ShadowNodeFragment{ + generateDefaultProps(viewComponentDescriptor), + std::make_shared( + SharedShadowNodeList{ + childJ->clone(ShadowNodeFragment{ + generateDefaultProps( + viewComponentDescriptor), + std::make_shared< + SharedShadowNodeList>( + SharedShadowNodeList{ + reparentedViewA->clone( + {})})})})})})})})})})}, + family); + + // Root -> G* -> H* -> I -> J -> A* [nodes with * are _not_ flattened] + auto shadowNodeV2 = shadowNodeV1->clone(ShadowNodeFragment{ + generateDefaultProps(viewComponentDescriptor), + std::make_shared( + SharedShadowNodeList{childG->clone(ShadowNodeFragment{ + nonFlattenedDefaultProps(viewComponentDescriptor), + std::make_shared( + SharedShadowNodeList{childH->clone(ShadowNodeFragment{ + nonFlattenedDefaultProps(viewComponentDescriptor), + std::make_shared( + SharedShadowNodeList{childI->clone(ShadowNodeFragment{ + generateDefaultProps(viewComponentDescriptor), + std::make_shared< + SharedShadowNodeList>(SharedShadowNodeList{ + childJ->clone(ShadowNodeFragment{ + generateDefaultProps( + viewComponentDescriptor), + std::make_shared( + SharedShadowNodeList{ + reparentedViewA->clone( + {})})})})})})})})})})}); + + // Root -> G* -> H -> I -> J -> A* [nodes with * are _not_ flattened] + auto shadowNodeV3 = shadowNodeV2->clone(ShadowNodeFragment{ + generateDefaultProps(viewComponentDescriptor), + std::make_shared( + SharedShadowNodeList{childG->clone(ShadowNodeFragment{ + nonFlattenedDefaultProps(viewComponentDescriptor), + std::make_shared( + SharedShadowNodeList{childH->clone(ShadowNodeFragment{ + generateDefaultProps(viewComponentDescriptor), + std::make_shared( + SharedShadowNodeList{childI->clone(ShadowNodeFragment{ + generateDefaultProps(viewComponentDescriptor), + std::make_shared< + SharedShadowNodeList>(SharedShadowNodeList{ + childJ->clone(ShadowNodeFragment{ + generateDefaultProps( + viewComponentDescriptor), + std::make_shared( + SharedShadowNodeList{ + reparentedViewA->clone( + {})})})})})})})})})})}); + + // The view is reparented 1 level down with a different sibling + // Root -> G* -> H* -> I* -> J -> [B*, A*] [nodes with * are _not_ flattened] + auto shadowNodeV4 = shadowNodeV3->clone(ShadowNodeFragment{ + generateDefaultProps(viewComponentDescriptor), + std::make_shared( + SharedShadowNodeList{childG->clone(ShadowNodeFragment{ + nonFlattenedDefaultProps(viewComponentDescriptor), + std::make_shared( + SharedShadowNodeList{childH->clone(ShadowNodeFragment{ + nonFlattenedDefaultProps(viewComponentDescriptor), + std::make_shared( + SharedShadowNodeList{childI->clone(ShadowNodeFragment{ + nonFlattenedDefaultProps(viewComponentDescriptor), + std::make_shared< + SharedShadowNodeList>(SharedShadowNodeList{ + childJ->clone(ShadowNodeFragment{ + generateDefaultProps( + viewComponentDescriptor), + std::make_shared( + SharedShadowNodeList{ + reparentedViewB->clone({}), + reparentedViewA->clone( + {})})})})})})})})})})}); + + // The view is reparented 1 level further down with its order with the sibling + // swapped + // Root -> G* -> H* -> I* -> J* -> [A*, B*] [nodes with * are _not_ flattened] + auto shadowNodeV5 = shadowNodeV4->clone(ShadowNodeFragment{ + generateDefaultProps(viewComponentDescriptor), + std::make_shared( + SharedShadowNodeList{childG->clone(ShadowNodeFragment{ + nonFlattenedDefaultProps(viewComponentDescriptor), + std::make_shared( + SharedShadowNodeList{childH->clone(ShadowNodeFragment{ + nonFlattenedDefaultProps(viewComponentDescriptor), + std::make_shared( + SharedShadowNodeList{childI->clone(ShadowNodeFragment{ + nonFlattenedDefaultProps(viewComponentDescriptor), + std::make_shared< + SharedShadowNodeList>(SharedShadowNodeList{ + childJ->clone(ShadowNodeFragment{ + nonFlattenedDefaultProps( + viewComponentDescriptor), + std::make_shared( + SharedShadowNodeList{ + reparentedViewA->clone({}), + reparentedViewB->clone( + {})})})})})})})})})})}); + + // Injecting a tree into the root node. + auto rootNodeV1 = std::static_pointer_cast( + emptyRootNode->ShadowNode::clone( + ShadowNodeFragment{ShadowNodeFragment::propsPlaceholder(), + std::make_shared( + SharedShadowNodeList{shadowNodeV1})})); + auto rootNodeV2 = std::static_pointer_cast( + rootNodeV1->ShadowNode::clone( + ShadowNodeFragment{ShadowNodeFragment::propsPlaceholder(), + std::make_shared( + SharedShadowNodeList{shadowNodeV2})})); + auto rootNodeV3 = std::static_pointer_cast( + rootNodeV2->ShadowNode::clone( + ShadowNodeFragment{ShadowNodeFragment::propsPlaceholder(), + std::make_shared( + SharedShadowNodeList{shadowNodeV3})})); + auto rootNodeV4 = std::static_pointer_cast( + rootNodeV3->ShadowNode::clone( + ShadowNodeFragment{ShadowNodeFragment::propsPlaceholder(), + std::make_shared( + SharedShadowNodeList{shadowNodeV4})})); + auto rootNodeV5 = std::static_pointer_cast( + rootNodeV4->ShadowNode::clone( + ShadowNodeFragment{ShadowNodeFragment::propsPlaceholder(), + std::make_shared( + SharedShadowNodeList{shadowNodeV5})})); + + // Layout + std::vector affectedLayoutableNodesV1{}; + affectedLayoutableNodesV1.reserve(1024); + std::const_pointer_cast(rootNodeV1) + ->layoutIfNeeded(&affectedLayoutableNodesV1); + rootNodeV1->sealRecursive(); + + std::vector affectedLayoutableNodesV2{}; + affectedLayoutableNodesV2.reserve(1024); + std::const_pointer_cast(rootNodeV2) + ->layoutIfNeeded(&affectedLayoutableNodesV2); + rootNodeV2->sealRecursive(); + + std::vector affectedLayoutableNodesV3{}; + affectedLayoutableNodesV3.reserve(1024); + std::const_pointer_cast(rootNodeV3) + ->layoutIfNeeded(&affectedLayoutableNodesV3); + rootNodeV3->sealRecursive(); + + std::vector affectedLayoutableNodesV4{}; + affectedLayoutableNodesV4.reserve(1024); + std::const_pointer_cast(rootNodeV4) + ->layoutIfNeeded(&affectedLayoutableNodesV4); + rootNodeV4->sealRecursive(); + + std::vector affectedLayoutableNodesV5{}; + affectedLayoutableNodesV5.reserve(1024); + std::const_pointer_cast(rootNodeV5) + ->layoutIfNeeded(&affectedLayoutableNodesV5); + rootNodeV5->sealRecursive(); + + // Calculating mutations. + auto mutations1 = + calculateShadowViewMutations(*rootNodeV1, *rootNodeV2, true); + + EXPECT_EQ(mutations1.size(), 5); + EXPECT_EQ(mutations1[0].type, ShadowViewMutation::Update); + EXPECT_EQ(mutations1[0].oldChildShadowView.tag, 106); + EXPECT_EQ(mutations1[1].type, ShadowViewMutation::Remove); + EXPECT_EQ(mutations1[1].oldChildShadowView.tag, 1000); + EXPECT_EQ(mutations1[2].type, ShadowViewMutation::Create); + EXPECT_EQ(mutations1[2].newChildShadowView.tag, 107); + EXPECT_EQ(mutations1[3].type, ShadowViewMutation::Insert); + EXPECT_EQ(mutations1[3].newChildShadowView.tag, 107); + EXPECT_EQ(mutations1[4].type, ShadowViewMutation::Insert); + EXPECT_EQ(mutations1[4].newChildShadowView.tag, 1000); + + auto mutations2 = + calculateShadowViewMutations(*rootNodeV2, *rootNodeV3, true); + + EXPECT_EQ(mutations2.size(), 5); + EXPECT_EQ(mutations2[0].type, ShadowViewMutation::Update); + EXPECT_EQ(mutations2[0].oldChildShadowView.tag, 106); + EXPECT_EQ(mutations2[1].type, ShadowViewMutation::Remove); + EXPECT_EQ(mutations2[1].oldChildShadowView.tag, 1000); + EXPECT_EQ(mutations2[2].type, ShadowViewMutation::Remove); + EXPECT_EQ(mutations2[2].oldChildShadowView.tag, 107); + EXPECT_EQ( + mutations2[3].type, + ShadowViewMutation::Delete); // correct, 107 is removed from tree entirely + EXPECT_EQ(mutations2[3].oldChildShadowView.tag, 107); + EXPECT_EQ(mutations2[4].type, ShadowViewMutation::Insert); + EXPECT_EQ(mutations2[4].newChildShadowView.tag, 1000); + + auto mutations3 = + calculateShadowViewMutations(*rootNodeV3, *rootNodeV4, true); + + // between these two trees, lots of new nodes are created and inserted - this + // is all correct, and this is the minimal amount of mutations + + EXPECT_EQ(mutations3.size(), 15); + EXPECT_EQ(mutations3[0].type, ShadowViewMutation::Update); + EXPECT_EQ(mutations3[0].oldChildShadowView.tag, 106); + EXPECT_EQ(mutations3[1].type, ShadowViewMutation::Remove); + EXPECT_EQ(mutations3[1].oldChildShadowView.tag, 1000); + EXPECT_EQ(mutations3[2].type, ShadowViewMutation::Create); + EXPECT_EQ(mutations3[2].newChildShadowView.tag, 107); + EXPECT_EQ(mutations3[3].type, ShadowViewMutation::Create); + EXPECT_EQ(mutations3[3].newChildShadowView.tag, 2000); + EXPECT_EQ(mutations3[4].type, ShadowViewMutation::Create); + EXPECT_EQ(mutations3[4].newChildShadowView.tag, 108); + EXPECT_EQ(mutations3[5].type, ShadowViewMutation::Create); + EXPECT_EQ(mutations3[5].newChildShadowView.tag, 105); + EXPECT_EQ(mutations3[6].type, ShadowViewMutation::Create); + EXPECT_EQ(mutations3[6].newChildShadowView.tag, 104); + EXPECT_EQ(mutations3[7].type, ShadowViewMutation::Create); + EXPECT_EQ(mutations3[7].newChildShadowView.tag, 103); + EXPECT_EQ(mutations3[8].type, ShadowViewMutation::Insert); + EXPECT_EQ(mutations3[8].newChildShadowView.tag, 105); + EXPECT_EQ(mutations3[9].type, ShadowViewMutation::Insert); + EXPECT_EQ(mutations3[9].newChildShadowView.tag, 104); + EXPECT_EQ(mutations3[10].type, ShadowViewMutation::Insert); + EXPECT_EQ(mutations3[10].newChildShadowView.tag, 103); + EXPECT_EQ(mutations3[11].type, ShadowViewMutation::Insert); + EXPECT_EQ(mutations3[11].newChildShadowView.tag, 107); + EXPECT_EQ(mutations3[12].type, ShadowViewMutation::Insert); + EXPECT_EQ(mutations3[12].newChildShadowView.tag, 108); + EXPECT_EQ(mutations3[13].type, ShadowViewMutation::Insert); + EXPECT_EQ(mutations3[13].newChildShadowView.tag, 2000); + EXPECT_EQ(mutations3[14].type, ShadowViewMutation::Insert); + EXPECT_EQ(mutations3[14].newChildShadowView.tag, 1000); + + auto mutations4 = + calculateShadowViewMutations(*rootNodeV4, *rootNodeV5, true); + + EXPECT_EQ(mutations4.size(), 9); + EXPECT_EQ(mutations4[0].type, ShadowViewMutation::Update); + EXPECT_EQ(mutations4[0].oldChildShadowView.tag, 106); + EXPECT_EQ(mutations4[1].type, ShadowViewMutation::Update); + EXPECT_EQ(mutations4[1].oldChildShadowView.tag, 107); + EXPECT_EQ(mutations4[2].type, ShadowViewMutation::Update); + EXPECT_EQ(mutations4[2].oldChildShadowView.tag, 108); + EXPECT_EQ(mutations4[3].type, ShadowViewMutation::Remove); + EXPECT_EQ(mutations4[3].oldChildShadowView.tag, 1000); + EXPECT_EQ(mutations4[4].type, ShadowViewMutation::Remove); + EXPECT_EQ(mutations4[4].oldChildShadowView.tag, 2000); + EXPECT_EQ(mutations4[5].type, ShadowViewMutation::Create); + EXPECT_EQ(mutations4[5].newChildShadowView.tag, 109); + EXPECT_EQ(mutations4[6].type, ShadowViewMutation::Insert); + EXPECT_EQ(mutations4[6].newChildShadowView.tag, 109); + EXPECT_EQ(mutations4[7].type, ShadowViewMutation::Insert); + EXPECT_EQ(mutations4[7].newChildShadowView.tag, 1000); + EXPECT_EQ(mutations4[8].type, ShadowViewMutation::Insert); + EXPECT_EQ(mutations4[8].newChildShadowView.tag, 2000); +} + } // namespace react } // namespace facebook diff --git a/ReactCommon/react/renderer/mounting/tests/ShadowTreeLifeCycleTest.cpp b/ReactCommon/react/renderer/mounting/tests/ShadowTreeLifeCycleTest.cpp index 1def45c3cad4a3..851231da950841 100644 --- a/ReactCommon/react/renderer/mounting/tests/ShadowTreeLifeCycleTest.cpp +++ b/ReactCommon/react/renderer/mounting/tests/ShadowTreeLifeCycleTest.cpp @@ -23,7 +23,8 @@ static void testShadowNodeTreeLifeCycle( uint_fast32_t seed, int treeSize, int repeats, - int stages) { + int stages, + bool useFlattener) { auto entropy = seed == 0 ? Entropy() : Entropy(seed); auto eventDispatcher = EventDispatcher::Shared{}; @@ -98,8 +99,8 @@ static void testShadowNodeTreeLifeCycle( allNodes.push_back(nextRootNode); // Calculating mutations. - auto mutations = - calculateShadowViewMutations(*currentRootNode, *nextRootNode); + auto mutations = calculateShadowViewMutations( + *currentRootNode, *nextRootNode, useFlattener); // Mutating the view tree. viewTree.mutate(mutations); @@ -152,7 +153,8 @@ TEST(MountingTest, stableBiggerTreeFewerIterationsOptimizedMoves) { /* seed */ 0, /* size */ 512, /* repeats */ 32, - /* stages */ 32); + /* stages */ 32, + false); } TEST(MountingTest, stableSmallerTreeMoreIterationsOptimizedMoves) { @@ -160,5 +162,33 @@ TEST(MountingTest, stableSmallerTreeMoreIterationsOptimizedMoves) { /* seed */ 0, /* size */ 16, /* repeats */ 512, - /* stages */ 32); + /* stages */ 32, + false); +} + +TEST(MountingTest, stableBiggerTreeFewerIterationsOptimizedMovesFlattener) { + testShadowNodeTreeLifeCycle( + /* seed */ 0, + /* size */ 512, + /* repeats */ 32, + /* stages */ 32, + true); +} + +TEST(MountingTest, stableBiggerTreeFewerIterationsOptimizedMovesFlattener2) { + testShadowNodeTreeLifeCycle( + /* seed */ 1, + /* size */ 512, + /* repeats */ 32, + /* stages */ 32, + true); +} + +TEST(MountingTest, stableSmallerTreeMoreIterationsOptimizedMovesFlattener) { + testShadowNodeTreeLifeCycle( + /* seed */ 0, + /* size */ 16, + /* repeats */ 512, + /* stages */ 32, + true); } From 059e4246286bd6bda9234c8848697ef84c067b20 Mon Sep 17 00:00:00 2001 From: Joshua Gross Date: Mon, 24 Aug 2020 13:06:36 -0700 Subject: [PATCH 0043/1238] Classic Differ: don't recurse down subtrees if parents are pointer-identical Summary: Fairly self-explanatory. Should make a fairly meaningful perf difference. Changelog: [Internal] Reviewed By: shergin Differential Revision: D23296681 fbshipit-source-id: 727d0fb619eeef1b4bf8a47457c4746e6b31be80 --- .../renderer/mounting/Differentiator.cpp | 44 ++++++++++--------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/ReactCommon/react/renderer/mounting/Differentiator.cpp b/ReactCommon/react/renderer/mounting/Differentiator.cpp index 58c7dad749ba74..300c38059f8a64 100644 --- a/ReactCommon/react/renderer/mounting/Differentiator.cpp +++ b/ReactCommon/react/renderer/mounting/Differentiator.cpp @@ -1677,16 +1677,18 @@ static void calculateShadowViewMutations( } // Update subtrees - auto oldGrandChildPairs = - sliceChildShadowNodeViewPairs(*oldChildPair.shadowNode); - auto newGrandChildPairs = - sliceChildShadowNodeViewPairs(*newChildPair.shadowNode); - calculateShadowViewMutations( - *(newGrandChildPairs.size() ? &downwardMutations - : &destructiveDownwardMutations), - oldChildPair.shadowView, - std::move(oldGrandChildPairs), - std::move(newGrandChildPairs)); + if (oldChildPair.shadowNode != newChildPair.shadowNode) { + auto oldGrandChildPairs = + sliceChildShadowNodeViewPairs(*oldChildPair.shadowNode); + auto newGrandChildPairs = + sliceChildShadowNodeViewPairs(*newChildPair.shadowNode); + calculateShadowViewMutations( + *(newGrandChildPairs.size() ? &downwardMutations + : &destructiveDownwardMutations), + oldChildPair.shadowView, + std::move(oldGrandChildPairs), + std::move(newGrandChildPairs)); + } newIndex++; oldIndex++; @@ -1724,16 +1726,18 @@ static void calculateShadowViewMutations( } // Update subtrees - auto oldGrandChildPairs = - sliceChildShadowNodeViewPairs(*oldChildPair.shadowNode); - auto newGrandChildPairs = - sliceChildShadowNodeViewPairs(*newChildPair.shadowNode); - calculateShadowViewMutations( - *(newGrandChildPairs.size() ? &downwardMutations - : &destructiveDownwardMutations), - oldChildPair.shadowView, - std::move(oldGrandChildPairs), - std::move(newGrandChildPairs)); + if (oldChildPair.shadowNode != newChildPair.shadowNode) { + auto oldGrandChildPairs = + sliceChildShadowNodeViewPairs(*oldChildPair.shadowNode); + auto newGrandChildPairs = + sliceChildShadowNodeViewPairs(*newChildPair.shadowNode); + calculateShadowViewMutations( + *(newGrandChildPairs.size() ? &downwardMutations + : &destructiveDownwardMutations), + oldChildPair.shadowView, + std::move(oldGrandChildPairs), + std::move(newGrandChildPairs)); + } newInsertedPairs.erase(insertedIt); oldIndex++; From 8edd2e3ef6553c0c2be2c8111010fa2082c6b107 Mon Sep 17 00:00:00 2001 From: Tim Yung Date: Mon, 24 Aug 2020 15:22:50 -0700 Subject: [PATCH 0044/1238] RN: Extract `ScrollViewContext` Summary: Extracts `ScrollViewContext` so that other components can use it without requiring `ScrollView` as a dependency. Changelog: [Internal] Reviewed By: kacieb Differential Revision: D22670035 fbshipit-source-id: 7f902697ad2a60cd1869438e9a2b77e479a18065 --- Libraries/Components/ScrollView/ScrollView.js | 23 ++++++------------- .../ScrollView/ScrollViewContext.js | 22 ++++++++++++++++++ 2 files changed, 29 insertions(+), 16 deletions(-) create mode 100644 Libraries/Components/ScrollView/ScrollViewContext.js diff --git a/Libraries/Components/ScrollView/ScrollView.js b/Libraries/Components/ScrollView/ScrollView.js index c8a56d12686bf1..c6a90fb05fd18a 100644 --- a/Libraries/Components/ScrollView/ScrollView.js +++ b/Libraries/Components/ScrollView/ScrollView.js @@ -42,6 +42,7 @@ import type {State as ScrollResponderState} from '../ScrollResponder'; import type {ViewProps} from '../View/ViewPropTypes'; import type {Props as ScrollViewStickyHeaderProps} from './ScrollViewStickyHeader'; +import ScrollViewContext, {HORIZONTAL, VERTICAL} from './ScrollViewContext'; import ScrollViewNativeComponent from './ScrollViewNativeComponent'; import ScrollContentViewNativeComponent from './ScrollContentViewNativeComponent'; import AndroidHorizontalScrollViewNativeComponent from './AndroidHorizontalScrollViewNativeComponent'; @@ -610,14 +611,8 @@ function createScrollResponder( return scrollResponder; } -type ContextType = {|horizontal: boolean|} | null; -const Context: React.Context = React.createContext(null); -const standardHorizontalContext: ContextType = Object.freeze({ - horizontal: true, -}); -const standardVerticalContext: ContextType = Object.freeze({horizontal: false}); type ScrollViewComponentStatics = $ReadOnly<{| - Context: typeof Context, + Context: typeof ScrollViewContext, |}>; /** @@ -656,7 +651,7 @@ type ScrollViewComponentStatics = $ReadOnly<{| * supports out of the box. */ class ScrollView extends React.Component { - static Context: React$Context = Context; + static Context: typeof ScrollViewContext = ScrollViewContext; /** * Part 1: Removing ScrollResponder.Mixin: * @@ -1096,14 +1091,10 @@ class ScrollView extends React.Component { }); } children = ( - + {children} - + ); const hasStickyHeaders = @@ -1277,7 +1268,7 @@ Wrapper.displayName = 'ScrollView'; const ForwardedScrollView = React.forwardRef(Wrapper); // $FlowFixMe Add static context to ForwardedScrollView -ForwardedScrollView.Context = Context; +ForwardedScrollView.Context = ScrollViewContext; ForwardedScrollView.displayName = 'ScrollView'; diff --git a/Libraries/Components/ScrollView/ScrollViewContext.js b/Libraries/Components/ScrollView/ScrollViewContext.js new file mode 100644 index 00000000000000..f774483912d928 --- /dev/null +++ b/Libraries/Components/ScrollView/ScrollViewContext.js @@ -0,0 +1,22 @@ +/** + * 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. + * + * @flow strict + * @format + */ + +'use strict'; + +import * as React from 'react'; + +type Value = {horizontal: boolean} | null; + +const ScrollViewContext: React.Context = React.createContext(null); + +export default ScrollViewContext; + +export const HORIZONTAL: Value = Object.freeze({horizontal: true}); +export const VERTICAL: Value = Object.freeze({horizontal: false}); From 3cb78d5189665eaa07f4b407efdf06564cd45fd4 Mon Sep 17 00:00:00 2001 From: Samuel Susla Date: Mon, 24 Aug 2020 15:30:51 -0700 Subject: [PATCH 0045/1238] Remove State Reconciliation flags and dead code Summary: Changelog: [Internal] Reviewed By: shergin Differential Revision: D23292369 fbshipit-source-id: 6f00070495e9947476f1dbea7776ca85002e078b --- .../react/renderer/mounting/ShadowTree.cpp | 22 +---- .../react/renderer/mounting/ShadowTree.h | 7 -- .../mounting/TreeStateReconciliation.cpp | 94 ------------------- .../mounting/TreeStateReconciliation.h | 33 ------- .../react/renderer/scheduler/Scheduler.cpp | 6 -- .../react/renderer/scheduler/Scheduler.h | 1 - 6 files changed, 5 insertions(+), 158 deletions(-) delete mode 100644 ReactCommon/react/renderer/mounting/TreeStateReconciliation.cpp delete mode 100644 ReactCommon/react/renderer/mounting/TreeStateReconciliation.h diff --git a/ReactCommon/react/renderer/mounting/ShadowTree.cpp b/ReactCommon/react/renderer/mounting/ShadowTree.cpp index a0b5b2dc3c0644..8224995a164aad 100644 --- a/ReactCommon/react/renderer/mounting/ShadowTree.cpp +++ b/ReactCommon/react/renderer/mounting/ShadowTree.cpp @@ -17,7 +17,6 @@ #include #include "ShadowTreeDelegate.h" -#include "TreeStateReconciliation.h" namespace facebook { namespace react { @@ -303,22 +302,11 @@ bool ShadowTree::tryCommit( } if (enableStateReconciliation) { - if (enableNewStateReconciliation_) { - auto updatedNewRootShadowNode = - progressState(*newRootShadowNode, *oldRootShadowNode); - if (updatedNewRootShadowNode) { - newRootShadowNode = - std::static_pointer_cast(updatedNewRootShadowNode); - } - } else { - // Compare state revisions of old and new root - // Children of the root node may be mutated in-place - UnsharedShadowNode reconciledNode = - reconcileStateWithTree(newRootShadowNode.get(), oldRootShadowNode); - if (reconciledNode != nullptr) { - newRootShadowNode = std::make_shared( - *reconciledNode, ShadowNodeFragment{}); - } + auto updatedNewRootShadowNode = + progressState(*newRootShadowNode, *oldRootShadowNode); + if (updatedNewRootShadowNode) { + newRootShadowNode = + std::static_pointer_cast(updatedNewRootShadowNode); } } diff --git a/ReactCommon/react/renderer/mounting/ShadowTree.h b/ReactCommon/react/renderer/mounting/ShadowTree.h index 70155de275f11d..06e4e6c3e43c8c 100644 --- a/ReactCommon/react/renderer/mounting/ShadowTree.h +++ b/ReactCommon/react/renderer/mounting/ShadowTree.h @@ -81,13 +81,6 @@ class ShadowTree final { MountingCoordinator::Shared getMountingCoordinator() const; - /* - * Temporary. - * Do not use. - */ - void setEnableNewStateReconciliation(bool value) { - enableNewStateReconciliation_ = value; - } void setEnableReparentingDetection(bool value) { enableReparentingDetection_ = value; } diff --git a/ReactCommon/react/renderer/mounting/TreeStateReconciliation.cpp b/ReactCommon/react/renderer/mounting/TreeStateReconciliation.cpp deleted file mode 100644 index 58017f16a3c6c8..00000000000000 --- a/ReactCommon/react/renderer/mounting/TreeStateReconciliation.cpp +++ /dev/null @@ -1,94 +0,0 @@ -/* - * 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. - */ - -#include "TreeStateReconciliation.h" - -namespace facebook { -namespace react { - -using ChangedShadowNodePairs = - std::vector>; - -/** - * Clones any children in the subtree that need to be cloned, and adds those to - * the `changedPairs` vector argument. - */ -static ChangedShadowNodePairs reconcileStateWithChildren( - SharedShadowNodeList const &newChildren, - SharedShadowNodeList const &oldChildren) { - ChangedShadowNodePairs changedPairs; - // Find children that are the same family in both trees. - // We only want to find nodes that existing in the new tree - if they - // don't exist in the new tree, they're being deleted; if they don't exist - // in the old tree, they're new. We don't need to deal with either of those - // cases here. - // Currently we use a naive double loop - this could be improved, but we need - // to be able to handle cases where nodes are entirely reordered, for - // instance. - for (auto const &child : newChildren) { - auto const oldChild = std::find_if( - oldChildren.begin(), oldChildren.end(), [&](const auto &el) { - return ShadowNode::sameFamily(*child, *el); - }); - - if (oldChild != oldChildren.end()) { - UnsharedShadowNode newChild = - reconcileStateWithTree(child.get(), *oldChild); - if (newChild != nullptr) { - changedPairs.push_back(std::make_pair(child, newChild)); - } - } - }; - - return changedPairs; -} - -UnsharedShadowNode reconcileStateWithTree( - ShadowNode const *newNode, - SharedShadowNode committedNode) { - // If the revisions on the node are the same, we can finish here. - // Subtrees are guaranteed to be identical at this point, too. - if (committedNode->getStateRevision() <= newNode->getStateRevision()) { - return nullptr; - } - - // If we got this fair, we're guaranteed that the state of 1) this node, - // and/or 2) some descendant node is out-of-date and must be reconciled. - // This requires traversing all children, and we must at *least* clone - // this node, whether or not we clone and update any children. - auto const &newChildren = newNode->getChildren(); - auto const &oldChildren = committedNode->getChildren(); - auto const changedPairs = - reconcileStateWithChildren(newChildren, oldChildren); - - ShadowNode::SharedListOfShared clonedChildren = - ShadowNodeFragment::childrenPlaceholder(); - - // If any children were cloned, we need to recreate the child list. - // This won't cause any children to be cloned that weren't already cloned - - // it just collects all children, cloned or uncloned, into a new list. - if (!changedPairs.empty()) { - ShadowNode::UnsharedListOfShared newList = - std::make_shared(); - for (std::size_t i = 0, j = 0; i < newChildren.size(); ++i) { - if (j < changedPairs.size() && changedPairs[j].first == newChildren[i]) { - newList->push_back(changedPairs[j].second); - ++j; - } else { - newList->push_back(newChildren[i]); - } - } - clonedChildren = newList; - } - - return newNode->clone({/* .props = */ ShadowNodeFragment::propsPlaceholder(), - /* .children = */ clonedChildren, - /* .state = */ newNode->getMostRecentState()}); -} - -} // namespace react -} // namespace facebook diff --git a/ReactCommon/react/renderer/mounting/TreeStateReconciliation.h b/ReactCommon/react/renderer/mounting/TreeStateReconciliation.h deleted file mode 100644 index ff95b7e763d2c8..00000000000000 --- a/ReactCommon/react/renderer/mounting/TreeStateReconciliation.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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. - */ - -#include -#include - -namespace facebook { -namespace react { - -/** - * Problem Description: because of C++ State, the React Native C++ ShadowTree - * can diverge from the ReactJS ShadowTree; ReactJS communicates all tree - * changes to C++, but C++ state commits are not propagated to ReactJS (ReactJS - * may or may not clone nodes with state changes, but it has no way of knowing - * if it /should/ clone those nodes; so those clones may never happen). This - * causes a number of problems. This function resolves the problem by taking a - * candidate tree being committed, and sees if any State changes need to be - * applied to it. If any changes need to be made, a new ShadowNode is returned; - * otherwise, nullptr is returned if the node is already consistent with the - * latest tree, including all state changes. - * - * This should be called during the commit phase, pre-layout and pre-diff. - */ -UnsharedShadowNode reconcileStateWithTree( - ShadowNode const *newNode, - SharedShadowNode committedNode); - -} // namespace react -} // namespace facebook diff --git a/ReactCommon/react/renderer/scheduler/Scheduler.cpp b/ReactCommon/react/renderer/scheduler/Scheduler.cpp index 58128870bd0a7c..39d733264a89e6 100644 --- a/ReactCommon/react/renderer/scheduler/Scheduler.cpp +++ b/ReactCommon/react/renderer/scheduler/Scheduler.cpp @@ -108,15 +108,11 @@ Scheduler::Scheduler( #ifdef ANDROID enableReparentingDetection_ = reactNativeConfig_->getBool( "react_fabric:enable_reparenting_detection_android"); - enableNewStateReconciliation_ = reactNativeConfig_->getBool( - "react_fabric:enable_new_state_reconciliation_android"); removeOutstandingSurfacesOnDestruction_ = reactNativeConfig_->getBool( "react_fabric:remove_outstanding_surfaces_on_destruction_android"); #else enableReparentingDetection_ = reactNativeConfig_->getBool( "react_fabric:enable_reparenting_detection_ios"); - enableNewStateReconciliation_ = reactNativeConfig_->getBool( - "react_fabric:enable_new_state_reconciliation_ios"); removeOutstandingSurfacesOnDestruction_ = reactNativeConfig_->getBool( "react_fabric:remove_outstanding_surfaces_on_destruction_ios"); #endif @@ -192,8 +188,6 @@ void Scheduler::startSurface( mountingOverrideDelegate, enableReparentingDetection_); - shadowTree->setEnableNewStateReconciliation(enableNewStateReconciliation_); - auto uiManager = uiManager_; uiManager->getShadowTreeRegistry().add(std::move(shadowTree)); diff --git a/ReactCommon/react/renderer/scheduler/Scheduler.h b/ReactCommon/react/renderer/scheduler/Scheduler.h index c025b39a3b98dd..3b5693cb724093 100644 --- a/ReactCommon/react/renderer/scheduler/Scheduler.h +++ b/ReactCommon/react/renderer/scheduler/Scheduler.h @@ -138,7 +138,6 @@ class Scheduler final : public UIManagerDelegate { * Temporary flags. */ bool enableReparentingDetection_{false}; - bool enableNewStateReconciliation_{false}; bool removeOutstandingSurfacesOnDestruction_{false}; }; From e1d53ce6971f919697a2d2747935f013abe932fe Mon Sep 17 00:00:00 2001 From: Peter Argany Date: Mon, 24 Aug 2020 16:34:58 -0700 Subject: [PATCH 0046/1238] Create init method for RCTNativeAnimatedModule and it's TM fork Summary: The animated native module relies on `setBridge` to perform generic setup which doesn't rely on the bridge at all. This diff refactors that setup code to an `init` function. Changelog: [Internal] Differential Revision: D23272427 fbshipit-source-id: 0c9c5522c9044283f4db25360010465ff42aba25 --- .../RCTNativeAnimatedModule.mm | 20 ++++++++++++---- .../RCTNativeAnimatedTurboModule.mm | 23 +++++++++++++------ 2 files changed, 31 insertions(+), 12 deletions(-) diff --git a/Libraries/NativeAnimation/RCTNativeAnimatedModule.mm b/Libraries/NativeAnimation/RCTNativeAnimatedModule.mm index 742794d80a50b9..5483b8809a9913 100644 --- a/Libraries/NativeAnimation/RCTNativeAnimatedModule.mm +++ b/Libraries/NativeAnimation/RCTNativeAnimatedModule.mm @@ -28,6 +28,21 @@ @implementation RCTNativeAnimatedModule RCT_EXPORT_MODULE(); ++ (BOOL)requiresMainQueueSetup +{ + return NO; +} + +- (instancetype)init +{ + if (self = [super init]) { + _operations = [NSMutableArray new]; + _preOperations = [NSMutableArray new]; + _animIdIsManagedByFabric = [NSMutableDictionary new]; + } + return self; +} + - (void)invalidate { [_nodesManager stopAnimationLoop]; @@ -47,12 +62,7 @@ - (dispatch_queue_t)methodQueue - (void)setBridge:(RCTBridge *)bridge { [super setBridge:bridge]; - _nodesManager = [[RCTNativeAnimatedNodesManager alloc] initWithBridge:self.bridge]; - _operations = [NSMutableArray new]; - _preOperations = [NSMutableArray new]; - _animIdIsManagedByFabric = [NSMutableDictionary new]; - [bridge.eventDispatcher addDispatchObserver:self]; [bridge.uiManager.observerCoordinator addObserver:self]; [bridge.surfacePresenter addObserver:self]; diff --git a/Libraries/NativeAnimation/RCTNativeAnimatedTurboModule.mm b/Libraries/NativeAnimation/RCTNativeAnimatedTurboModule.mm index 81adca98f30a43..4bad8a605029ba 100644 --- a/Libraries/NativeAnimation/RCTNativeAnimatedTurboModule.mm +++ b/Libraries/NativeAnimation/RCTNativeAnimatedTurboModule.mm @@ -6,11 +6,10 @@ */ #import +#import #import #import -#import - #import "RCTAnimationPlugins.h" typedef void (^AnimatedOperation)(RCTNativeAnimatedNodesManager *nodesManager); @@ -31,6 +30,21 @@ @implementation RCTNativeAnimatedTurboModule RCT_EXPORT_MODULE(); ++ (BOOL)requiresMainQueueSetup +{ + return NO; +} + +- (instancetype)init +{ + if (self = [super init]) { + _operations = [NSMutableArray new]; + _preOperations = [NSMutableArray new]; + _animIdIsManagedByFabric = [NSMutableDictionary new]; + } + return self; +} + - (void)invalidate { [_nodesManager stopAnimationLoop]; @@ -50,12 +64,7 @@ - (dispatch_queue_t)methodQueue - (void)setBridge:(RCTBridge *)bridge { [super setBridge:bridge]; - _nodesManager = [[RCTNativeAnimatedNodesManager alloc] initWithBridge:self.bridge]; - _operations = [NSMutableArray new]; - _preOperations = [NSMutableArray new]; - _animIdIsManagedByFabric = [NSMutableDictionary new]; - [bridge.eventDispatcher addDispatchObserver:self]; [bridge.uiManager.observerCoordinator addObserver:self]; [bridge.surfacePresenter addObserver:self]; From 700960c9f1a27a12d703b4f0a17673690799f019 Mon Sep 17 00:00:00 2001 From: Peter Argany Date: Mon, 24 Aug 2020 16:34:58 -0700 Subject: [PATCH 0047/1238] Pass SurfacePresenter directly instead of relying on bridge Summary: `RCTPropsAnimatedNode` uses the bridge to access it's current surface presenter to perform animations. In bridgeless mode, the surface presenter is not owned by the bridge. Instead, pass the surface presenter through the ownership chain: `RCTNativeAnimated*Module` -> `RCTNativeAnimatedNodesManager` -> `RCTPropsAnimatedNode` `RCTSurfacePresenter` should not be strongly held by any of these animation internals. If it gets destroyed at a higher level, animations should not be completed. Changelog: [Internal] Differential Revision: D23272735 fbshipit-source-id: ce08ee3b59ac2ba70e31cebb7ba8e9f3a644c848 --- .../Nodes/RCTPropsAnimatedNode.h | 5 +++- .../Nodes/RCTPropsAnimatedNode.m | 23 +++++++++++-------- .../RCTNativeAnimatedModule.mm | 2 +- .../RCTNativeAnimatedNodesManager.h | 4 +++- .../RCTNativeAnimatedNodesManager.m | 9 ++++++-- .../RCTNativeAnimatedTurboModule.mm | 9 ++++---- .../RCTNativeAnimatedNodesManagerTests.m | 2 +- 7 files changed, 35 insertions(+), 19 deletions(-) diff --git a/Libraries/NativeAnimation/Nodes/RCTPropsAnimatedNode.h b/Libraries/NativeAnimation/Nodes/RCTPropsAnimatedNode.h index 1486833787ede3..0b5f5329419c7a 100644 --- a/Libraries/NativeAnimation/Nodes/RCTPropsAnimatedNode.h +++ b/Libraries/NativeAnimation/Nodes/RCTPropsAnimatedNode.h @@ -7,6 +7,8 @@ #import "RCTAnimatedNode.h" +#import + @class RCTBridge; @class RCTViewPropertyMapper; @@ -14,7 +16,8 @@ - (void)connectToView:(NSNumber *)viewTag viewName:(NSString *)viewName - bridge:(RCTBridge *)bridge; + bridge:(RCTBridge *)bridge + surfacePresenter:(id)surfacePresenter; - (void)disconnectFromView:(NSNumber *)viewTag; diff --git a/Libraries/NativeAnimation/Nodes/RCTPropsAnimatedNode.m b/Libraries/NativeAnimation/Nodes/RCTPropsAnimatedNode.m index 5c31145d84f7c0..afb6a67e34c60a 100644 --- a/Libraries/NativeAnimation/Nodes/RCTPropsAnimatedNode.m +++ b/Libraries/NativeAnimation/Nodes/RCTPropsAnimatedNode.m @@ -5,24 +5,21 @@ * LICENSE file in the root directory of this source tree. */ -#import - -#import -#import -#import +#import "RCTPropsAnimatedNode.h" #import +#import #import +#import #import - - @implementation RCTPropsAnimatedNode { NSNumber *_connectedViewTag; NSNumber *_rootTag; NSString *_connectedViewName; __weak RCTBridge *_bridge; + __weak id _surfacePresenter; NSMutableDictionary *_propsDictionary; // TODO: use RawProps or folly::dynamic directly BOOL _managedByFabric; } @@ -44,8 +41,10 @@ - (BOOL)isManagedByFabric - (void)connectToView:(NSNumber *)viewTag viewName:(NSString *)viewName bridge:(RCTBridge *)bridge + surfacePresenter:(id )surfacePresenter { _bridge = bridge; + _surfacePresenter = surfacePresenter; _connectedViewTag = viewTag; _connectedViewName = viewName; _managedByFabric = RCTUIManagerTypeForTagIsFabric(viewTag); @@ -55,6 +54,7 @@ - (void)connectToView:(NSNumber *)viewTag - (void)disconnectFromView:(NSNumber *)viewTag { _bridge = nil; + _surfacePresenter = nil; _connectedViewTag = nil; _connectedViewName = nil; _managedByFabric = NO; @@ -64,8 +64,13 @@ - (void)disconnectFromView:(NSNumber *)viewTag - (void)updateView { if (_managedByFabric) { - [_bridge.surfacePresenter synchronouslyUpdateViewOnUIThread:_connectedViewTag - props:_propsDictionary]; + if (_bridge.surfacePresenter) { + [_bridge.surfacePresenter synchronouslyUpdateViewOnUIThread:_connectedViewTag + props:_propsDictionary]; + } else { + [_surfacePresenter synchronouslyUpdateViewOnUIThread:_connectedViewTag + props:_propsDictionary]; + } } else { [_bridge.uiManager synchronouslyUpdateViewOnUIThread:_connectedViewTag viewName:_connectedViewName diff --git a/Libraries/NativeAnimation/RCTNativeAnimatedModule.mm b/Libraries/NativeAnimation/RCTNativeAnimatedModule.mm index 5483b8809a9913..169c1ed6b234a8 100644 --- a/Libraries/NativeAnimation/RCTNativeAnimatedModule.mm +++ b/Libraries/NativeAnimation/RCTNativeAnimatedModule.mm @@ -62,7 +62,7 @@ - (dispatch_queue_t)methodQueue - (void)setBridge:(RCTBridge *)bridge { [super setBridge:bridge]; - _nodesManager = [[RCTNativeAnimatedNodesManager alloc] initWithBridge:self.bridge]; + _nodesManager = [[RCTNativeAnimatedNodesManager alloc] initWithBridge:self.bridge surfacePresenter:bridge.surfacePresenter]; [bridge.eventDispatcher addDispatchObserver:self]; [bridge.uiManager.observerCoordinator addObserver:self]; [bridge.surfacePresenter addObserver:self]; diff --git a/Libraries/NativeAnimation/RCTNativeAnimatedNodesManager.h b/Libraries/NativeAnimation/RCTNativeAnimatedNodesManager.h index 490117a885d8cf..a3e350842683f4 100644 --- a/Libraries/NativeAnimation/RCTNativeAnimatedNodesManager.h +++ b/Libraries/NativeAnimation/RCTNativeAnimatedNodesManager.h @@ -8,12 +8,14 @@ #import #import #import +#import @protocol RCTValueAnimatedNodeObserver; @interface RCTNativeAnimatedNodesManager : NSObject -- (nonnull instancetype)initWithBridge:(nonnull RCTBridge *)bridge; +- (nonnull instancetype)initWithBridge:(nonnull RCTBridge *)bridge + surfacePresenter:(id)surfacePresenter; - (void)updateAnimations; diff --git a/Libraries/NativeAnimation/RCTNativeAnimatedNodesManager.m b/Libraries/NativeAnimation/RCTNativeAnimatedNodesManager.m index 265ff81d4ecf0c..762b44c5b40507 100644 --- a/Libraries/NativeAnimation/RCTNativeAnimatedNodesManager.m +++ b/Libraries/NativeAnimation/RCTNativeAnimatedNodesManager.m @@ -46,6 +46,7 @@ @implementation RCTNativeAnimatedNodesManager { __weak RCTBridge *_bridge; + __weak id _surfacePresenter; NSMutableDictionary *_animationNodes; // Mapping of a view tag and an event name to a list of event animation drivers. 99% of the time // there will be only one driver per mapping so all code code should be optimized around that. @@ -54,10 +55,11 @@ @implementation RCTNativeAnimatedNodesManager CADisplayLink *_displayLink; } -- (instancetype)initWithBridge:(nonnull RCTBridge *)bridge +- (instancetype)initWithBridge:(nonnull RCTBridge *)bridge surfacePresenter:(id)surfacePresenter; { if ((self = [super init])) { _bridge = bridge; + _surfacePresenter = surfacePresenter; _animationNodes = [NSMutableDictionary new]; _eventDrivers = [NSMutableDictionary new]; _activeAnimations = [NSMutableSet new]; @@ -148,7 +150,10 @@ - (void)connectAnimatedNodeToView:(nonnull NSNumber *)nodeTag { RCTAnimatedNode *node = _animationNodes[nodeTag]; if ([node isKindOfClass:[RCTPropsAnimatedNode class]]) { - [(RCTPropsAnimatedNode *)node connectToView:viewTag viewName:viewName bridge:_bridge]; + [(RCTPropsAnimatedNode *)node connectToView:viewTag + viewName:viewName + bridge:_bridge + surfacePresenter:_surfacePresenter]; } [node setNeedsUpdate]; } diff --git a/Libraries/NativeAnimation/RCTNativeAnimatedTurboModule.mm b/Libraries/NativeAnimation/RCTNativeAnimatedTurboModule.mm index 4bad8a605029ba..0c97901a069d76 100644 --- a/Libraries/NativeAnimation/RCTNativeAnimatedTurboModule.mm +++ b/Libraries/NativeAnimation/RCTNativeAnimatedTurboModule.mm @@ -20,7 +20,7 @@ @interface RCTNativeAnimatedTurboModule() @implementation RCTNativeAnimatedTurboModule { RCTNativeAnimatedNodesManager *_nodesManager; - + __weak id _surfacePresenter; // Operations called after views have been updated. NSMutableArray *_operations; // Operations called before views have been updated. @@ -50,7 +50,7 @@ - (void)invalidate [_nodesManager stopAnimationLoop]; [self.bridge.eventDispatcher removeDispatchObserver:self]; [self.bridge.uiManager.observerCoordinator removeObserver:self]; - [self.bridge.surfacePresenter removeObserver:self]; + [_surfacePresenter removeObserver:self]; } - (dispatch_queue_t)methodQueue @@ -64,10 +64,11 @@ - (dispatch_queue_t)methodQueue - (void)setBridge:(RCTBridge *)bridge { [super setBridge:bridge]; - _nodesManager = [[RCTNativeAnimatedNodesManager alloc] initWithBridge:self.bridge]; + _surfacePresenter = bridge.surfacePresenter; + _nodesManager = [[RCTNativeAnimatedNodesManager alloc] initWithBridge:self.bridge surfacePresenter:_surfacePresenter]; [bridge.eventDispatcher addDispatchObserver:self]; [bridge.uiManager.observerCoordinator addObserver:self]; - [bridge.surfacePresenter addObserver:self]; + [_surfacePresenter addObserver:self]; } #pragma mark -- API diff --git a/packages/rn-tester/RNTesterUnitTests/RCTNativeAnimatedNodesManagerTests.m b/packages/rn-tester/RNTesterUnitTests/RCTNativeAnimatedNodesManagerTests.m index c5c599976ed4cf..244023c33e0bb7 100644 --- a/packages/rn-tester/RNTesterUnitTests/RCTNativeAnimatedNodesManagerTests.m +++ b/packages/rn-tester/RNTesterUnitTests/RCTNativeAnimatedNodesManagerTests.m @@ -129,7 +129,7 @@ - (void)setUp RCTBridge *bridge = [OCMockObject niceMockForClass:[RCTBridge class]]; _uiManager = [OCMockObject niceMockForClass:[RCTUIManager class]]; OCMStub([bridge uiManager]).andReturn(_uiManager); - _nodesManager = [[RCTNativeAnimatedNodesManager alloc] initWithBridge:bridge]; + _nodesManager = [[RCTNativeAnimatedNodesManager alloc] initWithBridge:bridge surfacePresenter:bridge.surfacePresenter]; _displayLink = [RCTFakeDisplayLink new]; } From 75197dbb16606f2b50cb96dca6e0b91535ce4690 Mon Sep 17 00:00:00 2001 From: Peter Argany Date: Mon, 24 Aug 2020 16:34:58 -0700 Subject: [PATCH 0048/1238] Pass RCTSurfacePresenter into RCTNativeAnimatedNodesManager in bridgeless Summary: This diff ties the stack together. It completes the long chain of RCTSurfacePresenter ownership: `FBReactModule` -> `RCTNativeAnimatedTurboModule` (this diff and D23272746) `RCTNativeAnimatedTurboModule` -> `RCTNativeAnimatedNodesManager` (this diff) `RCTNativeAnimatedNodesManager` -> `RCTPropsAnimatedNode` (D23272735) It completes animations working without the bridge. Changelog: [Internal] Differential Revision: D23272755 fbshipit-source-id: 137f7ff89993a2cb644bd67869eb685afcec4068 --- Libraries/NativeAnimation/RCTNativeAnimatedModule.mm | 9 +++++++++ .../NativeAnimation/RCTNativeAnimatedTurboModule.mm | 11 +++++++++++ 2 files changed, 20 insertions(+) diff --git a/Libraries/NativeAnimation/RCTNativeAnimatedModule.mm b/Libraries/NativeAnimation/RCTNativeAnimatedModule.mm index 169c1ed6b234a8..35adf39289aa07 100644 --- a/Libraries/NativeAnimation/RCTNativeAnimatedModule.mm +++ b/Libraries/NativeAnimation/RCTNativeAnimatedModule.mm @@ -8,6 +8,7 @@ #import #import #import +#import #import @@ -68,6 +69,14 @@ - (void)setBridge:(RCTBridge *)bridge [bridge.surfacePresenter addObserver:self]; } +/* + * This selector should only be invoked in bridgeless mode, which is not compatible with this non turbo module. + */ +- (void)setSurfacePresenter:(id)surfacePresenter +{ + RCTLogWarn(@"setSurfacePresenter should only be invoked in RCTNativeAnimatedTurboModule"); +} + #pragma mark -- API RCT_EXPORT_METHOD(createAnimatedNode:(double)tag diff --git a/Libraries/NativeAnimation/RCTNativeAnimatedTurboModule.mm b/Libraries/NativeAnimation/RCTNativeAnimatedTurboModule.mm index 0c97901a069d76..6fc594872f874b 100644 --- a/Libraries/NativeAnimation/RCTNativeAnimatedTurboModule.mm +++ b/Libraries/NativeAnimation/RCTNativeAnimatedTurboModule.mm @@ -71,6 +71,17 @@ - (void)setBridge:(RCTBridge *)bridge [_surfacePresenter addObserver:self]; } +/* + * In bridgeless mode, `setBridge` is never called during initializtion. Instead this selector is invoked via + * BridgelessTurboModuleSetup. + */ +- (void)setSurfacePresenter:(id)surfacePresenter +{ + _surfacePresenter = surfacePresenter; + _nodesManager = [[RCTNativeAnimatedNodesManager alloc] initWithBridge:self.bridge surfacePresenter:_surfacePresenter]; + [_surfacePresenter addObserver:self]; +} + #pragma mark -- API RCT_EXPORT_METHOD(startOperationBatch) From 6d5849018753f188af0c9cc10a0948cc57cd6b3a Mon Sep 17 00:00:00 2001 From: Peter Argany Date: Mon, 24 Aug 2020 17:18:14 -0700 Subject: [PATCH 0049/1238] Fix RCTEventDispatcher Crash Summary: This crash was introduced in D22962320 (https://github.com/facebook/react-native/commit/ffdfbbec08b1afb1970d2cfe75a78a203d4a79a4), which landed 8/17 and went into 8/23 cut. I plan to pick this diff into that release. I can't repro this, but there must be a scenario (in bridged mode), where we try to flush event queue while bridge is tearing down. I plan to consider this scenario going forward. Changelog: [Internal] Reviewed By: JoshuaGross Differential Revision: D23306445 fbshipit-source-id: 285d4b94a17423c3b08d83e7041c4ee04b7e6d0c --- React/Base/RCTEventDispatcher.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/React/Base/RCTEventDispatcher.m b/React/Base/RCTEventDispatcher.m index 2930fa855ee62e..dfb613657600e8 100644 --- a/React/Base/RCTEventDispatcher.m +++ b/React/Base/RCTEventDispatcher.m @@ -179,7 +179,7 @@ - (void)sendEvent:(id)event [self flushEventsQueue]; } queue:RCTJSThread]; - } else { + } else if (_dispatchToJSThread) { _dispatchToJSThread(^{ [self flushEventsQueue]; }); From 03d69fce59d5e64536e879fa010f04f59d438de2 Mon Sep 17 00:00:00 2001 From: Stephy Ma Date: Mon, 24 Aug 2020 19:02:06 -0700 Subject: [PATCH 0050/1238] Revert D23292369: Remove State Reconciliation flags and dead code Differential Revision: D23292369 (https://github.com/facebook/react-native/commit/3cb78d5189665eaa07f4b407efdf06564cd45fd4) Original commit changeset: 6f00070495e9 fbshipit-source-id: 7e41f6fbdbdb1b833b16c5f3f5ece35a5d7adebe --- .../react/renderer/mounting/ShadowTree.cpp | 22 ++++- .../react/renderer/mounting/ShadowTree.h | 7 ++ .../mounting/TreeStateReconciliation.cpp | 94 +++++++++++++++++++ .../mounting/TreeStateReconciliation.h | 33 +++++++ .../react/renderer/scheduler/Scheduler.cpp | 6 ++ .../react/renderer/scheduler/Scheduler.h | 1 + 6 files changed, 158 insertions(+), 5 deletions(-) create mode 100644 ReactCommon/react/renderer/mounting/TreeStateReconciliation.cpp create mode 100644 ReactCommon/react/renderer/mounting/TreeStateReconciliation.h diff --git a/ReactCommon/react/renderer/mounting/ShadowTree.cpp b/ReactCommon/react/renderer/mounting/ShadowTree.cpp index 8224995a164aad..a0b5b2dc3c0644 100644 --- a/ReactCommon/react/renderer/mounting/ShadowTree.cpp +++ b/ReactCommon/react/renderer/mounting/ShadowTree.cpp @@ -17,6 +17,7 @@ #include #include "ShadowTreeDelegate.h" +#include "TreeStateReconciliation.h" namespace facebook { namespace react { @@ -302,11 +303,22 @@ bool ShadowTree::tryCommit( } if (enableStateReconciliation) { - auto updatedNewRootShadowNode = - progressState(*newRootShadowNode, *oldRootShadowNode); - if (updatedNewRootShadowNode) { - newRootShadowNode = - std::static_pointer_cast(updatedNewRootShadowNode); + if (enableNewStateReconciliation_) { + auto updatedNewRootShadowNode = + progressState(*newRootShadowNode, *oldRootShadowNode); + if (updatedNewRootShadowNode) { + newRootShadowNode = + std::static_pointer_cast(updatedNewRootShadowNode); + } + } else { + // Compare state revisions of old and new root + // Children of the root node may be mutated in-place + UnsharedShadowNode reconciledNode = + reconcileStateWithTree(newRootShadowNode.get(), oldRootShadowNode); + if (reconciledNode != nullptr) { + newRootShadowNode = std::make_shared( + *reconciledNode, ShadowNodeFragment{}); + } } } diff --git a/ReactCommon/react/renderer/mounting/ShadowTree.h b/ReactCommon/react/renderer/mounting/ShadowTree.h index 06e4e6c3e43c8c..70155de275f11d 100644 --- a/ReactCommon/react/renderer/mounting/ShadowTree.h +++ b/ReactCommon/react/renderer/mounting/ShadowTree.h @@ -81,6 +81,13 @@ class ShadowTree final { MountingCoordinator::Shared getMountingCoordinator() const; + /* + * Temporary. + * Do not use. + */ + void setEnableNewStateReconciliation(bool value) { + enableNewStateReconciliation_ = value; + } void setEnableReparentingDetection(bool value) { enableReparentingDetection_ = value; } diff --git a/ReactCommon/react/renderer/mounting/TreeStateReconciliation.cpp b/ReactCommon/react/renderer/mounting/TreeStateReconciliation.cpp new file mode 100644 index 00000000000000..58017f16a3c6c8 --- /dev/null +++ b/ReactCommon/react/renderer/mounting/TreeStateReconciliation.cpp @@ -0,0 +1,94 @@ +/* + * 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. + */ + +#include "TreeStateReconciliation.h" + +namespace facebook { +namespace react { + +using ChangedShadowNodePairs = + std::vector>; + +/** + * Clones any children in the subtree that need to be cloned, and adds those to + * the `changedPairs` vector argument. + */ +static ChangedShadowNodePairs reconcileStateWithChildren( + SharedShadowNodeList const &newChildren, + SharedShadowNodeList const &oldChildren) { + ChangedShadowNodePairs changedPairs; + // Find children that are the same family in both trees. + // We only want to find nodes that existing in the new tree - if they + // don't exist in the new tree, they're being deleted; if they don't exist + // in the old tree, they're new. We don't need to deal with either of those + // cases here. + // Currently we use a naive double loop - this could be improved, but we need + // to be able to handle cases where nodes are entirely reordered, for + // instance. + for (auto const &child : newChildren) { + auto const oldChild = std::find_if( + oldChildren.begin(), oldChildren.end(), [&](const auto &el) { + return ShadowNode::sameFamily(*child, *el); + }); + + if (oldChild != oldChildren.end()) { + UnsharedShadowNode newChild = + reconcileStateWithTree(child.get(), *oldChild); + if (newChild != nullptr) { + changedPairs.push_back(std::make_pair(child, newChild)); + } + } + }; + + return changedPairs; +} + +UnsharedShadowNode reconcileStateWithTree( + ShadowNode const *newNode, + SharedShadowNode committedNode) { + // If the revisions on the node are the same, we can finish here. + // Subtrees are guaranteed to be identical at this point, too. + if (committedNode->getStateRevision() <= newNode->getStateRevision()) { + return nullptr; + } + + // If we got this fair, we're guaranteed that the state of 1) this node, + // and/or 2) some descendant node is out-of-date and must be reconciled. + // This requires traversing all children, and we must at *least* clone + // this node, whether or not we clone and update any children. + auto const &newChildren = newNode->getChildren(); + auto const &oldChildren = committedNode->getChildren(); + auto const changedPairs = + reconcileStateWithChildren(newChildren, oldChildren); + + ShadowNode::SharedListOfShared clonedChildren = + ShadowNodeFragment::childrenPlaceholder(); + + // If any children were cloned, we need to recreate the child list. + // This won't cause any children to be cloned that weren't already cloned - + // it just collects all children, cloned or uncloned, into a new list. + if (!changedPairs.empty()) { + ShadowNode::UnsharedListOfShared newList = + std::make_shared(); + for (std::size_t i = 0, j = 0; i < newChildren.size(); ++i) { + if (j < changedPairs.size() && changedPairs[j].first == newChildren[i]) { + newList->push_back(changedPairs[j].second); + ++j; + } else { + newList->push_back(newChildren[i]); + } + } + clonedChildren = newList; + } + + return newNode->clone({/* .props = */ ShadowNodeFragment::propsPlaceholder(), + /* .children = */ clonedChildren, + /* .state = */ newNode->getMostRecentState()}); +} + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/react/renderer/mounting/TreeStateReconciliation.h b/ReactCommon/react/renderer/mounting/TreeStateReconciliation.h new file mode 100644 index 00000000000000..ff95b7e763d2c8 --- /dev/null +++ b/ReactCommon/react/renderer/mounting/TreeStateReconciliation.h @@ -0,0 +1,33 @@ +/* + * 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. + */ + +#include +#include + +namespace facebook { +namespace react { + +/** + * Problem Description: because of C++ State, the React Native C++ ShadowTree + * can diverge from the ReactJS ShadowTree; ReactJS communicates all tree + * changes to C++, but C++ state commits are not propagated to ReactJS (ReactJS + * may or may not clone nodes with state changes, but it has no way of knowing + * if it /should/ clone those nodes; so those clones may never happen). This + * causes a number of problems. This function resolves the problem by taking a + * candidate tree being committed, and sees if any State changes need to be + * applied to it. If any changes need to be made, a new ShadowNode is returned; + * otherwise, nullptr is returned if the node is already consistent with the + * latest tree, including all state changes. + * + * This should be called during the commit phase, pre-layout and pre-diff. + */ +UnsharedShadowNode reconcileStateWithTree( + ShadowNode const *newNode, + SharedShadowNode committedNode); + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/react/renderer/scheduler/Scheduler.cpp b/ReactCommon/react/renderer/scheduler/Scheduler.cpp index 39d733264a89e6..58128870bd0a7c 100644 --- a/ReactCommon/react/renderer/scheduler/Scheduler.cpp +++ b/ReactCommon/react/renderer/scheduler/Scheduler.cpp @@ -108,11 +108,15 @@ Scheduler::Scheduler( #ifdef ANDROID enableReparentingDetection_ = reactNativeConfig_->getBool( "react_fabric:enable_reparenting_detection_android"); + enableNewStateReconciliation_ = reactNativeConfig_->getBool( + "react_fabric:enable_new_state_reconciliation_android"); removeOutstandingSurfacesOnDestruction_ = reactNativeConfig_->getBool( "react_fabric:remove_outstanding_surfaces_on_destruction_android"); #else enableReparentingDetection_ = reactNativeConfig_->getBool( "react_fabric:enable_reparenting_detection_ios"); + enableNewStateReconciliation_ = reactNativeConfig_->getBool( + "react_fabric:enable_new_state_reconciliation_ios"); removeOutstandingSurfacesOnDestruction_ = reactNativeConfig_->getBool( "react_fabric:remove_outstanding_surfaces_on_destruction_ios"); #endif @@ -188,6 +192,8 @@ void Scheduler::startSurface( mountingOverrideDelegate, enableReparentingDetection_); + shadowTree->setEnableNewStateReconciliation(enableNewStateReconciliation_); + auto uiManager = uiManager_; uiManager->getShadowTreeRegistry().add(std::move(shadowTree)); diff --git a/ReactCommon/react/renderer/scheduler/Scheduler.h b/ReactCommon/react/renderer/scheduler/Scheduler.h index 3b5693cb724093..c025b39a3b98dd 100644 --- a/ReactCommon/react/renderer/scheduler/Scheduler.h +++ b/ReactCommon/react/renderer/scheduler/Scheduler.h @@ -138,6 +138,7 @@ class Scheduler final : public UIManagerDelegate { * Temporary flags. */ bool enableReparentingDetection_{false}; + bool enableNewStateReconciliation_{false}; bool removeOutstandingSurfacesOnDestruction_{false}; }; From 1afd9f0e31d460aa8a8d41e9c55b20d42e5af358 Mon Sep 17 00:00:00 2001 From: Joshua Gross Date: Mon, 24 Aug 2020 19:37:55 -0700 Subject: [PATCH 0051/1238] UpdateState MountItems should *always* update ViewManagers Summary: I'm removing an ill-informed "optimization" that resulted in some StateUpdates being dropped. For some components (including TextInput) we rely on State updates to request a layout from the ShadowNode layer. In the past we were performing an optimization that didn't update the View layer if the data contained in the State container is identical, but in the case of TextInput and other components, we simply pass an opaque object with no meaningful data to trigger the layouts. In those cases, it could cause a permanent rift between the View layer's StateWrapper and the most recent state object from the C++ perspective. In the case of TextInput this didn't cause tangible bugs because you can always update state using an out-of-date State object, but it's better this way anyway. The other issue is that for some components, we want to know when there's a State update from the Cxx layer. This optimization broke certain logic in those components. Changelog: [Internal] Reviewed By: mdvacca Differential Revision: D23306222 fbshipit-source-id: 8ef83149b814de50776674b5fd22406be1db14ba --- .../com/facebook/react/fabric/mounting/MountingManager.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountingManager.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountingManager.java index 0e951ed4db67ff..3e1a234246c9fc 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountingManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountingManager.java @@ -502,10 +502,7 @@ public void updateState(final int reactTag, @Nullable StateWrapper stateWrapper) UiThreadUtil.assertOnUiThread(); ViewState viewState = getViewState(reactTag); @Nullable ReadableNativeMap newState = stateWrapper == null ? null : stateWrapper.getState(); - if ((viewState.mCurrentState != null && viewState.mCurrentState.equals(newState)) - || (viewState.mCurrentState == null && stateWrapper == null)) { - return; - } + viewState.mCurrentState = newState; ViewManager viewManager = viewState.mViewManager; From 835f3677c33e2f70f6f423df849461ed6bc67218 Mon Sep 17 00:00:00 2001 From: "generatedunixname89002005287564@sandcastle995.atn2.facebook.com" Date: Tue, 25 Aug 2020 05:15:12 -0700 Subject: [PATCH 0052/1238] Daily `arc lint --take CLANGFORMAT` Reviewed By: zertosh Differential Revision: D23315866 fbshipit-source-id: 8f8e71596f483754cc5f5f5c1677dc2e4f7fd72b --- ReactCommon/react/renderer/mounting/StubViewTree.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ReactCommon/react/renderer/mounting/StubViewTree.cpp b/ReactCommon/react/renderer/mounting/StubViewTree.cpp index 1fc9ba9c748f6a..fc68777f349fda 100644 --- a/ReactCommon/react/renderer/mounting/StubViewTree.cpp +++ b/ReactCommon/react/renderer/mounting/StubViewTree.cpp @@ -117,8 +117,8 @@ void StubViewTree::mutate( strChildList.append(std::to_string(child->tag)); strChildList.append(", "); } - LOG(ERROR) << "StubView: BEFORE REMOVE: Children of " << parentTag << ": " - << strChildList; + LOG(ERROR) << "StubView: BEFORE REMOVE: Children of " << parentTag + << ": " << strChildList; }); STUB_VIEW_ASSERT(childIsCorrect); parentStubView->children.erase( From 9aabc8cdf0fd4da3b9bb77a3076d098d8c292f34 Mon Sep 17 00:00:00 2001 From: Samuel Susla Date: Tue, 25 Aug 2020 06:48:11 -0700 Subject: [PATCH 0053/1238] Use window size instead of screen size in BottomSheet Summary: Changelog: [internal] Reviewed By: shergin Differential Revision: D23294566 fbshipit-source-id: 1da67feff377a2f8c843b961ce3b381f6b16828b --- React/Base/RCTUtils.h | 1 + React/Base/RCTUtils.m | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/React/Base/RCTUtils.h b/React/Base/RCTUtils.h index 4bacc367254cdc..1270e471d28d57 100644 --- a/React/Base/RCTUtils.h +++ b/React/Base/RCTUtils.h @@ -44,6 +44,7 @@ RCT_EXTERN void RCTUnsafeExecuteOnMainQueueSync(dispatch_block_t block); RCT_EXTERN CGFloat RCTScreenScale(void); RCT_EXTERN CGFloat RCTFontSizeMultiplier(void); RCT_EXTERN CGSize RCTScreenSize(void); +RCT_EXTERN CGSize RCTViewportSize(void); // Round float coordinates to nearest whole screen pixel (not point) RCT_EXTERN CGFloat RCTRoundPixelValue(CGFloat value); diff --git a/React/Base/RCTUtils.m b/React/Base/RCTUtils.m index ea69a2edf9da51..13547d5852c697 100644 --- a/React/Base/RCTUtils.m +++ b/React/Base/RCTUtils.m @@ -345,6 +345,12 @@ CGSize RCTScreenSize() return size; } +CGSize RCTViewportSize() +{ + UIWindow *window = RCTKeyWindow(); + return window ? window.bounds.size : RCTScreenSize(); +} + CGFloat RCTRoundPixelValue(CGFloat value) { CGFloat scale = RCTScreenScale(); From 258387ddaa4d3f38f0bd71b67be8ba70d00daf33 Mon Sep 17 00:00:00 2001 From: Samuel Susla Date: Tue, 25 Aug 2020 06:48:11 -0700 Subject: [PATCH 0054/1238] Use window size instead of screen size in InputAccessoryView Summary: Changelog: [internal] Use window size instead of screen size to layout InputAccessoryView. Reviewed By: PeteTheHeat Differential Revision: D23297141 fbshipit-source-id: d6d7223342d17a2e1b9e5fca6f999b7ad365d056 --- .../RCTInputAccessoryComponentView.mm | 15 ++++++++------- .../InputAccessoryComponentDescriptor.h | 2 +- .../inputaccessory/InputAccessoryState.h | 4 ++-- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/React/Fabric/Mounting/ComponentViews/InputAccessory/RCTInputAccessoryComponentView.mm b/React/Fabric/Mounting/ComponentViews/InputAccessory/RCTInputAccessoryComponentView.mm index a403b45bd9d264..d151d1c0c3a421 100644 --- a/React/Fabric/Mounting/ComponentViews/InputAccessory/RCTInputAccessoryComponentView.mm +++ b/React/Fabric/Mounting/ComponentViews/InputAccessory/RCTInputAccessoryComponentView.mm @@ -10,6 +10,7 @@ #import #import #import +#import #import #import #import @@ -120,17 +121,17 @@ - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const & - (void)updateState:(State::Shared const &)state oldState:(State::Shared const &)oldState { _stateTeller.setConcreteState(state); - CGSize oldScreenSize = RCTCGSizeFromSize(_stateTeller.getData().value().screenSize); - CGSize screenSize = [[UIScreen mainScreen] bounds].size; - screenSize.height = std::nan(""); - if (oldScreenSize.width != screenSize.width) { - auto stateData = InputAccessoryState{RCTSizeFromCGSize(screenSize)}; + CGSize oldViewportSize = RCTCGSizeFromSize(_stateTeller.getData().value().viewportSize); + CGSize viewportSize = RCTViewportSize(); + viewportSize.height = std::nan(""); + if (oldViewportSize.width != viewportSize.width) { + auto stateData = InputAccessoryState{RCTSizeFromCGSize(viewportSize)}; _stateTeller.updateState(std::move(stateData)); } } -- (void)updateLayoutMetrics:(const facebook::react::LayoutMetrics &)layoutMetrics - oldLayoutMetrics:(const facebook::react::LayoutMetrics &)oldLayoutMetrics +- (void)updateLayoutMetrics:(LayoutMetrics const &)layoutMetrics + oldLayoutMetrics:(LayoutMetrics const &)oldLayoutMetrics { [super updateLayoutMetrics:layoutMetrics oldLayoutMetrics:oldLayoutMetrics]; diff --git a/ReactCommon/react/renderer/components/inputaccessory/InputAccessoryComponentDescriptor.h b/ReactCommon/react/renderer/components/inputaccessory/InputAccessoryComponentDescriptor.h index e92cf6e5bf94db..99898b2395bae8 100644 --- a/ReactCommon/react/renderer/components/inputaccessory/InputAccessoryComponentDescriptor.h +++ b/ReactCommon/react/renderer/components/inputaccessory/InputAccessoryComponentDescriptor.h @@ -37,7 +37,7 @@ class InputAccessoryComponentDescriptor final auto stateData = state->getData(); layoutableShadowNode->setSize( - Size{stateData.screenSize.width, stateData.screenSize.height}); + Size{stateData.viewportSize.width, stateData.viewportSize.height}); layoutableShadowNode->setPositionType(YGPositionTypeAbsolute); ConcreteComponentDescriptor::adopt(shadowNode); diff --git a/ReactCommon/react/renderer/components/inputaccessory/InputAccessoryState.h b/ReactCommon/react/renderer/components/inputaccessory/InputAccessoryState.h index 928bff3128e57c..24fe19b4e5dfc1 100644 --- a/ReactCommon/react/renderer/components/inputaccessory/InputAccessoryState.h +++ b/ReactCommon/react/renderer/components/inputaccessory/InputAccessoryState.h @@ -20,9 +20,9 @@ namespace react { class InputAccessoryState final { public: InputAccessoryState(){}; - InputAccessoryState(Size screenSize_) : screenSize(screenSize_){}; + InputAccessoryState(Size viewportSize_) : viewportSize(viewportSize_){}; - const Size screenSize{}; + const Size viewportSize{}; }; } // namespace react From b7afbb1fe23c1596e904213abc3ea8cee497a663 Mon Sep 17 00:00:00 2001 From: Samuel Susla Date: Tue, 25 Aug 2020 06:48:11 -0700 Subject: [PATCH 0055/1238] Use window size instead of screensize for maximum size Summary: Changelog: [Internal] This was set to screensize in D13104172 (https://github.com/facebook/react-native/commit/346c9d5f2c0fd99d6f05828d594d05bfaeed902f) to work around issues at that time. The issues might not be around anymore. Reviewed By: PeteTheHeat Differential Revision: D23298723 fbshipit-source-id: 4f33a2cc65ae4fe5ba20b0b2b270b135878c339f --- React/Fabric/Surface/RCTFabricSurface.mm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/React/Fabric/Surface/RCTFabricSurface.mm b/React/Fabric/Surface/RCTFabricSurface.mm index acfd0dbd8e5ae0..f8ea1c39faeea4 100644 --- a/React/Fabric/Surface/RCTFabricSurface.mm +++ b/React/Fabric/Surface/RCTFabricSurface.mm @@ -55,8 +55,8 @@ - (instancetype)initWithSurfacePresenter:(RCTSurfacePresenter *)surfacePresenter _rootTag = [RCTAllocateRootViewTag() integerValue]; _minimumSize = CGSizeZero; - // FIXME: Replace with `_maximumSize = CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX);`. - _maximumSize = RCTScreenSize(); + + _maximumSize = CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX); _touchHandler = [RCTSurfaceTouchHandler new]; From 4aa69e634d8ed784fea12138ee05d59139b3fc15 Mon Sep 17 00:00:00 2001 From: Jordan Brown Date: Tue, 25 Aug 2020 07:30:54 -0700 Subject: [PATCH 0056/1238] 0.132 for xplat Summary: Changelog: [Internal] 0.132 for xplat/js allow-large-files Reviewed By: mroch Differential Revision: D23298358 fbshipit-source-id: 0c75746c0cc2895f63ebc034df386217ffb64c61 --- .flowconfig | 2 +- .flowconfig.android | 2 +- Libraries/Utilities/ReactNativeTestTools.js | 3 +++ Libraries/vendor/emitter/_EmitterSubscription.js | 2 ++ index.js | 9 +++++++++ package.json | 1 + .../js/examples/PanResponder/PanResponderExample.js | 1 + repo-config/package.json | 2 +- template/_flowconfig | 2 +- yarn.lock | 8 ++++---- 10 files changed, 24 insertions(+), 8 deletions(-) diff --git a/.flowconfig b/.flowconfig index 9448358b32e2f7..6e5fef3567bdf2 100644 --- a/.flowconfig +++ b/.flowconfig @@ -79,4 +79,4 @@ untyped-import untyped-type-import [version] -^0.131.0 +^0.132.0 diff --git a/.flowconfig.android b/.flowconfig.android index 3dff9cb0c09d55..96869fca459db9 100644 --- a/.flowconfig.android +++ b/.flowconfig.android @@ -79,4 +79,4 @@ untyped-import untyped-type-import [version] -^0.131.0 +^0.132.0 diff --git a/Libraries/Utilities/ReactNativeTestTools.js b/Libraries/Utilities/ReactNativeTestTools.js index 2240656b434d23..ea4e583e38f7f9 100644 --- a/Libraries/Utilities/ReactNativeTestTools.js +++ b/Libraries/Utilities/ReactNativeTestTools.js @@ -23,6 +23,7 @@ const shallowRenderer = new ShallowRenderer(); import type {ReactTestRenderer as ReactTestRendererType} from 'react-test-renderer'; +// $FlowFixMe[value-as-type] export type ReactTestInstance = $PropertyType; export type Predicate = (node: ReactTestInstance) => boolean; @@ -93,6 +94,7 @@ function enter(instance: ReactTestInstance, text: string) { // Returns null if there is no error, otherwise returns an error message string. function maximumDepthError( + // $FlowFixMe[value-as-type] tree: ReactTestRendererType, maxDepthLimit: number, ): ?string { @@ -184,6 +186,7 @@ function renderAndEnforceStrictMode(element: React.Node): any { return renderWithStrictMode(element); } +// $FlowFixMe[value-as-type] function renderWithStrictMode(element: React.Node): ReactTestRendererType { const WorkAroundBugWithStrictModeInTestRenderer = prps => prps.children; const StrictMode = (React: $FlowFixMe).StrictMode; diff --git a/Libraries/vendor/emitter/_EmitterSubscription.js b/Libraries/vendor/emitter/_EmitterSubscription.js index 5a767c823dd9f6..dc2c72efb85c15 100644 --- a/Libraries/vendor/emitter/_EmitterSubscription.js +++ b/Libraries/vendor/emitter/_EmitterSubscription.js @@ -18,6 +18,7 @@ import type EventSubscriptionVendor from './_EventSubscriptionVendor'; * EmitterSubscription represents a subscription with listener and context data. */ class EmitterSubscription extends EventSubscription { + // $FlowFixMe[value-as-type] emitter: EventEmitter; listener: Function; context: ?Object; @@ -33,6 +34,7 @@ class EmitterSubscription extends EventSubscription { * listener */ constructor( + // $FlowFixMe[value-as-type] emitter: EventEmitter, subscriber: EventSubscriptionVendor, listener: Function, diff --git a/index.js b/index.js index 9d5a6dcb1458e5..dbac8b116b1a38 100644 --- a/index.js +++ b/index.js @@ -119,6 +119,7 @@ module.exports = { get Button(): Button { return require('./Libraries/Components/Button'); }, + // $FlowFixMe[value-as-type] get DatePickerIOS(): DatePickerIOS { warnOnce( 'DatePickerIOS-merged', @@ -128,6 +129,7 @@ module.exports = { ); return require('./Libraries/Components/DatePicker/DatePickerIOS'); }, + // $FlowFixMe[value-as-type] get DrawerLayoutAndroid(): DrawerLayoutAndroid { return require('./Libraries/Components/DrawerAndroid/DrawerLayoutAndroid'); }, @@ -167,6 +169,7 @@ module.exports = { ); return require('./Libraries/Components/Picker/Picker'); }, + // $FlowFixMe[value-as-type] get PickerIOS(): PickerIOS { warnOnce( 'pickerios-moved', @@ -179,6 +182,7 @@ module.exports = { get Pressable(): Pressable { return require('./Libraries/Components/Pressable/Pressable').default; }, + // $FlowFixMe[value-as-type] get ProgressBarAndroid(): ProgressBarAndroid { warnOnce( 'progress-bar-android-moved', @@ -188,6 +192,7 @@ module.exports = { ); return require('./Libraries/Components/ProgressBarAndroid/ProgressBarAndroid'); }, + // $FlowFixMe[value-as-type] get ProgressViewIOS(): ProgressViewIOS { warnOnce( 'progress-view-ios-moved', @@ -206,6 +211,7 @@ module.exports = { get SectionList(): SectionList { return require('./Libraries/Lists/SectionList'); }, + // $FlowFixMe[value-as-type] get SegmentedControlIOS(): SegmentedControlIOS { warnOnce( 'segmented-control-ios-moved', @@ -283,6 +289,7 @@ module.exports = { get AppState(): AppState { return require('./Libraries/AppState/AppState'); }, + // $FlowFixMe[value-as-type] get AsyncStorage(): AsyncStorage { warnOnce( 'async-storage-moved', @@ -403,6 +410,7 @@ module.exports = { get Systrace(): Systrace { return require('./Libraries/Performance/Systrace'); }, + // $FlowFixMe[value-as-type] get ToastAndroid(): ToastAndroid { return require('./Libraries/Components/ToastAndroid/ToastAndroid'); }, @@ -477,6 +485,7 @@ module.exports = { ); }, // Prop Types + // $FlowFixMe[value-as-type] get ColorPropType(): DeprecatedColorPropType { return require('./Libraries/DeprecatedPropTypes/DeprecatedColorPropType'); }, diff --git a/package.json b/package.json index 74d9cbaac332b6..f95f03006ccf99 100644 --- a/package.json +++ b/package.json @@ -119,6 +119,7 @@ "ws": "^6.1.4" }, "devDependencies": { + "flow-bin": "^0.132.0", "react": "16.13.1" }, "detox": { diff --git a/packages/rn-tester/js/examples/PanResponder/PanResponderExample.js b/packages/rn-tester/js/examples/PanResponder/PanResponderExample.js index a09b7387f9cc94..00f966b585d944 100644 --- a/packages/rn-tester/js/examples/PanResponder/PanResponderExample.js +++ b/packages/rn-tester/js/examples/PanResponder/PanResponderExample.js @@ -147,6 +147,7 @@ exports.simpleExampleContainer = true; exports.examples = [ { title: 'Basic gesture handling', + // $FlowFixMe[value-as-type] render: function(): React.Element { return ; }, diff --git a/repo-config/package.json b/repo-config/package.json index 16fdef134f6646..a258b2d1c32673 100644 --- a/repo-config/package.json +++ b/repo-config/package.json @@ -33,7 +33,7 @@ "eslint-plugin-react-hooks": "^4.0.7", "eslint-plugin-react-native": "3.8.1", "eslint-plugin-relay": "1.7.1", - "flow-bin": "^0.131.0", + "flow-bin": "^0.132.0", "jest": "^26.0.1", "jest-junit": "^10.0.0", "jscodeshift": "^0.9.0", diff --git a/template/_flowconfig b/template/_flowconfig index 00831ca070dd5a..569c6378fd6fe2 100644 --- a/template/_flowconfig +++ b/template/_flowconfig @@ -67,4 +67,4 @@ untyped-import untyped-type-import [version] -^0.131.0 +^0.132.0 diff --git a/yarn.lock b/yarn.lock index 8f632250127d47..f3f8342890bd62 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3261,10 +3261,10 @@ flatted@^2.0.0: resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138" integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA== -flow-bin@^0.131.0: - version "0.131.0" - resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.131.0.tgz#d4228b6070afdf3b2a76acdee77a7f3f8e8f5133" - integrity sha512-fZmoIBcDrtLhy/NNMxwJysSYzMr1ksRcAOMi3AHSoYXfcuQqTvhGJx+wqjlIOqIwz8RRYm8J4V4JrSJbIKP+Xg== +flow-bin@^0.132.0: + version "0.132.0" + resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.132.0.tgz#8bf80a79630db24bd1422dc2cc4b5e97f97ccb98" + integrity sha512-S1g/vnAyNaLUdajmuUHCMl30qqye12gS6mr4LVyswf1k+JDF4efs6SfKmptuvnpitF3LGCVf0TIffChP8ljwnw== flow-parser@0.*: version "0.89.0" From 301e149f97abf902b03c8a3231a057653e9abfb3 Mon Sep 17 00:00:00 2001 From: Kevin Gozali Date: Tue, 25 Aug 2020 10:34:41 -0700 Subject: [PATCH 0057/1238] Codegen: JavaGenerator [4] - collect all parsed types in a flat list of "TypeData" Summary: Instead of recreating the schema structure, the generator only needs to collect the list of types that it needs to generate for. So instead, let's just add each parsed type into a map using TypeId as the key. This means every inner types in the schema needs its own unique TypeId. This was a change from the previous commit where we didn't assign unique names to the types. Here's the reasoning: * In Java, any generated class needs to be in its own file. * If a NativeModule spec defines a few aliases, and or inner types (function args, return type shape, etc) that needs representation with a dedicated class, we need to track them as well for code generation. * This means, the schema format is no longer relevant for the code generation step, so let's produce a structure that's more efficient for code generation Changelog: [Internal] Reviewed By: mdvacca Differential Revision: D23287818 fbshipit-source-id: 7caf4e95aeafe5c8ba336af290179b85bf87ad6d --- .../codegen/generator/JavaGenerator.java | 6 +- .../codegen/generator/SchemaJsonParser.java | 167 +++++++++--------- .../codegen/generator/model/RawSchema.java | 26 --- .../codegen/generator/model/TypeData.java | 43 +++++ .../react/codegen/generator/model/TypeId.java | 4 + 5 files changed, 137 insertions(+), 109 deletions(-) delete mode 100644 packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/model/RawSchema.java create mode 100644 packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/model/TypeData.java diff --git a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/JavaGenerator.java b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/JavaGenerator.java index 2ad0aa51cd0175..2f15f43ceda859 100644 --- a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/JavaGenerator.java +++ b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/JavaGenerator.java @@ -7,7 +7,7 @@ package com.facebook.react.codegen.generator; -import com.facebook.react.codegen.generator.model.RawSchema; +import com.facebook.react.codegen.generator.model.TypeData; import com.squareup.javapoet.JavaFile; import com.squareup.javapoet.MethodSpec; import com.squareup.javapoet.TypeSpec; @@ -29,9 +29,7 @@ public JavaGenerator(final File schemaFile, final String javaPackageName, final } public void build() throws FileNotFoundException, IOException { - final RawSchema rawSchema = SchemaJsonParser.parse(mSchemaFile); - // TODO (T71663018): remove - this is for debugging - System.out.println(rawSchema); + TypeData typeData = SchemaJsonParser.parse(mSchemaFile); final MethodSpec main = MethodSpec.methodBuilder("main") diff --git a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/SchemaJsonParser.java b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/SchemaJsonParser.java index fa9c67352c932e..b8deb6ed48b1bd 100644 --- a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/SchemaJsonParser.java +++ b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/SchemaJsonParser.java @@ -21,12 +21,13 @@ import com.facebook.react.codegen.generator.model.NumberType; import com.facebook.react.codegen.generator.model.ObjectType; import com.facebook.react.codegen.generator.model.PromiseType; -import com.facebook.react.codegen.generator.model.RawSchema; import com.facebook.react.codegen.generator.model.ReservedFunctionValueType; import com.facebook.react.codegen.generator.model.StringType; import com.facebook.react.codegen.generator.model.Type; +import com.facebook.react.codegen.generator.model.TypeData; import com.facebook.react.codegen.generator.model.TypeId; import com.facebook.react.codegen.generator.model.VoidType; +import com.google.common.base.CaseFormat; import com.google.common.collect.ImmutableList; import com.google.gson.JsonArray; import com.google.gson.JsonElement; @@ -41,8 +42,16 @@ import java.util.stream.Collectors; public final class SchemaJsonParser { + private final TypeData mTypeData = new TypeData(); - public static RawSchema parse(final File schemaFile) throws FileNotFoundException, IOException { + public static TypeData parse(final File schemaFile) throws FileNotFoundException, IOException { + final SchemaJsonParser parser = new SchemaJsonParser(); + parser.buildTypeData(schemaFile); + System.out.println(parser.mTypeData); + return parser.mTypeData; + } + + private void buildTypeData(final File schemaFile) throws FileNotFoundException, IOException { final JsonParser parser = new JsonParser(); final JsonElement rootElement = parser.parse(new FileReader(schemaFile)); @@ -63,62 +72,25 @@ public static RawSchema parse(final File schemaFile) throws FileNotFoundExceptio return; } - collection.put( - jsModuleName, - nativeModules.entrySet().stream() - .collect( - Collectors.toMap( - Map.Entry::getKey, - e -> { - return parseNativeModule( - // TODO (T71955395): NativeModule spec type name does not - // exist in the schema. For now assume it's "Spec". - TypeId.of(jsModuleName, "Spec"), - e.getValue().getAsJsonObject()); - }))); + nativeModules + .entrySet() + .forEach( + e -> { + final Type parsedType = + parseNativeModule( + // TODO (T71955395): NativeModule spec type name does not + // exist in the schema. For now assume it's "Spec". + // The final type name will be the output class name. + TypeId.of(jsModuleName, "Native" + e.getKey() + "Spec"), + e.getValue().getAsJsonObject()); + mTypeData.addType(parsedType); + }); }); } - - return new RawSchema(collection); - } - - private static NativeModuleType parseNativeModule(final TypeId typeId, final JsonObject json) { - final JsonObject aliases = json.getAsJsonObject("aliases"); - final JsonArray properties = json.getAsJsonArray("properties"); - - final ImmutableList collectedAliases = - ImmutableList.copyOf( - aliases.entrySet().stream() - .map( - entry -> { - final String typeName = entry.getKey(); - final JsonObject typeAnnotation = entry.getValue().getAsJsonObject(); - // The alias name is the type name that other types can refer to. - return parseTypeAnnotation( - TypeId.of(typeId.moduleName, typeName), typeAnnotation); - }) - .collect(Collectors.toList())); - - ImmutableList.Builder collectedPropertiesBuilder = - new ImmutableList.Builder<>(); - properties.forEach( - p -> { - final JsonObject node = p.getAsJsonObject(); - final String name = node.has("name") ? node.get("name").getAsString() : null; - final JsonObject typeAnnotation = node.getAsJsonObject("typeAnnotation"); - // TODO (T71845349): "optional" field shouldn't be part of the Function's typeAnnotation. - final boolean optional = typeAnnotation.get("optional").getAsBoolean(); - final TypeId propertyTypeId = TypeId.of(typeId.moduleName); - collectedPropertiesBuilder.add( - new NativeModuleType.Property( - name, parseTypeAnnotation(propertyTypeId, typeAnnotation), optional)); - }); - - return new NativeModuleType(typeId, collectedAliases, collectedPropertiesBuilder.build()); } // Parse type information from a JSON "typeAnnotation" node. - private static Type parseTypeAnnotation(final TypeId typeId, final JsonObject typeAnnotation) + private Type parseTypeAnnotation(final TypeId typeId, final JsonObject typeAnnotation) throws IllegalStateException { final String type = typeAnnotation.get("type").getAsString(); // TODO (T71824250): Support NullableTypeAnnotation in the schema instead of a field here. @@ -176,60 +148,96 @@ private static Type parseTypeAnnotation(final TypeId typeId, final JsonObject ty throw new IllegalStateException("Found invalid type annotation: " + type); } - return maybeCreateNullableType(nullable, parsedType); + final Type finalType = maybeCreateNullableType(nullable, parsedType); + mTypeData.addType(finalType); + return finalType; } - private static Type parseAliasTypeAnnotation( - final TypeId typeId, final JsonObject typeAnnotation) { + private NativeModuleType parseNativeModule(final TypeId typeId, final JsonObject json) { + final JsonObject aliases = json.getAsJsonObject("aliases"); + final JsonArray properties = json.getAsJsonArray("properties"); + + final ImmutableList collectedAliases = + ImmutableList.copyOf( + aliases.entrySet().stream() + .map( + entry -> { + final String typeName = entry.getKey(); + final JsonObject typeAnnotation = entry.getValue().getAsJsonObject(); + // The alias name is the type name that other types can refer to. + return parseTypeAnnotation( + TypeId.of(typeId.moduleName, typeName), typeAnnotation); + }) + .collect(Collectors.toList())); + + ImmutableList.Builder collectedPropertiesBuilder = + new ImmutableList.Builder<>(); + properties.forEach( + p -> { + final JsonObject node = p.getAsJsonObject(); + final String name = node.has("name") ? node.get("name").getAsString() : null; + final JsonObject typeAnnotation = node.getAsJsonObject("typeAnnotation"); + // TODO (T71845349): "optional" field shouldn't be part of the Function's typeAnnotation. + final boolean optional = typeAnnotation.get("optional").getAsBoolean(); + final TypeId propertyTypeId = + TypeId.expandOf(typeId, CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_CAMEL, name)); + collectedPropertiesBuilder.add( + new NativeModuleType.Property( + name, parseTypeAnnotation(propertyTypeId, typeAnnotation), optional)); + }); + + return new NativeModuleType(typeId, collectedAliases, collectedPropertiesBuilder.build()); + } + + private Type parseAliasTypeAnnotation(final TypeId typeId, final JsonObject typeAnnotation) { // For now, assume the alias lives inside the same file. return new AliasType( typeId, TypeId.of(typeId.moduleName, typeAnnotation.get("name").getAsString())); } - private static Type parseArrayTypeAnnotation( - final TypeId typeId, final JsonObject typeAnnotation) { + private Type parseArrayTypeAnnotation(final TypeId typeId, final JsonObject typeAnnotation) { final JsonObject elementTypeAnnotation = typeAnnotation.getAsJsonObject("elementType"); + final TypeId elementTypeId = TypeId.expandOf(typeId, "ElementType"); // TODO (T71847026): Some array types are missing elementType annotation. final Type elementType = elementTypeAnnotation != null - ? parseTypeAnnotation(TypeId.of(typeId.moduleName), elementTypeAnnotation) - : new AnyType(TypeId.of(typeId.moduleName)); - + ? parseTypeAnnotation(elementTypeId, elementTypeAnnotation) + : new AnyType(elementTypeId); return new ArrayType(typeId, elementType); } - private static Type parseFunctionTypeAnnotation( - final TypeId typeId, final JsonObject typeAnnotation) { + private Type parseFunctionTypeAnnotation(final TypeId typeId, final JsonObject typeAnnotation) { final JsonArray params = typeAnnotation.getAsJsonArray("params"); ImmutableList.Builder paramsList = new ImmutableList.Builder<>(); // TODO (T71846321): Some functions are missing params specification. if (params != null) { - params.forEach( - p -> { - final JsonObject node = p.getAsJsonObject(); - final String name = node.has("name") ? node.get("name").getAsString() : null; - paramsList.add( - FunctionType.createArgument( - name, - parseTypeAnnotation( - TypeId.of(typeId.moduleName), node.getAsJsonObject("typeAnnotation")))); - }); + for (int i = 0; i < params.size(); i++) { + final JsonElement p = params.get(i); + final JsonObject node = p.getAsJsonObject(); + final String name = node.has("name") ? node.get("name").getAsString() : ("Arg" + i); + paramsList.add( + FunctionType.createArgument( + name, + parseTypeAnnotation( + TypeId.expandOf( + typeId, CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_CAMEL, name)), + node.getAsJsonObject("typeAnnotation")))); + } } // TODO (T71846321): Some functions are missing a return type. final JsonObject returnTypeAnnotation = typeAnnotation.getAsJsonObject("returnTypeAnnotation"); final Type returnType = returnTypeAnnotation != null - ? parseTypeAnnotation(TypeId.of(typeId.moduleName), returnTypeAnnotation) + ? parseTypeAnnotation(TypeId.expandOf(typeId, "ReturnType"), returnTypeAnnotation) : VoidType.VOID; return new FunctionType(typeId, paramsList.build(), returnType); } - private static Type parseObjectTypeAnnotation( - final TypeId typeId, final JsonObject typeAnnotation) { + private Type parseObjectTypeAnnotation(final TypeId typeId, final JsonObject typeAnnotation) { final JsonArray properties = typeAnnotation.getAsJsonArray("properties"); ImmutableList.Builder propertiesList = new ImmutableList.Builder<>(); @@ -239,7 +247,8 @@ private static Type parseObjectTypeAnnotation( final String name = node.has("name") ? node.get("name").getAsString() : null; final boolean optional = node.get("optional").getAsBoolean(); final JsonObject propertyTypeAnnotation = node.getAsJsonObject("typeAnnotation"); - final TypeId propertyTypeId = TypeId.of(typeId.moduleName); + final TypeId propertyTypeId = + TypeId.expandOf(typeId, CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_CAMEL, name)); // TODO (T67898313): Some object properties are missing typeAnnotation. final Type propertyType = @@ -253,14 +262,14 @@ private static Type parseObjectTypeAnnotation( return new ObjectType(typeId, propertiesList.build()); } - private static Type parseReservedFunctionValueTypeAnnotation( + private Type parseReservedFunctionValueTypeAnnotation( final TypeId typeId, final JsonObject typeAnnotation) { return new ReservedFunctionValueType( typeId, ReservedFunctionValueType.ReservedName.valueOf(typeAnnotation.get("name").getAsString())); } - private static Type maybeCreateNullableType(final boolean nullable, final Type original) { + private Type maybeCreateNullableType(final boolean nullable, final Type original) { if (!nullable || original instanceof VoidType) { return original; } diff --git a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/model/RawSchema.java b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/model/RawSchema.java deleted file mode 100644 index 969164e4a56a0e..00000000000000 --- a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/model/RawSchema.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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 com.facebook.react.codegen.generator.model; - -import java.util.Collections; -import java.util.Map; - -/** Represents the parsed JSON schema without any type resolution. */ -public final class RawSchema { - - public final Map> modules; - - public RawSchema(final Map> modules) { - this.modules = Collections.unmodifiableMap(modules); - } - - @Override - public String toString() { - return modules.toString(); - } -} diff --git a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/model/TypeData.java b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/model/TypeData.java new file mode 100644 index 00000000000000..1b19bfee0a58d8 --- /dev/null +++ b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/model/TypeData.java @@ -0,0 +1,43 @@ +/* + * 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 com.facebook.react.codegen.generator.model; + +import java.util.HashMap; +import java.util.Map; +import javax.annotation.Nullable; + +/** A collection of all types information based on the parsed schema. */ +public final class TypeData { + private final Map mTypes = new HashMap<>(); + + public void addType(final TypeId typeId, final Type type) throws IllegalStateException { + if (getType(typeId) != null) { + throw new IllegalStateException("Found duplicated TypeId: " + typeId + " for: " + type); + } + mTypes.put(typeId, type); + } + + public void addType(final Type type) { + addType(type.getTypeId(), type); + } + + public @Nullable Type getType(final TypeId typeId) { + return mTypes.get(typeId); + } + + @Override + public String toString() { + final StringBuilder builder = new StringBuilder(); + mTypes.forEach( + (k, v) -> { + builder.append(v.toString()); + builder.append("\n"); + }); + return builder.toString(); + } +} diff --git a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/model/TypeId.java b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/model/TypeId.java index a8c5208c02de1f..ef9831c5256281 100644 --- a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/model/TypeId.java +++ b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/model/TypeId.java @@ -42,6 +42,10 @@ public static TypeId of(final TypeId typeId) { return of(typeId.moduleName, typeId.typeName); } + public static TypeId expandOf(final TypeId typeId, String suffix) { + return of(typeId.moduleName, typeId.typeName + suffix); + } + @Override public String toString() { return String.format( From eda1f8da7b2be1513ba00202a5e769b9e8e61e9a Mon Sep 17 00:00:00 2001 From: Kevin Gozali Date: Tue, 25 Aug 2020 10:34:41 -0700 Subject: [PATCH 0058/1238] Codegen: JavaGenerator [5] - Introduced ResolvedType structure that knows how to generate code for itself Summary: This is the base setup for ResolvedType. Each Type needs to be resolved to its final representation, which knows what Java type it needs, and what standalone Java code (e.g. class) it needs to produce. Individual resolved types are not yet implemented, this commit provides the flow to pass the parsed structure (from schema) to the resolution logic. Changelog: [Internal] Reviewed By: mdvacca Differential Revision: D23288208 fbshipit-source-id: 18535d5fae8ca15f6d9374bdba38f57dfd4300e8 --- .../codegen/generator/JavaGenerator.java | 8 ++ .../codegen/generator/SchemaJsonParser.java | 8 +- .../codegen/generator/model/TypeData.java | 5 + .../generator/resolver/AliasResolvedType.java | 38 ++++++++ .../generator/resolver/AnyResolvedType.java | 38 ++++++++ .../generator/resolver/ArrayResolvedType.java | 38 ++++++++ .../resolver/BooleanResolvedType.java | 38 ++++++++ .../resolver/FunctionResolvedType.java | 38 ++++++++ .../resolver/GenericObjectResolvedType.java | 38 ++++++++ .../resolver/NativeModuleResolvedType.java | 38 ++++++++ .../resolver/NullableResolvedType.java | 38 ++++++++ .../resolver/NumberResolvedType.java | 38 ++++++++ .../resolver/ObjectResolvedType.java | 38 ++++++++ .../resolver/PromiseResolvedType.java | 38 ++++++++ .../ReservedFunctionValueResolvedType.java | 40 ++++++++ .../generator/resolver/ResolvedType.java | 52 +++++++++++ .../resolver/StringResolvedType.java | 38 ++++++++ .../generator/resolver/TypeResolver.java | 91 +++++++++++++++++++ .../generator/resolver/VoidResolvedType.java | 38 ++++++++ 19 files changed, 694 insertions(+), 4 deletions(-) create mode 100644 packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/AliasResolvedType.java create mode 100644 packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/AnyResolvedType.java create mode 100644 packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/ArrayResolvedType.java create mode 100644 packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/BooleanResolvedType.java create mode 100644 packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/FunctionResolvedType.java create mode 100644 packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/GenericObjectResolvedType.java create mode 100644 packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/NativeModuleResolvedType.java create mode 100644 packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/NullableResolvedType.java create mode 100644 packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/NumberResolvedType.java create mode 100644 packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/ObjectResolvedType.java create mode 100644 packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/PromiseResolvedType.java create mode 100644 packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/ReservedFunctionValueResolvedType.java create mode 100644 packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/ResolvedType.java create mode 100644 packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/StringResolvedType.java create mode 100644 packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/TypeResolver.java create mode 100644 packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/VoidResolvedType.java diff --git a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/JavaGenerator.java b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/JavaGenerator.java index 2f15f43ceda859..d6f759e01dddf2 100644 --- a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/JavaGenerator.java +++ b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/JavaGenerator.java @@ -8,6 +8,7 @@ package com.facebook.react.codegen.generator; import com.facebook.react.codegen.generator.model.TypeData; +import com.facebook.react.codegen.generator.resolver.TypeResolver; import com.squareup.javapoet.JavaFile; import com.squareup.javapoet.MethodSpec; import com.squareup.javapoet.TypeSpec; @@ -30,6 +31,13 @@ public JavaGenerator(final File schemaFile, final String javaPackageName, final public void build() throws FileNotFoundException, IOException { TypeData typeData = SchemaJsonParser.parse(mSchemaFile); + typeData + .getAllTypes() + .forEach( + t -> { + // TODO: Ask each resolved type to produce its own code if it supports it. + TypeResolver.resolveType(typeData.getType(t), typeData, false); + }); final MethodSpec main = MethodSpec.methodBuilder("main") diff --git a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/SchemaJsonParser.java b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/SchemaJsonParser.java index b8deb6ed48b1bd..45d254cd16d6a2 100644 --- a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/SchemaJsonParser.java +++ b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/SchemaJsonParser.java @@ -46,12 +46,10 @@ public final class SchemaJsonParser { public static TypeData parse(final File schemaFile) throws FileNotFoundException, IOException { final SchemaJsonParser parser = new SchemaJsonParser(); - parser.buildTypeData(schemaFile); - System.out.println(parser.mTypeData); - return parser.mTypeData; + return parser.buildTypeData(schemaFile); } - private void buildTypeData(final File schemaFile) throws FileNotFoundException, IOException { + private TypeData buildTypeData(final File schemaFile) throws FileNotFoundException, IOException { final JsonParser parser = new JsonParser(); final JsonElement rootElement = parser.parse(new FileReader(schemaFile)); @@ -87,6 +85,8 @@ private void buildTypeData(final File schemaFile) throws FileNotFoundException, }); }); } + + return mTypeData; } // Parse type information from a JSON "typeAnnotation" node. diff --git a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/model/TypeData.java b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/model/TypeData.java index 1b19bfee0a58d8..91a58f51062f71 100644 --- a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/model/TypeData.java +++ b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/model/TypeData.java @@ -9,6 +9,7 @@ import java.util.HashMap; import java.util.Map; +import java.util.Set; import javax.annotation.Nullable; /** A collection of all types information based on the parsed schema. */ @@ -30,6 +31,10 @@ public void addType(final Type type) { return mTypes.get(typeId); } + public Set getAllTypes() { + return mTypes.keySet(); + } + @Override public String toString() { final StringBuilder builder = new StringBuilder(); diff --git a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/AliasResolvedType.java b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/AliasResolvedType.java new file mode 100644 index 00000000000000..2f6d3d5bbd05a5 --- /dev/null +++ b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/AliasResolvedType.java @@ -0,0 +1,38 @@ +/* + * 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 com.facebook.react.codegen.generator.resolver; + +import com.facebook.react.codegen.generator.model.AliasType; +import com.facebook.react.codegen.generator.model.TypeData; +import com.squareup.javapoet.TypeName; +import com.squareup.javapoet.TypeSpec; +import javax.annotation.Nullable; + +public final class AliasResolvedType extends ResolvedType { + + private AliasResolvedType(final AliasType type, final boolean nullable) { + super(type, nullable); + } + + public static AliasResolvedType create( + final AliasType type, final TypeData typeData, final boolean nullable) { + return new AliasResolvedType(type, nullable); + } + + @Override + public TypeName getNativeType(final NativeTypeContext typeContext) { + // TODO + return TypeName.VOID; + } + + @Override + public @Nullable TypeSpec getGeneratedCode(final String packageName) { + // TODO + throw new UnsupportedOperationException(); + } +} diff --git a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/AnyResolvedType.java b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/AnyResolvedType.java new file mode 100644 index 00000000000000..203cd1150bdf40 --- /dev/null +++ b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/AnyResolvedType.java @@ -0,0 +1,38 @@ +/* + * 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 com.facebook.react.codegen.generator.resolver; + +import com.facebook.react.codegen.generator.model.AnyType; +import com.facebook.react.codegen.generator.model.TypeData; +import com.squareup.javapoet.TypeName; +import com.squareup.javapoet.TypeSpec; +import javax.annotation.Nullable; + +public final class AnyResolvedType extends ResolvedType { + + private AnyResolvedType(final AnyType type, final boolean nullable) { + super(type, nullable); + } + + public static AnyResolvedType create( + final AnyType type, final TypeData typeData, final boolean nullable) { + return new AnyResolvedType(type, nullable); + } + + @Override + public TypeName getNativeType(final NativeTypeContext typeContext) { + // TODO + return TypeName.VOID; + } + + @Override + public @Nullable TypeSpec getGeneratedCode(final String packageName) { + // TODO + throw new UnsupportedOperationException(); + } +} diff --git a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/ArrayResolvedType.java b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/ArrayResolvedType.java new file mode 100644 index 00000000000000..e6d08108dd5681 --- /dev/null +++ b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/ArrayResolvedType.java @@ -0,0 +1,38 @@ +/* + * 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 com.facebook.react.codegen.generator.resolver; + +import com.facebook.react.codegen.generator.model.ArrayType; +import com.facebook.react.codegen.generator.model.TypeData; +import com.squareup.javapoet.TypeName; +import com.squareup.javapoet.TypeSpec; +import javax.annotation.Nullable; + +public final class ArrayResolvedType extends ResolvedType { + + private ArrayResolvedType(final ArrayType type, final boolean nullable) { + super(type, nullable); + } + + public static ArrayResolvedType create( + final ArrayType type, final TypeData typeData, final boolean nullable) { + return new ArrayResolvedType(type, nullable); + } + + @Override + public TypeName getNativeType(final NativeTypeContext typeContext) { + // TODO + return TypeName.VOID; + } + + @Override + public @Nullable TypeSpec getGeneratedCode(final String packageName) { + // TODO + throw new UnsupportedOperationException(); + } +} diff --git a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/BooleanResolvedType.java b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/BooleanResolvedType.java new file mode 100644 index 00000000000000..48cc67dc280421 --- /dev/null +++ b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/BooleanResolvedType.java @@ -0,0 +1,38 @@ +/* + * 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 com.facebook.react.codegen.generator.resolver; + +import com.facebook.react.codegen.generator.model.BooleanType; +import com.facebook.react.codegen.generator.model.TypeData; +import com.squareup.javapoet.TypeName; +import com.squareup.javapoet.TypeSpec; +import javax.annotation.Nullable; + +public final class BooleanResolvedType extends ResolvedType { + + private BooleanResolvedType(final BooleanType type, final boolean nullable) { + super(type, nullable); + } + + public static BooleanResolvedType create( + final BooleanType type, final TypeData typeData, final boolean nullable) { + return new BooleanResolvedType(type, nullable); + } + + @Override + public TypeName getNativeType(final NativeTypeContext typeContext) { + // TODO + return TypeName.VOID; + } + + @Override + public @Nullable TypeSpec getGeneratedCode(final String packageName) { + // TODO + throw new UnsupportedOperationException(); + } +} diff --git a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/FunctionResolvedType.java b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/FunctionResolvedType.java new file mode 100644 index 00000000000000..19d0dde4637bd8 --- /dev/null +++ b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/FunctionResolvedType.java @@ -0,0 +1,38 @@ +/* + * 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 com.facebook.react.codegen.generator.resolver; + +import com.facebook.react.codegen.generator.model.FunctionType; +import com.facebook.react.codegen.generator.model.TypeData; +import com.squareup.javapoet.TypeName; +import com.squareup.javapoet.TypeSpec; +import javax.annotation.Nullable; + +public final class FunctionResolvedType extends ResolvedType { + + private FunctionResolvedType(final FunctionType type, final boolean nullable) { + super(type, nullable); + } + + public static FunctionResolvedType create( + final FunctionType type, final TypeData typeData, final boolean nullable) { + return new FunctionResolvedType(type, nullable); + } + + @Override + public TypeName getNativeType(final NativeTypeContext typeContext) { + // TODO + return TypeName.VOID; + } + + @Override + public @Nullable TypeSpec getGeneratedCode(final String packageName) { + // TODO + throw new UnsupportedOperationException(); + } +} diff --git a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/GenericObjectResolvedType.java b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/GenericObjectResolvedType.java new file mode 100644 index 00000000000000..c2dd163540282e --- /dev/null +++ b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/GenericObjectResolvedType.java @@ -0,0 +1,38 @@ +/* + * 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 com.facebook.react.codegen.generator.resolver; + +import com.facebook.react.codegen.generator.model.GenericObjectType; +import com.facebook.react.codegen.generator.model.TypeData; +import com.squareup.javapoet.TypeName; +import com.squareup.javapoet.TypeSpec; +import javax.annotation.Nullable; + +public final class GenericObjectResolvedType extends ResolvedType { + + private GenericObjectResolvedType(final GenericObjectType type, final boolean nullable) { + super(type, nullable); + } + + public static GenericObjectResolvedType create( + final GenericObjectType type, final TypeData typeData, final boolean nullable) { + return new GenericObjectResolvedType(type, nullable); + } + + @Override + public TypeName getNativeType(final NativeTypeContext typeContext) { + // TODO + return TypeName.VOID; + } + + @Override + public @Nullable TypeSpec getGeneratedCode(final String packageName) { + // TODO + throw new UnsupportedOperationException(); + } +} diff --git a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/NativeModuleResolvedType.java b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/NativeModuleResolvedType.java new file mode 100644 index 00000000000000..15ffde5d197412 --- /dev/null +++ b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/NativeModuleResolvedType.java @@ -0,0 +1,38 @@ +/* + * 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 com.facebook.react.codegen.generator.resolver; + +import com.facebook.react.codegen.generator.model.NativeModuleType; +import com.facebook.react.codegen.generator.model.TypeData; +import com.squareup.javapoet.TypeName; +import com.squareup.javapoet.TypeSpec; +import javax.annotation.Nullable; + +public final class NativeModuleResolvedType extends ResolvedType { + + private NativeModuleResolvedType(final NativeModuleType type, final boolean nullable) { + super(type, nullable); + } + + public static NativeModuleResolvedType create( + final NativeModuleType type, final TypeData typeData, final boolean nullable) { + return new NativeModuleResolvedType(type, nullable); + } + + @Override + public TypeName getNativeType(final NativeTypeContext typeContext) { + // TODO + return TypeName.VOID; + } + + @Override + public @Nullable TypeSpec getGeneratedCode(final String packageName) { + // TODO + throw new UnsupportedOperationException(); + } +} diff --git a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/NullableResolvedType.java b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/NullableResolvedType.java new file mode 100644 index 00000000000000..0ffe587ade2d70 --- /dev/null +++ b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/NullableResolvedType.java @@ -0,0 +1,38 @@ +/* + * 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 com.facebook.react.codegen.generator.resolver; + +import com.facebook.react.codegen.generator.model.NullableType; +import com.facebook.react.codegen.generator.model.TypeData; +import com.squareup.javapoet.TypeName; +import com.squareup.javapoet.TypeSpec; +import javax.annotation.Nullable; + +public final class NullableResolvedType extends ResolvedType { + + private NullableResolvedType(final NullableType type, final boolean nullable) { + super(type, nullable); + } + + public static NullableResolvedType create( + final NullableType type, final TypeData typeData, final boolean nullable) { + return new NullableResolvedType(type, nullable); + } + + @Override + public TypeName getNativeType(final NativeTypeContext typeContext) { + // TODO + return TypeName.VOID; + } + + @Override + public @Nullable TypeSpec getGeneratedCode(final String packageName) { + // TODO + throw new UnsupportedOperationException(); + } +} diff --git a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/NumberResolvedType.java b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/NumberResolvedType.java new file mode 100644 index 00000000000000..8b241ddeed7435 --- /dev/null +++ b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/NumberResolvedType.java @@ -0,0 +1,38 @@ +/* + * 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 com.facebook.react.codegen.generator.resolver; + +import com.facebook.react.codegen.generator.model.NumberType; +import com.facebook.react.codegen.generator.model.TypeData; +import com.squareup.javapoet.TypeName; +import com.squareup.javapoet.TypeSpec; +import javax.annotation.Nullable; + +public final class NumberResolvedType extends ResolvedType { + + private NumberResolvedType(final NumberType type, final boolean nullable) { + super(type, nullable); + } + + public static NumberResolvedType create( + final NumberType type, final TypeData typeData, final boolean nullable) { + return new NumberResolvedType(type, nullable); + } + + @Override + public TypeName getNativeType(final NativeTypeContext typeContext) { + // TODO + return TypeName.VOID; + } + + @Override + public @Nullable TypeSpec getGeneratedCode(final String packageName) { + // TODO + throw new UnsupportedOperationException(); + } +} diff --git a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/ObjectResolvedType.java b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/ObjectResolvedType.java new file mode 100644 index 00000000000000..5f57fab1091cdd --- /dev/null +++ b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/ObjectResolvedType.java @@ -0,0 +1,38 @@ +/* + * 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 com.facebook.react.codegen.generator.resolver; + +import com.facebook.react.codegen.generator.model.ObjectType; +import com.facebook.react.codegen.generator.model.TypeData; +import com.squareup.javapoet.TypeName; +import com.squareup.javapoet.TypeSpec; +import javax.annotation.Nullable; + +public final class ObjectResolvedType extends ResolvedType { + + private ObjectResolvedType(final ObjectType type, final boolean nullable) { + super(type, nullable); + } + + public static ObjectResolvedType create( + final ObjectType type, final TypeData typeData, final boolean nullable) { + return new ObjectResolvedType(type, nullable); + } + + @Override + public TypeName getNativeType(final NativeTypeContext typeContext) { + // TODO + return TypeName.VOID; + } + + @Override + public @Nullable TypeSpec getGeneratedCode(final String packageName) { + // TODO + throw new UnsupportedOperationException(); + } +} diff --git a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/PromiseResolvedType.java b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/PromiseResolvedType.java new file mode 100644 index 00000000000000..9c34e59eadc716 --- /dev/null +++ b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/PromiseResolvedType.java @@ -0,0 +1,38 @@ +/* + * 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 com.facebook.react.codegen.generator.resolver; + +import com.facebook.react.codegen.generator.model.PromiseType; +import com.facebook.react.codegen.generator.model.TypeData; +import com.squareup.javapoet.TypeName; +import com.squareup.javapoet.TypeSpec; +import javax.annotation.Nullable; + +public final class PromiseResolvedType extends ResolvedType { + + private PromiseResolvedType(final PromiseType type, final boolean nullable) { + super(type, nullable); + } + + public static PromiseResolvedType create( + final PromiseType type, final TypeData typeData, final boolean nullable) { + return new PromiseResolvedType(type, nullable); + } + + @Override + public TypeName getNativeType(final NativeTypeContext typeContext) { + // TODO + return TypeName.VOID; + } + + @Override + public @Nullable TypeSpec getGeneratedCode(final String packageName) { + // TODO + throw new UnsupportedOperationException(); + } +} diff --git a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/ReservedFunctionValueResolvedType.java b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/ReservedFunctionValueResolvedType.java new file mode 100644 index 00000000000000..67991dc47b8136 --- /dev/null +++ b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/ReservedFunctionValueResolvedType.java @@ -0,0 +1,40 @@ +/* + * 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 com.facebook.react.codegen.generator.resolver; + +import com.facebook.react.codegen.generator.model.ReservedFunctionValueType; +import com.facebook.react.codegen.generator.model.TypeData; +import com.squareup.javapoet.TypeName; +import com.squareup.javapoet.TypeSpec; +import javax.annotation.Nullable; + +public final class ReservedFunctionValueResolvedType + extends ResolvedType { + + private ReservedFunctionValueResolvedType( + final ReservedFunctionValueType type, final boolean nullable) { + super(type, nullable); + } + + public static ReservedFunctionValueResolvedType create( + final ReservedFunctionValueType type, final TypeData typeData, final boolean nullable) { + return new ReservedFunctionValueResolvedType(type, nullable); + } + + @Override + public TypeName getNativeType(final NativeTypeContext typeContext) { + // TODO + return TypeName.VOID; + } + + @Override + public @Nullable TypeSpec getGeneratedCode(final String packageName) { + // TODO + throw new UnsupportedOperationException(); + } +} diff --git a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/ResolvedType.java b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/ResolvedType.java new file mode 100644 index 00000000000000..e9373ed5f56cc0 --- /dev/null +++ b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/ResolvedType.java @@ -0,0 +1,52 @@ +/* + * 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 com.facebook.react.codegen.generator.resolver; + +import com.facebook.react.codegen.generator.model.Type; +import com.facebook.react.codegen.generator.model.TypeData; +import com.squareup.javapoet.TypeName; +import com.squareup.javapoet.TypeSpec; +import javax.annotation.Nullable; + +public abstract class ResolvedType { + /** Contexts native types can appear in. */ + public enum NativeTypeContext { + FUNCTION_ARGUMENT, + FUNCTION_RETURN, + DEFAULT, + } + + protected final T mType; + protected final boolean mNullable; + + protected ResolvedType(final T type, final boolean nullable) { + mType = type; + mNullable = nullable; + } + + protected static ResolvedType resolveType( + final Type type, final TypeData typeData, final boolean nullable) { + return TypeResolver.resolveType(type, typeData, nullable); + } + + public T getType() { + return mType; + } + + public boolean isNullable() { + return mNullable; + } + + /** The Java type generated for this type */ + public abstract TypeName getNativeType(NativeTypeContext typeContext); + + /** Generate code for this type itself, if applicable. */ + public @Nullable TypeSpec getGeneratedCode(final String packageName) { + return null; + } +} diff --git a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/StringResolvedType.java b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/StringResolvedType.java new file mode 100644 index 00000000000000..199968c567bd6d --- /dev/null +++ b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/StringResolvedType.java @@ -0,0 +1,38 @@ +/* + * 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 com.facebook.react.codegen.generator.resolver; + +import com.facebook.react.codegen.generator.model.StringType; +import com.facebook.react.codegen.generator.model.TypeData; +import com.squareup.javapoet.TypeName; +import com.squareup.javapoet.TypeSpec; +import javax.annotation.Nullable; + +public final class StringResolvedType extends ResolvedType { + + private StringResolvedType(final StringType type, final boolean nullable) { + super(type, nullable); + } + + public static StringResolvedType create( + final StringType type, final TypeData typeData, final boolean nullable) { + return new StringResolvedType(type, nullable); + } + + @Override + public TypeName getNativeType(final NativeTypeContext typeContext) { + // TODO + return TypeName.VOID; + } + + @Override + public @Nullable TypeSpec getGeneratedCode(final String packageName) { + // TODO + throw new UnsupportedOperationException(); + } +} diff --git a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/TypeResolver.java b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/TypeResolver.java new file mode 100644 index 00000000000000..e20534b3ba8942 --- /dev/null +++ b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/TypeResolver.java @@ -0,0 +1,91 @@ +/* + * 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 com.facebook.react.codegen.generator.resolver; + +import com.facebook.react.codegen.generator.model.AliasType; +import com.facebook.react.codegen.generator.model.AnyType; +import com.facebook.react.codegen.generator.model.ArrayType; +import com.facebook.react.codegen.generator.model.BooleanType; +import com.facebook.react.codegen.generator.model.FunctionType; +import com.facebook.react.codegen.generator.model.GenericObjectType; +import com.facebook.react.codegen.generator.model.NativeModuleType; +import com.facebook.react.codegen.generator.model.NullableType; +import com.facebook.react.codegen.generator.model.NumberType; +import com.facebook.react.codegen.generator.model.ObjectType; +import com.facebook.react.codegen.generator.model.PromiseType; +import com.facebook.react.codegen.generator.model.ReservedFunctionValueType; +import com.facebook.react.codegen.generator.model.StringType; +import com.facebook.react.codegen.generator.model.Type; +import com.facebook.react.codegen.generator.model.TypeData; +import com.facebook.react.codegen.generator.model.VoidType; + +public final class TypeResolver { + public static ResolvedType resolveType( + final Type type, final TypeData typeData, final boolean nullable) { + System.out.println("Resolving: " + type); + + if (type instanceof AliasType) { + return AliasResolvedType.create((AliasType) type, typeData, nullable); + } + + if (type instanceof AnyType) { + return AnyResolvedType.create((AnyType) type, typeData, nullable); + } + + if (type instanceof ArrayType) { + return ArrayResolvedType.create((ArrayType) type, typeData, nullable); + } + + if (type instanceof BooleanType) { + return BooleanResolvedType.create((BooleanType) type, typeData, nullable); + } + + if (type instanceof FunctionType) { + return FunctionResolvedType.create((FunctionType) type, typeData, nullable); + } + + if (type instanceof GenericObjectType) { + return GenericObjectResolvedType.create((GenericObjectType) type, typeData, nullable); + } + + if (type instanceof NativeModuleType) { + return NativeModuleResolvedType.create((NativeModuleType) type, typeData, nullable); + } + + if (type instanceof NullableType) { + return NullableResolvedType.create((NullableType) type, typeData, nullable); + } + + if (type instanceof NumberType) { + return NumberResolvedType.create((NumberType) type, typeData, nullable); + } + + if (type instanceof ObjectType) { + return ObjectResolvedType.create((ObjectType) type, typeData, nullable); + } + + if (type instanceof PromiseType) { + return PromiseResolvedType.create((PromiseType) type, typeData, nullable); + } + + if (type instanceof ReservedFunctionValueType) { + return ReservedFunctionValueResolvedType.create( + (ReservedFunctionValueType) type, typeData, nullable); + } + + if (type instanceof StringType) { + return StringResolvedType.create((StringType) type, typeData, nullable); + } + + if (type instanceof VoidType) { + return VoidResolvedType.create((VoidType) type, typeData, nullable); + } + + throw new IllegalArgumentException("Unable to resolve unsupported type: " + type.getClass()); + } +} diff --git a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/VoidResolvedType.java b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/VoidResolvedType.java new file mode 100644 index 00000000000000..2d8deebb63c7cb --- /dev/null +++ b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/VoidResolvedType.java @@ -0,0 +1,38 @@ +/* + * 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 com.facebook.react.codegen.generator.resolver; + +import com.facebook.react.codegen.generator.model.TypeData; +import com.facebook.react.codegen.generator.model.VoidType; +import com.squareup.javapoet.TypeName; +import com.squareup.javapoet.TypeSpec; +import javax.annotation.Nullable; + +public final class VoidResolvedType extends ResolvedType { + + private VoidResolvedType(final VoidType type, final boolean nullable) { + super(type, nullable); + } + + public static VoidResolvedType create( + final VoidType type, final TypeData typeData, final boolean nullable) { + return new VoidResolvedType(type, nullable); + } + + @Override + public TypeName getNativeType(final NativeTypeContext typeContext) { + // TODO + return TypeName.VOID; + } + + @Override + public @Nullable TypeSpec getGeneratedCode(final String packageName) { + // TODO + throw new UnsupportedOperationException(); + } +} From 8fc1646c75c86f1aaa77417245e664fa070bf8cd Mon Sep 17 00:00:00 2001 From: Kevin Gozali Date: Tue, 25 Aug 2020 10:34:41 -0700 Subject: [PATCH 0059/1238] Codegen: JavaGenerator [6] - resolve individual types into their generated code Summary: For each resolved type, define how to process its own type and whether it should produce generated code/file, minus the NativeModuleResolvedType (will be in the next commit). Changelog: [Internal] Reviewed By: mdvacca Differential Revision: D23307961 fbshipit-source-id: 87af09867aace7a5ff060a33a00b141048630eda --- .../codegen/generator/JavaGenerator.java | 35 ++++++-------- .../codegen/generator/SchemaJsonParser.java | 15 +++--- .../generator/model/CodegenException.java | 16 +++++++ .../codegen/generator/model/NullableType.java | 6 +-- .../codegen/generator/model/NumberType.java | 2 +- .../model/ReservedFunctionValueType.java | 5 ++ .../generator/resolver/AliasResolvedType.java | 15 ++++-- .../generator/resolver/AnyResolvedType.java | 18 ++++---- .../generator/resolver/ArrayResolvedType.java | 29 +++++++----- .../resolver/BooleanResolvedType.java | 11 +---- .../resolver/FunctionResolvedType.java | 34 +++++++++----- .../resolver/GenericObjectResolvedType.java | 20 ++++---- .../resolver/NativeModuleResolvedType.java | 46 ++++++++++++++++--- .../resolver/NullableResolvedType.java | 9 ++-- .../resolver/NumberResolvedType.java | 24 ++++++---- .../resolver/ObjectResolvedType.java | 42 ++++++++++++++--- .../resolver/PromiseResolvedType.java | 11 +---- .../generator/resolver/ReactClassNames.java | 39 ++++++++++++++++ .../ReservedFunctionValueResolvedType.java | 18 ++++++-- .../resolver/StringResolvedType.java | 12 +---- .../generator/resolver/TypeResolver.java | 1 - .../codegen/generator/resolver/TypeUtils.java | 42 +++++++++++++++++ .../generator/resolver/VoidResolvedType.java | 4 +- 23 files changed, 310 insertions(+), 144 deletions(-) create mode 100644 packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/model/CodegenException.java create mode 100644 packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/ReactClassNames.java create mode 100644 packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/TypeUtils.java diff --git a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/JavaGenerator.java b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/JavaGenerator.java index d6f759e01dddf2..8f8a7b2bf8d77e 100644 --- a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/JavaGenerator.java +++ b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/JavaGenerator.java @@ -8,14 +8,13 @@ package com.facebook.react.codegen.generator; import com.facebook.react.codegen.generator.model.TypeData; +import com.facebook.react.codegen.generator.resolver.ResolvedType; import com.facebook.react.codegen.generator.resolver.TypeResolver; import com.squareup.javapoet.JavaFile; -import com.squareup.javapoet.MethodSpec; import com.squareup.javapoet.TypeSpec; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; -import javax.lang.model.element.Modifier; // TODO: Implement proper generator - this is a sample usage of JavaPoet public final class JavaGenerator { @@ -35,26 +34,18 @@ public void build() throws FileNotFoundException, IOException { .getAllTypes() .forEach( t -> { - // TODO: Ask each resolved type to produce its own code if it supports it. - TypeResolver.resolveType(typeData.getType(t), typeData, false); + ResolvedType resolvedType = + TypeResolver.resolveType(typeData.getType(t), typeData, false); + TypeSpec spec = resolvedType.getGeneratedCode(mJavaPackageName); + if (spec != null) { + final JavaFile javaFile = JavaFile.builder(mJavaPackageName, spec).build(); + System.out.println(javaFile.toString()); + try { + javaFile.writeTo(mOutputDir); + } catch (IOException ex) { + // TODO: Handle this in a different way. + } + } }); - - final MethodSpec main = - MethodSpec.methodBuilder("main") - .addModifiers(Modifier.PUBLIC, Modifier.STATIC) - .returns(void.class) - .addParameter(String[].class, "args") - .addStatement("$T.out.println($S)", System.class, "Hello, JavaPoet!") - .build(); - - final TypeSpec helloWorld = - TypeSpec.classBuilder("ReactNativeCodegen") - .addModifiers(Modifier.PUBLIC, Modifier.FINAL) - .addMethod(main) - .build(); - - final JavaFile javaFile = JavaFile.builder(mJavaPackageName, helloWorld).build(); - - javaFile.writeTo(mOutputDir); } } diff --git a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/SchemaJsonParser.java b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/SchemaJsonParser.java index 45d254cd16d6a2..0b44b62826df84 100644 --- a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/SchemaJsonParser.java +++ b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/SchemaJsonParser.java @@ -11,6 +11,7 @@ import com.facebook.react.codegen.generator.model.AnyType; import com.facebook.react.codegen.generator.model.ArrayType; import com.facebook.react.codegen.generator.model.BooleanType; +import com.facebook.react.codegen.generator.model.CodegenException; import com.facebook.react.codegen.generator.model.DoubleType; import com.facebook.react.codegen.generator.model.FloatType; import com.facebook.react.codegen.generator.model.FunctionType; @@ -44,12 +45,14 @@ public final class SchemaJsonParser { private final TypeData mTypeData = new TypeData(); - public static TypeData parse(final File schemaFile) throws FileNotFoundException, IOException { + public static TypeData parse(final File schemaFile) + throws CodegenException, FileNotFoundException, IOException { final SchemaJsonParser parser = new SchemaJsonParser(); return parser.buildTypeData(schemaFile); } - private TypeData buildTypeData(final File schemaFile) throws FileNotFoundException, IOException { + private TypeData buildTypeData(final File schemaFile) + throws CodegenException, FileNotFoundException, IOException { final JsonParser parser = new JsonParser(); final JsonElement rootElement = parser.parse(new FileReader(schemaFile)); @@ -90,8 +93,7 @@ private TypeData buildTypeData(final File schemaFile) throws FileNotFoundExcepti } // Parse type information from a JSON "typeAnnotation" node. - private Type parseTypeAnnotation(final TypeId typeId, final JsonObject typeAnnotation) - throws IllegalStateException { + private Type parseTypeAnnotation(final TypeId typeId, final JsonObject typeAnnotation) { final String type = typeAnnotation.get("type").getAsString(); // TODO (T71824250): Support NullableTypeAnnotation in the schema instead of a field here. final boolean nullable = @@ -128,7 +130,8 @@ private Type parseTypeAnnotation(final TypeId typeId, final JsonObject typeAnnot parsedType = new Int32Type(typeId); break; case NumberType.TYPE_NAME: - parsedType = new NumberType(typeId); + // Use double type for generic numbers. + parsedType = new DoubleType(typeId); break; case ObjectType.TYPE_NAME: parsedType = parseObjectTypeAnnotation(typeId, typeAnnotation); @@ -145,7 +148,7 @@ private Type parseTypeAnnotation(final TypeId typeId, final JsonObject typeAnnot case VoidType.TYPE_NAME: return VoidType.VOID; default: - throw new IllegalStateException("Found invalid type annotation: " + type); + throw new CodegenException("Found invalid type annotation: " + type); } final Type finalType = maybeCreateNullableType(nullable, parsedType); diff --git a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/model/CodegenException.java b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/model/CodegenException.java new file mode 100644 index 00000000000000..0b0ff3c8680e58 --- /dev/null +++ b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/model/CodegenException.java @@ -0,0 +1,16 @@ +/* + * 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 com.facebook.react.codegen.generator.model; + +public class CodegenException extends RuntimeException { + private static final long serialVersionUID = 1L; + + public CodegenException(final String message) { + super(message); + } +} diff --git a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/model/NullableType.java b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/model/NullableType.java index 5b85bb28cb0396..51809250d204da 100644 --- a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/model/NullableType.java +++ b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/model/NullableType.java @@ -10,10 +10,10 @@ public final class NullableType extends Type { public static final String TYPE_NAME = "NullableTypeAnnotation"; - public final Type referredType; + public final Type innerType; - public NullableType(final TypeId typeId, final Type referredType) { + public NullableType(final TypeId typeId, final Type innerType) { super(typeId); - this.referredType = referredType; + this.innerType = innerType; } } diff --git a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/model/NumberType.java b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/model/NumberType.java index e31df14556b40c..382e06846d6ab5 100644 --- a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/model/NumberType.java +++ b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/model/NumberType.java @@ -7,7 +7,7 @@ package com.facebook.react.codegen.generator.model; -public class NumberType extends Type { +public abstract class NumberType extends Type { public static final String TYPE_NAME = "NumberTypeAnnotation"; public NumberType(final TypeId typeId) { diff --git a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/model/ReservedFunctionValueType.java b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/model/ReservedFunctionValueType.java index c8a6d132aa8167..c1f755ed118f82 100644 --- a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/model/ReservedFunctionValueType.java +++ b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/model/ReservedFunctionValueType.java @@ -20,4 +20,9 @@ public ReservedFunctionValueType(final TypeId typeId, ReservedName reservedName) super(typeId); this.reservedName = reservedName; } + + @Override + public String toString() { + return mTypeId + "(" + reservedName.toString() + ")"; + } } diff --git a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/AliasResolvedType.java b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/AliasResolvedType.java index 2f6d3d5bbd05a5..6720ef76e38efc 100644 --- a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/AliasResolvedType.java +++ b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/AliasResolvedType.java @@ -8,6 +8,8 @@ package com.facebook.react.codegen.generator.resolver; import com.facebook.react.codegen.generator.model.AliasType; +import com.facebook.react.codegen.generator.model.AnyType; +import com.facebook.react.codegen.generator.model.Type; import com.facebook.react.codegen.generator.model.TypeData; import com.squareup.javapoet.TypeName; import com.squareup.javapoet.TypeSpec; @@ -17,22 +19,25 @@ public final class AliasResolvedType extends ResolvedType { private AliasResolvedType(final AliasType type, final boolean nullable) { super(type, nullable); + throw new UnsupportedOperationException(); } - public static AliasResolvedType create( + public static ResolvedType create( final AliasType type, final TypeData typeData, final boolean nullable) { - return new AliasResolvedType(type, nullable); + Type referredType = typeData.getType(type.referredTypeId); + if (referredType != null) { + return resolveType(referredType, typeData, nullable); + } + return resolveType(new AnyType(type.getTypeId()), typeData, nullable); } @Override public TypeName getNativeType(final NativeTypeContext typeContext) { - // TODO - return TypeName.VOID; + throw new UnsupportedOperationException(); } @Override public @Nullable TypeSpec getGeneratedCode(final String packageName) { - // TODO throw new UnsupportedOperationException(); } } diff --git a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/AnyResolvedType.java b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/AnyResolvedType.java index 203cd1150bdf40..e9fc8dc335b5f4 100644 --- a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/AnyResolvedType.java +++ b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/AnyResolvedType.java @@ -10,8 +10,6 @@ import com.facebook.react.codegen.generator.model.AnyType; import com.facebook.react.codegen.generator.model.TypeData; import com.squareup.javapoet.TypeName; -import com.squareup.javapoet.TypeSpec; -import javax.annotation.Nullable; public final class AnyResolvedType extends ResolvedType { @@ -26,13 +24,13 @@ public static AnyResolvedType create( @Override public TypeName getNativeType(final NativeTypeContext typeContext) { - // TODO - return TypeName.VOID; - } - - @Override - public @Nullable TypeSpec getGeneratedCode(final String packageName) { - // TODO - throw new UnsupportedOperationException(); + switch (typeContext) { + case FUNCTION_ARGUMENT: + return TypeUtils.makeNullable(ReactClassNames.REACT_READABLE_MAP, mNullable); + case FUNCTION_RETURN: + return TypeUtils.makeNullable(ReactClassNames.REACT_WRITABLE_MAP, mNullable); + default: + return TypeUtils.makeNullable(TypeName.OBJECT, mNullable); + } } } diff --git a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/ArrayResolvedType.java b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/ArrayResolvedType.java index e6d08108dd5681..b6a7d3b7854c43 100644 --- a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/ArrayResolvedType.java +++ b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/ArrayResolvedType.java @@ -9,30 +9,37 @@ import com.facebook.react.codegen.generator.model.ArrayType; import com.facebook.react.codegen.generator.model.TypeData; +import com.squareup.javapoet.ArrayTypeName; import com.squareup.javapoet.TypeName; -import com.squareup.javapoet.TypeSpec; -import javax.annotation.Nullable; public final class ArrayResolvedType extends ResolvedType { - private ArrayResolvedType(final ArrayType type, final boolean nullable) { + private final ResolvedType mElementResolvedType; + + private ArrayResolvedType(final ArrayType type, final TypeData typeData, final boolean nullable) { super(type, nullable); + mElementResolvedType = resolveType(mType.elementType, typeData, nullable); } public static ArrayResolvedType create( final ArrayType type, final TypeData typeData, final boolean nullable) { - return new ArrayResolvedType(type, nullable); + return new ArrayResolvedType(type, typeData, nullable); } - @Override - public TypeName getNativeType(final NativeTypeContext typeContext) { - // TODO - return TypeName.VOID; + public ResolvedType getElementResolvedType() { + return mElementResolvedType; } @Override - public @Nullable TypeSpec getGeneratedCode(final String packageName) { - // TODO - throw new UnsupportedOperationException(); + public TypeName getNativeType(final NativeTypeContext typeContext) { + switch (typeContext) { + case FUNCTION_ARGUMENT: + return TypeUtils.makeNullable(ReactClassNames.REACT_READABLE_ARRAY, mNullable); + case FUNCTION_RETURN: + return TypeUtils.makeNullable(ReactClassNames.REACT_WRITABLE_ARRAY, mNullable); + default: + return TypeUtils.makeNullable( + ArrayTypeName.of(mElementResolvedType.getNativeType(typeContext)), mNullable); + } } } diff --git a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/BooleanResolvedType.java b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/BooleanResolvedType.java index 48cc67dc280421..75ac0a77ce5f8b 100644 --- a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/BooleanResolvedType.java +++ b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/BooleanResolvedType.java @@ -10,8 +10,6 @@ import com.facebook.react.codegen.generator.model.BooleanType; import com.facebook.react.codegen.generator.model.TypeData; import com.squareup.javapoet.TypeName; -import com.squareup.javapoet.TypeSpec; -import javax.annotation.Nullable; public final class BooleanResolvedType extends ResolvedType { @@ -26,13 +24,6 @@ public static BooleanResolvedType create( @Override public TypeName getNativeType(final NativeTypeContext typeContext) { - // TODO - return TypeName.VOID; - } - - @Override - public @Nullable TypeSpec getGeneratedCode(final String packageName) { - // TODO - throw new UnsupportedOperationException(); + return TypeUtils.makeNullable(TypeName.BOOLEAN, mNullable); } } diff --git a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/FunctionResolvedType.java b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/FunctionResolvedType.java index 19d0dde4637bd8..495070afa2b0ed 100644 --- a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/FunctionResolvedType.java +++ b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/FunctionResolvedType.java @@ -10,29 +10,41 @@ import com.facebook.react.codegen.generator.model.FunctionType; import com.facebook.react.codegen.generator.model.TypeData; import com.squareup.javapoet.TypeName; -import com.squareup.javapoet.TypeSpec; -import javax.annotation.Nullable; +import java.util.Collections; +import java.util.Map; +import java.util.stream.Collectors; public final class FunctionResolvedType extends ResolvedType { + private final Map mResolvedArgTypes; + private final ResolvedType mResolvedReturnType; - private FunctionResolvedType(final FunctionType type, final boolean nullable) { + private FunctionResolvedType( + final FunctionType type, final TypeData typeData, final boolean nullable) { super(type, nullable); + mResolvedReturnType = resolveType(type.returnType, typeData, nullable); + mResolvedArgTypes = + Collections.unmodifiableMap( + type.parameters.stream() + .collect( + Collectors.toMap( + item -> item.name, item -> resolveType(item.type, typeData, false)))); } public static FunctionResolvedType create( final FunctionType type, final TypeData typeData, final boolean nullable) { - return new FunctionResolvedType(type, nullable); + return new FunctionResolvedType(type, typeData, nullable); } - @Override - public TypeName getNativeType(final NativeTypeContext typeContext) { - // TODO - return TypeName.VOID; + public ResolvedType getResolvedReturnType() { + return mResolvedReturnType; + } + + public Map getResolvedArgTypes() { + return mResolvedArgTypes; } @Override - public @Nullable TypeSpec getGeneratedCode(final String packageName) { - // TODO - throw new UnsupportedOperationException(); + public TypeName getNativeType(final NativeTypeContext typeContext) { + return TypeUtils.makeNullable(ReactClassNames.REACT_CALLBACK, mNullable); } } diff --git a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/GenericObjectResolvedType.java b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/GenericObjectResolvedType.java index c2dd163540282e..84b98eb9698e14 100644 --- a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/GenericObjectResolvedType.java +++ b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/GenericObjectResolvedType.java @@ -7,11 +7,10 @@ package com.facebook.react.codegen.generator.resolver; +import com.facebook.react.codegen.generator.model.CodegenException; import com.facebook.react.codegen.generator.model.GenericObjectType; import com.facebook.react.codegen.generator.model.TypeData; import com.squareup.javapoet.TypeName; -import com.squareup.javapoet.TypeSpec; -import javax.annotation.Nullable; public final class GenericObjectResolvedType extends ResolvedType { @@ -26,13 +25,16 @@ public static GenericObjectResolvedType create( @Override public TypeName getNativeType(final NativeTypeContext typeContext) { - // TODO - return TypeName.VOID; - } + switch (typeContext) { + case FUNCTION_ARGUMENT: + return TypeUtils.makeNullable(ReactClassNames.REACT_READABLE_MAP, mNullable); + case FUNCTION_RETURN: + return TypeUtils.makeNullable(ReactClassNames.REACT_WRITABLE_MAP, mNullable); + default: + break; + } - @Override - public @Nullable TypeSpec getGeneratedCode(final String packageName) { - // TODO - throw new UnsupportedOperationException(); + throw new CodegenException( + "Unsupported GenericObjectType: " + mType + " - typeContext: " + typeContext); } } diff --git a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/NativeModuleResolvedType.java b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/NativeModuleResolvedType.java index 15ffde5d197412..001615615c5dff 100644 --- a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/NativeModuleResolvedType.java +++ b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/NativeModuleResolvedType.java @@ -9,30 +9,64 @@ import com.facebook.react.codegen.generator.model.NativeModuleType; import com.facebook.react.codegen.generator.model.TypeData; +import com.squareup.javapoet.MethodSpec; import com.squareup.javapoet.TypeName; import com.squareup.javapoet.TypeSpec; +import java.util.Collections; +import java.util.Map; +import java.util.stream.Collectors; import javax.annotation.Nullable; +import javax.lang.model.element.Modifier; public final class NativeModuleResolvedType extends ResolvedType { + private final Map mResolvedAliasTypes; + private final Map mResolvedPropertyTypes; - private NativeModuleResolvedType(final NativeModuleType type, final boolean nullable) { + private NativeModuleResolvedType( + final NativeModuleType type, final TypeData typeData, final boolean nullable) { super(type, nullable); + mResolvedAliasTypes = + Collections.unmodifiableMap( + type.aliases.stream() + .collect( + Collectors.toMap( + item -> item.getTypeId().typeName, + item -> resolveType(item, typeData, false)))); + mResolvedPropertyTypes = + Collections.unmodifiableMap( + type.properties.stream() + .collect( + Collectors.toMap( + item -> item.name, + // TODO: Optional Object property is not necessarily nullable. + item -> resolveType(item.type, typeData, item.optional)))); } public static NativeModuleResolvedType create( final NativeModuleType type, final TypeData typeData, final boolean nullable) { - return new NativeModuleResolvedType(type, nullable); + return new NativeModuleResolvedType(type, typeData, nullable); } @Override public TypeName getNativeType(final NativeTypeContext typeContext) { - // TODO - return TypeName.VOID; + throw new UnsupportedOperationException( + "NativeModuleType cannot be referred to by other types."); } @Override public @Nullable TypeSpec getGeneratedCode(final String packageName) { - // TODO - throw new UnsupportedOperationException(); + // TODO: Remove this placeholder implementation. + final MethodSpec main = + MethodSpec.methodBuilder("main") + .addModifiers(Modifier.PUBLIC, Modifier.STATIC) + .returns(void.class) + .addParameter(String[].class, "args") + .addStatement("$T.out.println($S)", System.class, "Hello, JavaPoet!") + .build(); + + return TypeSpec.classBuilder(mType.getTypeId().typeName) + .addModifiers(Modifier.PUBLIC, Modifier.FINAL) + .addMethod(main) + .build(); } } diff --git a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/NullableResolvedType.java b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/NullableResolvedType.java index 0ffe587ade2d70..b5dd2fee1ea7d3 100644 --- a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/NullableResolvedType.java +++ b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/NullableResolvedType.java @@ -17,22 +17,21 @@ public final class NullableResolvedType extends ResolvedType { private NullableResolvedType(final NullableType type, final boolean nullable) { super(type, nullable); + throw new UnsupportedOperationException(); } - public static NullableResolvedType create( + public static ResolvedType create( final NullableType type, final TypeData typeData, final boolean nullable) { - return new NullableResolvedType(type, nullable); + return resolveType(type.innerType, typeData, true); } @Override public TypeName getNativeType(final NativeTypeContext typeContext) { - // TODO - return TypeName.VOID; + throw new UnsupportedOperationException(); } @Override public @Nullable TypeSpec getGeneratedCode(final String packageName) { - // TODO throw new UnsupportedOperationException(); } } diff --git a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/NumberResolvedType.java b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/NumberResolvedType.java index 8b241ddeed7435..6a9576efe7cabb 100644 --- a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/NumberResolvedType.java +++ b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/NumberResolvedType.java @@ -7,11 +7,13 @@ package com.facebook.react.codegen.generator.resolver; +import com.facebook.react.codegen.generator.model.CodegenException; +import com.facebook.react.codegen.generator.model.DoubleType; +import com.facebook.react.codegen.generator.model.FloatType; +import com.facebook.react.codegen.generator.model.Int32Type; import com.facebook.react.codegen.generator.model.NumberType; import com.facebook.react.codegen.generator.model.TypeData; import com.squareup.javapoet.TypeName; -import com.squareup.javapoet.TypeSpec; -import javax.annotation.Nullable; public final class NumberResolvedType extends ResolvedType { @@ -26,13 +28,15 @@ public static NumberResolvedType create( @Override public TypeName getNativeType(final NativeTypeContext typeContext) { - // TODO - return TypeName.VOID; - } - - @Override - public @Nullable TypeSpec getGeneratedCode(final String packageName) { - // TODO - throw new UnsupportedOperationException(); + if (mType instanceof Int32Type) { + return TypeUtils.makeNullable(TypeName.INT, mNullable); + } + if (mType instanceof FloatType) { + return TypeUtils.makeNullable(TypeName.FLOAT, mNullable); + } + if (mType instanceof DoubleType) { + return TypeUtils.makeNullable(TypeName.DOUBLE, mNullable); + } + throw new CodegenException("Unsupported NumberType: " + mType.getClass()); } } diff --git a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/ObjectResolvedType.java b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/ObjectResolvedType.java index 5f57fab1091cdd..54a9cb09eeec28 100644 --- a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/ObjectResolvedType.java +++ b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/ObjectResolvedType.java @@ -7,32 +7,62 @@ package com.facebook.react.codegen.generator.resolver; +import com.facebook.react.codegen.generator.model.CodegenException; import com.facebook.react.codegen.generator.model.ObjectType; import com.facebook.react.codegen.generator.model.TypeData; import com.squareup.javapoet.TypeName; import com.squareup.javapoet.TypeSpec; +import java.util.Collections; +import java.util.Map; +import java.util.stream.Collectors; import javax.annotation.Nullable; public final class ObjectResolvedType extends ResolvedType { + private final Map mResolvedPropertyTypes; - private ObjectResolvedType(final ObjectType type, final boolean nullable) { + private ObjectResolvedType( + final ObjectType type, final TypeData typeData, final boolean nullable) { super(type, nullable); + mResolvedPropertyTypes = + Collections.unmodifiableMap( + type.properties.stream() + .collect( + Collectors.toMap( + item -> item.name, + // TODO: Optional Object property is not necessarily nullable. + item -> resolveType(item.type, typeData, item.optional)))); } public static ObjectResolvedType create( final ObjectType type, final TypeData typeData, final boolean nullable) { - return new ObjectResolvedType(type, nullable); + return new ObjectResolvedType(type, typeData, nullable); + } + + public Map getResolvedPropertyTypes() { + return mResolvedPropertyTypes; } @Override public TypeName getNativeType(final NativeTypeContext typeContext) { - // TODO - return TypeName.VOID; + // TODO: It should return its own class type. + // However, the NativeModule system only supports built-in ReadableMap/WritableMap for now. + switch (typeContext) { + case FUNCTION_ARGUMENT: + return TypeUtils.makeNullable(ReactClassNames.REACT_READABLE_MAP, mNullable); + case FUNCTION_RETURN: + return TypeUtils.makeNullable(ReactClassNames.REACT_WRITABLE_MAP, mNullable); + default: + break; + } + + throw new CodegenException( + "Unsupported ObjectType: " + mType + " - typeContext: " + typeContext); } @Override public @Nullable TypeSpec getGeneratedCode(final String packageName) { - // TODO - throw new UnsupportedOperationException(); + // TODO: Object type should produce is own class to represent its shape. + // However, the NativeModule system only supports built-in ReadableMap/WritableMap for now. + return null; } } diff --git a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/PromiseResolvedType.java b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/PromiseResolvedType.java index 9c34e59eadc716..0c575ff08a2646 100644 --- a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/PromiseResolvedType.java +++ b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/PromiseResolvedType.java @@ -10,8 +10,6 @@ import com.facebook.react.codegen.generator.model.PromiseType; import com.facebook.react.codegen.generator.model.TypeData; import com.squareup.javapoet.TypeName; -import com.squareup.javapoet.TypeSpec; -import javax.annotation.Nullable; public final class PromiseResolvedType extends ResolvedType { @@ -26,13 +24,6 @@ public static PromiseResolvedType create( @Override public TypeName getNativeType(final NativeTypeContext typeContext) { - // TODO - return TypeName.VOID; - } - - @Override - public @Nullable TypeSpec getGeneratedCode(final String packageName) { - // TODO - throw new UnsupportedOperationException(); + return TypeUtils.makeNullable(ReactClassNames.REACT_PROMISE, mNullable); } } diff --git a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/ReactClassNames.java b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/ReactClassNames.java new file mode 100644 index 00000000000000..2fca4df5dfde38 --- /dev/null +++ b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/ReactClassNames.java @@ -0,0 +1,39 @@ +/* + * 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 com.facebook.react.codegen.generator.resolver; + +import com.squareup.javapoet.ClassName; + +/** Names of React-specific Java classes required by generated code. */ +public class ReactClassNames { + + public static final ClassName REACT_APPLICATION_CONTEXT = + ClassName.bestGuess("com.facebook.react.bridge.ReactApplicationContext"); + public static final ClassName REACT_CALLBACK = + ClassName.bestGuess("com.facebook.react.bridge.Callback"); + public static final ClassName REACT_CONTEXT_BASE_JAVA_MODULE = + ClassName.bestGuess("com.facebook.react.bridge.ReactContextBaseJavaModule"); + public static final ClassName REACT_METHOD = + ClassName.bestGuess("com.facebook.react.bridge.ReactMethod"); + public static final ClassName REACT_MODULE_WITH_SPEC = + ClassName.bestGuess("com.facebook.react.bridge.ReactModuleWithSpec"); + public static final ClassName REACT_PROMISE = + ClassName.bestGuess("com.facebook.react.bridge.Promise"); + public static final ClassName REACT_READABLE_ARRAY = + ClassName.bestGuess("com.facebook.react.bridge.ReadableArray"); + public static final ClassName REACT_READABLE_MAP = + ClassName.bestGuess("com.facebook.react.bridge.ReadableMap"); + public static final ClassName REACT_WRITABLE_ARRAY = + ClassName.bestGuess("com.facebook.react.bridge.WritableArray"); + public static final ClassName REACT_WRITABLE_MAP = + ClassName.bestGuess("com.facebook.react.bridge.WritableMap"); + public static final ClassName REACT_BUILD_CONFIG = + ClassName.bestGuess("com.facebook.react.common.build.ReactBuildConfig"); + public static final ClassName REACT_TURBOMODULE = + ClassName.bestGuess("com.facebook.react.turbomodule.core.interfaces.TurboModule"); +} diff --git a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/ReservedFunctionValueResolvedType.java b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/ReservedFunctionValueResolvedType.java index 67991dc47b8136..3cd677cc70e53c 100644 --- a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/ReservedFunctionValueResolvedType.java +++ b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/ReservedFunctionValueResolvedType.java @@ -7,6 +7,8 @@ package com.facebook.react.codegen.generator.resolver; +import com.facebook.react.codegen.generator.model.CodegenException; +import com.facebook.react.codegen.generator.model.DoubleType; import com.facebook.react.codegen.generator.model.ReservedFunctionValueType; import com.facebook.react.codegen.generator.model.TypeData; import com.squareup.javapoet.TypeName; @@ -19,22 +21,28 @@ public final class ReservedFunctionValueResolvedType private ReservedFunctionValueResolvedType( final ReservedFunctionValueType type, final boolean nullable) { super(type, nullable); + throw new UnsupportedOperationException(); } - public static ReservedFunctionValueResolvedType create( + public static ResolvedType create( final ReservedFunctionValueType type, final TypeData typeData, final boolean nullable) { - return new ReservedFunctionValueResolvedType(type, nullable); + switch (type.reservedName) { + case RootTag: + return resolveType(new DoubleType(type.getTypeId()), typeData, nullable); + default: + break; + } + + throw new CodegenException("Unsupported ReservedFunctionValueType: " + type); } @Override public TypeName getNativeType(final NativeTypeContext typeContext) { - // TODO - return TypeName.VOID; + throw new UnsupportedOperationException(); } @Override public @Nullable TypeSpec getGeneratedCode(final String packageName) { - // TODO throw new UnsupportedOperationException(); } } diff --git a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/StringResolvedType.java b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/StringResolvedType.java index 199968c567bd6d..7a24e39be6bce7 100644 --- a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/StringResolvedType.java +++ b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/StringResolvedType.java @@ -9,9 +9,8 @@ import com.facebook.react.codegen.generator.model.StringType; import com.facebook.react.codegen.generator.model.TypeData; +import com.squareup.javapoet.ClassName; import com.squareup.javapoet.TypeName; -import com.squareup.javapoet.TypeSpec; -import javax.annotation.Nullable; public final class StringResolvedType extends ResolvedType { @@ -26,13 +25,6 @@ public static StringResolvedType create( @Override public TypeName getNativeType(final NativeTypeContext typeContext) { - // TODO - return TypeName.VOID; - } - - @Override - public @Nullable TypeSpec getGeneratedCode(final String packageName) { - // TODO - throw new UnsupportedOperationException(); + return TypeUtils.makeNullable(ClassName.get(String.class), mNullable); } } diff --git a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/TypeResolver.java b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/TypeResolver.java index e20534b3ba8942..6b9b533876e34e 100644 --- a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/TypeResolver.java +++ b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/TypeResolver.java @@ -27,7 +27,6 @@ public final class TypeResolver { public static ResolvedType resolveType( final Type type, final TypeData typeData, final boolean nullable) { - System.out.println("Resolving: " + type); if (type instanceof AliasType) { return AliasResolvedType.create((AliasType) type, typeData, nullable); diff --git a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/TypeUtils.java b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/TypeUtils.java new file mode 100644 index 00000000000000..4c45f76889e74a --- /dev/null +++ b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/TypeUtils.java @@ -0,0 +1,42 @@ +/* + * 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 com.facebook.react.codegen.generator.resolver; + +import com.squareup.javapoet.AnnotationSpec; +import com.squareup.javapoet.ParameterizedTypeName; +import com.squareup.javapoet.TypeName; +import com.squareup.javapoet.TypeVariableName; +import javax.annotation.Nullable; + +public class TypeUtils { + + public static class Annotations { + public static final AnnotationSpec OVERRIDE = AnnotationSpec.builder(Override.class).build(); + public static final AnnotationSpec NULLABLE = AnnotationSpec.builder(Nullable.class).build(); + } + + public static TypeName getNativeClassName(TypeName className) { + while (className instanceof ParameterizedTypeName) { + className = ((ParameterizedTypeName) className).rawType; + } + + return (className instanceof TypeVariableName) ? TypeName.OBJECT : className.box(); + } + + public static TypeName makeNullable(TypeName typeName, boolean isNullable) { + if (isNullable) { + if (typeName.isPrimitive()) { + return typeName.box(); + } + if (!typeName.annotations.contains(Annotations.NULLABLE)) { + return typeName.annotated(Annotations.NULLABLE); + } + } + return typeName; + } +} diff --git a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/VoidResolvedType.java b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/VoidResolvedType.java index 2d8deebb63c7cb..4a4e0c823de2db 100644 --- a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/VoidResolvedType.java +++ b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/VoidResolvedType.java @@ -26,13 +26,11 @@ public static VoidResolvedType create( @Override public TypeName getNativeType(final NativeTypeContext typeContext) { - // TODO - return TypeName.VOID; + return TypeUtils.makeNullable(TypeName.VOID, mNullable); } @Override public @Nullable TypeSpec getGeneratedCode(final String packageName) { - // TODO throw new UnsupportedOperationException(); } } From 92a3dff58ab062acf4cd5eefaba8ac67a835cbc2 Mon Sep 17 00:00:00 2001 From: Kevin Gozali Date: Tue, 25 Aug 2020 10:34:41 -0700 Subject: [PATCH 0060/1238] Codegen: ignore NativeUIManager.js when producing schema given a JavaScript directory Summary: When crawling a provided JS directory to find all .js files for NativeModules and native components, ignore `NativeUIManager.js` for now, because it will be replaced with the Fabric UIManager in the future. The existing NativeUIManagerSpec.java won't be produced by the codegen, but stays manually checked in just in case: https://github.com/facebook/react-native/blob/0199a0392c65fa72d9599262ba1b4f8e14c0fc04/ReactAndroid/src/main/java/com/facebook/fbreact/specs/NativeUIManagerSpec.java Changelog: [Internal] Reviewed By: mdvacca Differential Revision: D23312859 fbshipit-source-id: 7d554fefa651732c13e478b8ec94566348ed3142 --- .../src/cli/combine/combine-js-to-schema-cli.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/react-native-codegen/src/cli/combine/combine-js-to-schema-cli.js b/packages/react-native-codegen/src/cli/combine/combine-js-to-schema-cli.js index 7de7a602b34319..f9a0a07d8c90af 100644 --- a/packages/react-native-codegen/src/cli/combine/combine-js-to-schema-cli.js +++ b/packages/react-native-codegen/src/cli/combine/combine-js-to-schema-cli.js @@ -29,6 +29,9 @@ fileList.forEach(file => { .filter( f => /^(Native.+|.+NativeComponent)/.test(path.basename(f)) && + // NativeUIManager will be deprecated by Fabric UIManager. + // For now, ignore this spec completely because the types are not fully supported. + !f.endsWith('NativeUIManager.js') && !f.includes('__tests'), ); allFiles.push(...dirFiles); From 8ce57ec1b5ee5399c72bce55c0a6c83c8b449003 Mon Sep 17 00:00:00 2001 From: Kevin Gozali Date: Tue, 25 Aug 2020 10:34:41 -0700 Subject: [PATCH 0061/1238] Codegen: JavaGenerator [7] - produce complete NativeModule spec .java files Summary: This implements the full NativeModuleResolvedType for each NativeModule spec, producing .java spec files in the output directory. The output files are now compiled during build time for :ReactAndroid and :packages:rn-tester:android:app. Changelog: [Internal] Reviewed By: mdvacca Differential Revision: D23312858 fbshipit-source-id: c521b9d6602677fd275891cf44329740c6bd7387 --- .../codegen/generator/JavaGenerator.java | 95 ++++++-- .../generator/resolver/Annotations.java | 16 ++ .../generator/resolver/ClassNames.java | 23 ++ .../resolver/FunctionResolvedType.java | 72 ++++++ .../resolver/NativeModuleResolvedType.java | 214 ++++++++++++++++-- .../resolver/StringResolvedType.java | 3 +- .../codegen/generator/resolver/TypeUtils.java | 17 +- 7 files changed, 397 insertions(+), 43 deletions(-) create mode 100644 packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/Annotations.java create mode 100644 packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/ClassNames.java diff --git a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/JavaGenerator.java b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/JavaGenerator.java index 8f8a7b2bf8d77e..ee2a968bd23011 100644 --- a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/JavaGenerator.java +++ b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/JavaGenerator.java @@ -7,6 +7,9 @@ package com.facebook.react.codegen.generator; +import static java.nio.charset.StandardCharsets.UTF_8; + +import com.facebook.react.codegen.generator.model.CodegenException; import com.facebook.react.codegen.generator.model.TypeData; import com.facebook.react.codegen.generator.resolver.ResolvedType; import com.facebook.react.codegen.generator.resolver.TypeResolver; @@ -15,9 +18,32 @@ import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; +import java.util.stream.Collectors; -// TODO: Implement proper generator - this is a sample usage of JavaPoet +/** + * Given a react-native-codegen JSON schema, generate a set of .java files for React Native. The + * generator is isolated to a single schema, and a single Java package output. + */ public final class JavaGenerator { + public static String LICENSE_HEADER = + "/*\n" + + " * Copyright (c) Facebook, Inc. and its affiliates.\n" + + " *\n" + + " * This source code is licensed under the MIT license found in the\n" + + " * LICENSE file in the root directory of this source tree.\n" + + " *\n" + + " * Generated by react-native-codegen JavaGenerator.\n" + + " *\n" + + " * @" + + "generated\n" + + " * @" + + "nolint\n" + + " */\n\n"; private final File mSchemaFile; private final String mJavaPackageName; private final File mOutputDir; @@ -28,24 +54,53 @@ public JavaGenerator(final File schemaFile, final String javaPackageName, final mOutputDir = outputDir; } - public void build() throws FileNotFoundException, IOException { - TypeData typeData = SchemaJsonParser.parse(mSchemaFile); - typeData - .getAllTypes() - .forEach( - t -> { - ResolvedType resolvedType = - TypeResolver.resolveType(typeData.getType(t), typeData, false); - TypeSpec spec = resolvedType.getGeneratedCode(mJavaPackageName); - if (spec != null) { - final JavaFile javaFile = JavaFile.builder(mJavaPackageName, spec).build(); - System.out.println(javaFile.toString()); - try { - javaFile.writeTo(mOutputDir); - } catch (IOException ex) { - // TODO: Handle this in a different way. - } - } - }); + public void build() throws CodegenException, FileNotFoundException, IOException { + // Step 1: Given a schema JSON, collect all types. + final TypeData typeData = SchemaJsonParser.parse(mSchemaFile); + + // Step 2: Resolve each type, then collect those that produce a class or interface (TypeSpec). + final List typeSpecsToWrite = + typeData.getAllTypes().stream() + .map( + t -> { + final ResolvedType resolvedType = + TypeResolver.resolveType(typeData.getType(t), typeData, false); + final TypeSpec spec = resolvedType.getGeneratedCode(mJavaPackageName); + return spec; + }) + .filter(f -> f != null) + .collect(Collectors.toList()); + + // Step 3: Write all of the TypeSpec's into the output directory. + for (final TypeSpec typeSpec : typeSpecsToWrite) { + writeTypeSpecToFile(typeSpec); + } + } + + private final void writeTypeSpecToFile(final TypeSpec typeSpec) + throws CodegenException, IOException { + JavaFile file = JavaFile.builder(mJavaPackageName, typeSpec).skipJavaLangImports(true).build(); + + // Instead of using JavaFile.writeTo() API, manage the output files ourselves because + // JavaFile.addFileComment() does not support "block comment" style. + // See https://github.com/square/javapoet/issues/682#issuecomment-512238075. + Path outputDirPath = mOutputDir.toPath(); + + if (Files.exists(outputDirPath) && !Files.isDirectory(outputDirPath)) { + throw new CodegenException( + "Output path " + outputDirPath + " exists but is not a directory."); + } + + if (!mJavaPackageName.isEmpty()) { + for (String packageComponent : mJavaPackageName.split("\\.")) { + outputDirPath = outputDirPath.resolve(packageComponent); + } + Files.createDirectories(outputDirPath); + } + + Path outputPath = outputDirPath.resolve(typeSpec.name + ".java"); + try (Writer writer = new OutputStreamWriter(Files.newOutputStream(outputPath), UTF_8)) { + writer.write(LICENSE_HEADER + file.toString()); + } } } diff --git a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/Annotations.java b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/Annotations.java new file mode 100644 index 00000000000000..4025b545ef75bf --- /dev/null +++ b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/Annotations.java @@ -0,0 +1,16 @@ +/* + * 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 com.facebook.react.codegen.generator.resolver; + +import com.squareup.javapoet.AnnotationSpec; +import javax.annotation.Nullable; + +public class Annotations { + public static final AnnotationSpec OVERRIDE = AnnotationSpec.builder(Override.class).build(); + public static final AnnotationSpec NULLABLE = AnnotationSpec.builder(Nullable.class).build(); +} diff --git a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/ClassNames.java b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/ClassNames.java new file mode 100644 index 00000000000000..5a76753ed2bf22 --- /dev/null +++ b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/ClassNames.java @@ -0,0 +1,23 @@ +/* + * 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 com.facebook.react.codegen.generator.resolver; + +import com.squareup.javapoet.ClassName; +import com.squareup.javapoet.ParameterizedTypeName; +import com.squareup.javapoet.TypeName; +import java.util.Map; + +/** Names of Java classes required by generated code. */ +public class ClassNames { + + // Java standard classes + public static final TypeName STRING = ClassName.get(String.class); + + public static final ParameterizedTypeName CONSTANTS_MAP = + ParameterizedTypeName.get(ClassName.get(Map.class), ClassNames.STRING, ClassName.OBJECT); +} diff --git a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/FunctionResolvedType.java b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/FunctionResolvedType.java index 495070afa2b0ed..067f0b3c7a24c4 100644 --- a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/FunctionResolvedType.java +++ b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/FunctionResolvedType.java @@ -9,10 +9,16 @@ import com.facebook.react.codegen.generator.model.FunctionType; import com.facebook.react.codegen.generator.model.TypeData; +import com.squareup.javapoet.AnnotationSpec; +import com.squareup.javapoet.CodeBlock; +import com.squareup.javapoet.MethodSpec; +import com.squareup.javapoet.ParameterSpec; import com.squareup.javapoet.TypeName; import java.util.Collections; import java.util.Map; import java.util.stream.Collectors; +import javax.annotation.Nullable; +import javax.lang.model.element.Modifier; public final class FunctionResolvedType extends ResolvedType { private final Map mResolvedArgTypes; @@ -47,4 +53,70 @@ public Map getResolvedArgTypes() { public TypeName getNativeType(final NativeTypeContext typeContext) { return TypeUtils.makeNullable(ReactClassNames.REACT_CALLBACK, mNullable); } + + public MethodSpec getGeneratedMethodWithReactAnnotation(String methodName) { + TypeName resolvedReturnTypeName = + mResolvedReturnType.getNativeType(NativeTypeContext.FUNCTION_RETURN); + + boolean isReturnTypePromise = resolvedReturnTypeName == ReactClassNames.REACT_PROMISE; + TypeName returnTypeName = isReturnTypePromise ? TypeName.VOID : resolvedReturnTypeName; + + MethodSpec.Builder methodBuilder = + MethodSpec.methodBuilder(methodName).addModifiers(Modifier.PUBLIC); + methodBuilder.returns(returnTypeName); + + if (!mNullable) { + methodBuilder.addModifiers(Modifier.ABSTRACT); + } else { + String returnStatement = getFalsyReturnStatement(returnTypeName); + if (returnStatement != null) { + CodeBlock.Builder methodBody = CodeBlock.builder(); + methodBody.addStatement(returnStatement); + methodBuilder.addCode(methodBody.build()); + } + } + + mResolvedArgTypes + .entrySet() + .forEach( + e -> { + String argName = e.getKey(); + ResolvedType argResolvedType = e.getValue(); + methodBuilder.addParameter( + ParameterSpec.builder( + argResolvedType.getNativeType(NativeTypeContext.FUNCTION_ARGUMENT), + argName) + .build()); + }); + + AnnotationSpec.Builder annotationBuilder = AnnotationSpec.builder(ReactClassNames.REACT_METHOD); + + // Special case: Promise inserts additional method arg at the end. + if (isReturnTypePromise) { + methodBuilder.addParameter( + ParameterSpec.builder(ReactClassNames.REACT_PROMISE, "promise").build()); + } else if (!TypeName.VOID.equals(returnTypeName)) { + // A non-promise non-void return type means the method is synchronous. + annotationBuilder.addMember("isBlockingSynchronousMethod", "$L", true); + } + + // React methods need special `@ReactMethod` annotation for now. + methodBuilder.addAnnotation(annotationBuilder.build()); + + return methodBuilder.build(); + } + + private static @Nullable String getFalsyReturnStatement(TypeName returnType) { + if (returnType == TypeName.BOOLEAN) { + return "return false"; + } else if (returnType == TypeName.DOUBLE) { + return "return 0.0"; + } else if (returnType == ClassNames.STRING + || returnType == ReactClassNames.REACT_WRITABLE_ARRAY + || returnType == ReactClassNames.REACT_WRITABLE_MAP) { + return "return null"; + } + + return null; + } } diff --git a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/NativeModuleResolvedType.java b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/NativeModuleResolvedType.java index 001615615c5dff..0022209dbf2004 100644 --- a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/NativeModuleResolvedType.java +++ b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/NativeModuleResolvedType.java @@ -9,18 +9,26 @@ import com.facebook.react.codegen.generator.model.NativeModuleType; import com.facebook.react.codegen.generator.model.TypeData; +import com.squareup.javapoet.ClassName; +import com.squareup.javapoet.CodeBlock; import com.squareup.javapoet.MethodSpec; +import com.squareup.javapoet.ParameterSpec; +import com.squareup.javapoet.ParameterizedTypeName; import com.squareup.javapoet.TypeName; import com.squareup.javapoet.TypeSpec; +import java.util.Arrays; import java.util.Collections; +import java.util.HashSet; +import java.util.List; import java.util.Map; +import java.util.Set; import java.util.stream.Collectors; import javax.annotation.Nullable; import javax.lang.model.element.Modifier; public final class NativeModuleResolvedType extends ResolvedType { private final Map mResolvedAliasTypes; - private final Map mResolvedPropertyTypes; + private final Map mResolvedPropertyTypes; private NativeModuleResolvedType( final NativeModuleType type, final TypeData typeData, final boolean nullable) { @@ -39,7 +47,16 @@ private NativeModuleResolvedType( Collectors.toMap( item -> item.name, // TODO: Optional Object property is not necessarily nullable. - item -> resolveType(item.type, typeData, item.optional)))); + item -> { + final ResolvedType resolvedType = + resolveType(item.type, typeData, item.optional); + TypeUtils.assertCondition( + resolvedType instanceof FunctionResolvedType, + "NativeModules can only contain methods. Constants like '" + + item.name + + "' must be declared in the return type of the 'getConstants()' method."); + return (FunctionResolvedType) resolvedType; + }))); } public static NativeModuleResolvedType create( @@ -55,18 +72,189 @@ public TypeName getNativeType(final NativeTypeContext typeContext) { @Override public @Nullable TypeSpec getGeneratedCode(final String packageName) { - // TODO: Remove this placeholder implementation. - final MethodSpec main = - MethodSpec.methodBuilder("main") - .addModifiers(Modifier.PUBLIC, Modifier.STATIC) - .returns(void.class) - .addParameter(String[].class, "args") - .addStatement("$T.out.println($S)", System.class, "Hello, JavaPoet!") - .build(); - - return TypeSpec.classBuilder(mType.getTypeId().typeName) + final TypeSpec.Builder classBuilder = + TypeSpec.classBuilder(mType.getTypeId().typeName) + .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT) + .superclass(ReactClassNames.REACT_CONTEXT_BASE_JAVA_MODULE) + .addSuperinterface(ReactClassNames.REACT_MODULE_WITH_SPEC) + .addSuperinterface(ReactClassNames.REACT_TURBOMODULE); + + final MethodSpec.Builder constructorBuilder = + MethodSpec.constructorBuilder() + .addModifiers(Modifier.PUBLIC) + .addParameter( + ParameterSpec.builder(ReactClassNames.REACT_APPLICATION_CONTEXT, "reactContext") + .build()) + .addStatement("super($N)", "reactContext"); + classBuilder.addMethod(constructorBuilder.build()); + + mResolvedPropertyTypes.forEach( + (name, resolvedType) -> { + if (name.equals("getConstants")) { + classBuilder.addMethod(generateGetTypedExportedConstantsMethod()); + classBuilder.addMethod(generateGetConstantsMethod(resolvedType)); + } else { + classBuilder.addMethod( + ((FunctionResolvedType) resolvedType).getGeneratedMethodWithReactAnnotation(name)); + } + }); + + return classBuilder.build(); + } + + // For now, getConstants() needs a runtime check to ensure the object return value has the + // required properties. In the future, the method should return the specific object type that + // can be verified during build time. + private static MethodSpec generateGetConstantsMethod(final FunctionResolvedType resolvedType) { + final ResolvedType resolvedReturnType = resolvedType.getResolvedReturnType(); + TypeUtils.assertCondition( + resolvedReturnType instanceof ObjectResolvedType, + "getConstants() method must return an exact object. Found: " + resolvedType.mType); + + final ParameterizedTypeName returnType = + ParameterizedTypeName.get(ClassName.get(Map.class), ClassNames.STRING, ClassName.OBJECT); + return MethodSpec.methodBuilder("getConstants") .addModifiers(Modifier.PUBLIC, Modifier.FINAL) - .addMethod(main) + .addAnnotation(Annotations.OVERRIDE) + .returns(returnType.annotated(Annotations.NULLABLE)) + .addCode( + getConstantsMethodBody( + returnType, ((ObjectResolvedType) resolvedReturnType).getResolvedPropertyTypes())) + .build(); + } + + private static MethodSpec generateGetTypedExportedConstantsMethod() { + return MethodSpec.methodBuilder("getTypedExportedConstants") + .addModifiers(Modifier.PROTECTED, Modifier.ABSTRACT) + .returns(ClassNames.CONSTANTS_MAP) + .build(); + } + + private static CodeBlock getConstantsMethodBody( + final ParameterizedTypeName returnType, final Map constantsTypes) { + final CodeBlock.Builder methodBody = CodeBlock.builder(); + + final Map>> constantsByNullability = + constantsTypes.entrySet().stream() + .collect(Collectors.partitioningBy(entry -> entry.getValue().mNullable)); + + final String constantsVariableName = "constants"; + final String obligatoryFlowConstantsVariableName = "obligatoryFlowConstants"; + final String optionalFlowConstantsVariableName = "optionalFlowConstants"; + final TypeName setOfStringsType = + ParameterizedTypeName.get(ClassName.get(Set.class), ClassNames.STRING); + final TypeName hashsetType = ClassName.get(HashSet.class); + + methodBody.addStatement( + "$T $N = $N()", + returnType, + constantsVariableName, + generateGetTypedExportedConstantsMethod().name); + + // Enable all of this for internal (debug) builds only. + methodBody.beginControlFlow( + "if ($1T.DEBUG || $1T.IS_INTERNAL_BUILD)", ReactClassNames.REACT_BUILD_CONFIG); + { + final List obligatoryConstants = + constantsByNullability.get(false).stream() + .map(Map.Entry::getKey) + .sorted() + .collect(Collectors.toList()); + addVariableDeclaration( + methodBody, + obligatoryFlowConstantsVariableName, + obligatoryConstants, + setOfStringsType, + hashsetType); + + final List optionalConstants = + constantsByNullability.get(true).stream() + .map(Map.Entry::getKey) + .sorted() + .collect(Collectors.toList()); + addVariableDeclaration( + methodBody, + optionalFlowConstantsVariableName, + optionalConstants, + setOfStringsType, + hashsetType); + + final String undeclaredConstantsVariableName = "undeclaredConstants"; + + methodBody + .addStatement( + "$T $N = new $T<>($N.keySet())", + setOfStringsType, + undeclaredConstantsVariableName, + hashsetType, + constantsVariableName) + .addStatement( + "$N.removeAll($N)", + undeclaredConstantsVariableName, + obligatoryFlowConstantsVariableName) + .addStatement( + "$N.removeAll($N)", + undeclaredConstantsVariableName, + optionalFlowConstantsVariableName); + methodBody.add( + checkForConstantsFulfillmentBlock( + undeclaredConstantsVariableName, + "Native Module Flow doesn\'t declare constants: %s")); + + methodBody + .addStatement( + "$N = $N", undeclaredConstantsVariableName, obligatoryFlowConstantsVariableName) + .addStatement( + "$N.removeAll($N.keySet())", undeclaredConstantsVariableName, constantsVariableName); + methodBody.add( + checkForConstantsFulfillmentBlock( + undeclaredConstantsVariableName, "Native Module doesn\'t fill in constants: %s")); + } + methodBody.endControlFlow(); + methodBody.addStatement("return $N", constantsVariableName); + + return methodBody.build(); + } + + private static void addVariableDeclaration( + final CodeBlock.Builder builder, + final String variableName, + final List values, + final TypeName varType, + final TypeName actualType) { + if (values.isEmpty()) { + builder.addStatement("$T $N = new $T<>()", varType, variableName, actualType); + } else { + builder.add( + "$T $N = new $T<>($T.asList(\n", + varType, + variableName, + actualType, + ClassName.get(Arrays.class)); + builder.indent().indent(); + + int constantsToAdd = values.size(); + for (final String constantName : values) { + builder.add("\"$L\"", constantName); + if (--constantsToAdd > 0) { + builder.add(","); + } + builder.add("\n"); + } + + builder.unindent().unindent(); + builder.addStatement("))"); + } + } + + private static CodeBlock checkForConstantsFulfillmentBlock( + final String undeclaredConstantsVariableName, final String formatString) { + return CodeBlock.builder() + .beginControlFlow("if (!$N.isEmpty())", undeclaredConstantsVariableName) + .addStatement( + "throw new IllegalStateException(String.format(\"" + formatString + "\", $N))", + undeclaredConstantsVariableName) + .endControlFlow() .build(); } } diff --git a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/StringResolvedType.java b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/StringResolvedType.java index 7a24e39be6bce7..c24711171028c7 100644 --- a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/StringResolvedType.java +++ b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/StringResolvedType.java @@ -9,7 +9,6 @@ import com.facebook.react.codegen.generator.model.StringType; import com.facebook.react.codegen.generator.model.TypeData; -import com.squareup.javapoet.ClassName; import com.squareup.javapoet.TypeName; public final class StringResolvedType extends ResolvedType { @@ -25,6 +24,6 @@ public static StringResolvedType create( @Override public TypeName getNativeType(final NativeTypeContext typeContext) { - return TypeUtils.makeNullable(ClassName.get(String.class), mNullable); + return TypeUtils.makeNullable(ClassNames.STRING, mNullable); } } diff --git a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/TypeUtils.java b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/TypeUtils.java index 4c45f76889e74a..b8742b6f89e959 100644 --- a/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/TypeUtils.java +++ b/packages/react-native-codegen/android/gradlePlugin-build/gradlePlugin/src/main/java/com/facebook/react/codegen/generator/resolver/TypeUtils.java @@ -7,19 +7,13 @@ package com.facebook.react.codegen.generator.resolver; -import com.squareup.javapoet.AnnotationSpec; +import com.facebook.react.codegen.generator.model.CodegenException; import com.squareup.javapoet.ParameterizedTypeName; import com.squareup.javapoet.TypeName; import com.squareup.javapoet.TypeVariableName; -import javax.annotation.Nullable; public class TypeUtils { - public static class Annotations { - public static final AnnotationSpec OVERRIDE = AnnotationSpec.builder(Override.class).build(); - public static final AnnotationSpec NULLABLE = AnnotationSpec.builder(Nullable.class).build(); - } - public static TypeName getNativeClassName(TypeName className) { while (className instanceof ParameterizedTypeName) { className = ((ParameterizedTypeName) className).rawType; @@ -28,7 +22,7 @@ public static TypeName getNativeClassName(TypeName className) { return (className instanceof TypeVariableName) ? TypeName.OBJECT : className.box(); } - public static TypeName makeNullable(TypeName typeName, boolean isNullable) { + public static TypeName makeNullable(final TypeName typeName, final boolean isNullable) { if (isNullable) { if (typeName.isPrimitive()) { return typeName.box(); @@ -39,4 +33,11 @@ public static TypeName makeNullable(TypeName typeName, boolean isNullable) { } return typeName; } + + public static void assertCondition(final boolean condition, final String errorMessage) + throws CodegenException { + if (!condition) { + throw new CodegenException(errorMessage); + } + } } From 287cf070cb1c072bd5fdacc0b1ee3ae85c7a388e Mon Sep 17 00:00:00 2001 From: Betty Ni Date: Tue, 25 Aug 2020 12:20:39 -0700 Subject: [PATCH 0062/1238] Unbreak the build Summary: build-break overriding_review_checks_triggers_an_audit_and_retroactive_review Oncall Short Name: fbandroid_sheriff Differential Revision: D23325277 fbshipit-source-id: 20e4fb649ce8a0c8640a5ff1c5eb0ff310a4cc22 --- .../specs/NativeAccessibilityManagerSpec.java | 4 ++-- .../specs/NativeAnimatedModuleSpec.java | 20 +++++++++---------- .../specs/NativeAnimatedTurboModuleSpec.java | 20 +++++++++---------- .../fbreact/specs/NativeAppearanceSpec.java | 6 +++--- .../fbreact/specs/NativeAsyncStorageSpec.java | 8 ++++---- .../fbreact/specs/NativeBlobModuleSpec.java | 4 ++-- .../fbreact/specs/NativeDevSettingsSpec.java | 12 +++++------ .../specs/NativeExceptionsManagerSpec.java | 4 ++-- .../specs/NativeImageLoaderAndroidSpec.java | 4 ++-- .../specs/NativeImagePickerIOSSpec.java | 6 +++--- .../fbreact/specs/NativeLinkingSpec.java | 4 ++-- .../specs/NativePermissionsAndroidSpec.java | 4 ++-- .../NativePushNotificationManagerIOSSpec.java | 20 +++++++++---------- .../fbreact/specs/NativeToastAndroidSpec.java | 6 +++--- .../fbreact/specs/NativeUIManagerSpec.java | 20 +++++++++---------- .../specs/NativeWebSocketModuleSpec.java | 4 ++-- 16 files changed, 73 insertions(+), 73 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/fbreact/specs/NativeAccessibilityManagerSpec.java b/ReactAndroid/src/main/java/com/facebook/fbreact/specs/NativeAccessibilityManagerSpec.java index a25747864a695f..85eca1d044fd62 100644 --- a/ReactAndroid/src/main/java/com/facebook/fbreact/specs/NativeAccessibilityManagerSpec.java +++ b/ReactAndroid/src/main/java/com/facebook/fbreact/specs/NativeAccessibilityManagerSpec.java @@ -32,13 +32,13 @@ public NativeAccessibilityManagerSpec(ReactApplicationContext reactContext) { public abstract void getCurrentReduceTransparencyState(Callback onSuccess, Callback onError); @ReactMethod - public abstract void getCurrentInvertColorsState(Callback onSuccess, Callback onError); + public abstract void getCurrentBoldTextState(Callback onSuccess, Callback onError); @ReactMethod public abstract void getCurrentGrayscaleState(Callback onSuccess, Callback onError); @ReactMethod - public abstract void getCurrentBoldTextState(Callback onSuccess, Callback onError); + public abstract void getCurrentInvertColorsState(Callback onSuccess, Callback onError); @ReactMethod public abstract void setAccessibilityFocus(double reactTag); diff --git a/ReactAndroid/src/main/java/com/facebook/fbreact/specs/NativeAnimatedModuleSpec.java b/ReactAndroid/src/main/java/com/facebook/fbreact/specs/NativeAnimatedModuleSpec.java index 109fe5e29cdb9b..84de5093cdb20e 100644 --- a/ReactAndroid/src/main/java/com/facebook/fbreact/specs/NativeAnimatedModuleSpec.java +++ b/ReactAndroid/src/main/java/com/facebook/fbreact/specs/NativeAnimatedModuleSpec.java @@ -26,33 +26,33 @@ public NativeAnimatedModuleSpec(ReactApplicationContext reactContext) { } @ReactMethod - public abstract void dropAnimatedNode(double tag); + public abstract void connectAnimatedNodes(double parentTag, double childTag); @ReactMethod - public abstract void connectAnimatedNodes(double parentTag, double childTag); + public abstract void dropAnimatedNode(double tag); @ReactMethod public abstract void stopAnimation(double animationId); + @ReactMethod + public abstract void disconnectAnimatedNodeFromView(double nodeTag, double viewTag); + @ReactMethod public abstract void removeListeners(double count); @ReactMethod - public abstract void disconnectAnimatedNodeFromView(double nodeTag, double viewTag); + public abstract void flattenAnimatedNodeOffset(double nodeTag); @ReactMethod public abstract void removeAnimatedEventFromView(double viewTag, String eventName, double animatedNodeTag); @ReactMethod - public abstract void flattenAnimatedNodeOffset(double nodeTag); + public abstract void disconnectAnimatedNodes(double parentTag, double childTag); @ReactMethod public abstract void extractAnimatedNodeOffset(double nodeTag); - @ReactMethod - public abstract void disconnectAnimatedNodes(double parentTag, double childTag); - @ReactMethod public abstract void setAnimatedNodeValue(double nodeTag, double value); @@ -62,13 +62,13 @@ public abstract void removeAnimatedEventFromView(double viewTag, String eventNam @ReactMethod public abstract void setAnimatedNodeOffset(double nodeTag, double offset); - @ReactMethod - public abstract void restoreDefaultValues(double nodeTag); - @ReactMethod public abstract void startAnimatingNode(double animationId, double nodeTag, ReadableMap config, Callback endCallback); + @ReactMethod + public abstract void restoreDefaultValues(double nodeTag); + @ReactMethod public abstract void getValue(double tag, Callback saveValueCallback); diff --git a/ReactAndroid/src/main/java/com/facebook/fbreact/specs/NativeAnimatedTurboModuleSpec.java b/ReactAndroid/src/main/java/com/facebook/fbreact/specs/NativeAnimatedTurboModuleSpec.java index 27c614e9a3d145..64f09cae2c2365 100644 --- a/ReactAndroid/src/main/java/com/facebook/fbreact/specs/NativeAnimatedTurboModuleSpec.java +++ b/ReactAndroid/src/main/java/com/facebook/fbreact/specs/NativeAnimatedTurboModuleSpec.java @@ -26,33 +26,33 @@ public NativeAnimatedTurboModuleSpec(ReactApplicationContext reactContext) { } @ReactMethod - public abstract void dropAnimatedNode(double tag); + public abstract void connectAnimatedNodes(double parentTag, double childTag); @ReactMethod - public abstract void connectAnimatedNodes(double parentTag, double childTag); + public abstract void dropAnimatedNode(double tag); @ReactMethod public abstract void stopAnimation(double animationId); + @ReactMethod + public abstract void disconnectAnimatedNodeFromView(double nodeTag, double viewTag); + @ReactMethod public abstract void removeListeners(double count); @ReactMethod - public abstract void disconnectAnimatedNodeFromView(double nodeTag, double viewTag); + public abstract void flattenAnimatedNodeOffset(double nodeTag); @ReactMethod public abstract void removeAnimatedEventFromView(double viewTag, String eventName, double animatedNodeTag); @ReactMethod - public abstract void flattenAnimatedNodeOffset(double nodeTag); + public abstract void disconnectAnimatedNodes(double parentTag, double childTag); @ReactMethod public abstract void extractAnimatedNodeOffset(double nodeTag); - @ReactMethod - public abstract void disconnectAnimatedNodes(double parentTag, double childTag); - @ReactMethod public abstract void setAnimatedNodeValue(double nodeTag, double value); @@ -62,13 +62,13 @@ public abstract void removeAnimatedEventFromView(double viewTag, String eventNam @ReactMethod public abstract void setAnimatedNodeOffset(double nodeTag, double offset); - @ReactMethod - public abstract void restoreDefaultValues(double nodeTag); - @ReactMethod public abstract void startAnimatingNode(double animationId, double nodeTag, ReadableMap config, Callback endCallback); + @ReactMethod + public abstract void restoreDefaultValues(double nodeTag); + @ReactMethod public abstract void getValue(double tag, Callback saveValueCallback); diff --git a/ReactAndroid/src/main/java/com/facebook/fbreact/specs/NativeAppearanceSpec.java b/ReactAndroid/src/main/java/com/facebook/fbreact/specs/NativeAppearanceSpec.java index d374986b1f56ff..f3062e88c70582 100644 --- a/ReactAndroid/src/main/java/com/facebook/fbreact/specs/NativeAppearanceSpec.java +++ b/ReactAndroid/src/main/java/com/facebook/fbreact/specs/NativeAppearanceSpec.java @@ -27,11 +27,11 @@ public NativeAppearanceSpec(ReactApplicationContext reactContext) { @ReactMethod public abstract void removeListeners(double count); - @ReactMethod - public abstract void addListener(String eventName); - @ReactMethod( isBlockingSynchronousMethod = true ) public abstract @Nullable String getColorScheme(); + + @ReactMethod + public abstract void addListener(String eventName); } diff --git a/ReactAndroid/src/main/java/com/facebook/fbreact/specs/NativeAsyncStorageSpec.java b/ReactAndroid/src/main/java/com/facebook/fbreact/specs/NativeAsyncStorageSpec.java index 562e308978deb4..336a1721c423e6 100644 --- a/ReactAndroid/src/main/java/com/facebook/fbreact/specs/NativeAsyncStorageSpec.java +++ b/ReactAndroid/src/main/java/com/facebook/fbreact/specs/NativeAsyncStorageSpec.java @@ -28,18 +28,18 @@ public NativeAsyncStorageSpec(ReactApplicationContext reactContext) { @ReactMethod public abstract void multiSet(ReadableArray kvPairs, Callback callback); - @ReactMethod - public abstract void getAllKeys(Callback callback); - @ReactMethod public abstract void multiGet(ReadableArray keys, Callback callback); @ReactMethod - public abstract void clear(Callback callback); + public abstract void getAllKeys(Callback callback); @ReactMethod public abstract void multiMerge(ReadableArray kvPairs, Callback callback); + @ReactMethod + public abstract void clear(Callback callback); + @ReactMethod public abstract void multiRemove(ReadableArray keys, Callback callback); } diff --git a/ReactAndroid/src/main/java/com/facebook/fbreact/specs/NativeBlobModuleSpec.java b/ReactAndroid/src/main/java/com/facebook/fbreact/specs/NativeBlobModuleSpec.java index 774bbfd390a4ec..79afe32db09f05 100644 --- a/ReactAndroid/src/main/java/com/facebook/fbreact/specs/NativeBlobModuleSpec.java +++ b/ReactAndroid/src/main/java/com/facebook/fbreact/specs/NativeBlobModuleSpec.java @@ -38,10 +38,10 @@ public NativeBlobModuleSpec(ReactApplicationContext reactContext) { public abstract void addNetworkingHandler(); @ReactMethod - public abstract void createFromParts(ReadableArray parts, String withId); + public abstract void addWebSocketHandler(double id); @ReactMethod - public abstract void addWebSocketHandler(double id); + public abstract void createFromParts(ReadableArray parts, String withId); @ReactMethod public abstract void release(String blobId); diff --git a/ReactAndroid/src/main/java/com/facebook/fbreact/specs/NativeDevSettingsSpec.java b/ReactAndroid/src/main/java/com/facebook/fbreact/specs/NativeDevSettingsSpec.java index 77bd1cdf8deea6..3405f97b2f1ddf 100644 --- a/ReactAndroid/src/main/java/com/facebook/fbreact/specs/NativeDevSettingsSpec.java +++ b/ReactAndroid/src/main/java/com/facebook/fbreact/specs/NativeDevSettingsSpec.java @@ -31,10 +31,10 @@ public void onFastRefresh() { } @ReactMethod - public abstract void removeListeners(double count); + public abstract void reload(); @ReactMethod - public abstract void reload(); + public abstract void removeListeners(double count); @ReactMethod public abstract void setProfilingEnabled(boolean isProfilingEnabled); @@ -43,18 +43,18 @@ public void onFastRefresh() { public abstract void addMenuItem(String title); @ReactMethod - public abstract void toggleElementInspector(); + public abstract void setHotLoadingEnabled(boolean isHotLoadingEnabled); @ReactMethod - public abstract void setHotLoadingEnabled(boolean isHotLoadingEnabled); + public abstract void toggleElementInspector(); @ReactMethod public void reloadWithReason(String reason) { } @ReactMethod - public abstract void setIsShakeToShowDevMenuEnabled(boolean enabled); + public abstract void addListener(String eventName); @ReactMethod - public abstract void addListener(String eventName); + public abstract void setIsShakeToShowDevMenuEnabled(boolean enabled); } diff --git a/ReactAndroid/src/main/java/com/facebook/fbreact/specs/NativeExceptionsManagerSpec.java b/ReactAndroid/src/main/java/com/facebook/fbreact/specs/NativeExceptionsManagerSpec.java index 0e55067f682c62..e532a1ad0dd5b5 100644 --- a/ReactAndroid/src/main/java/com/facebook/fbreact/specs/NativeExceptionsManagerSpec.java +++ b/ReactAndroid/src/main/java/com/facebook/fbreact/specs/NativeExceptionsManagerSpec.java @@ -30,7 +30,7 @@ public void dismissRedbox() { } @ReactMethod - public abstract void updateExceptionMessage(String message, ReadableArray stack, + public abstract void reportFatalException(String message, ReadableArray stack, double exceptionId); @ReactMethod @@ -38,7 +38,7 @@ public void reportException(ReadableMap data) { } @ReactMethod - public abstract void reportFatalException(String message, ReadableArray stack, + public abstract void updateExceptionMessage(String message, ReadableArray stack, double exceptionId); @ReactMethod diff --git a/ReactAndroid/src/main/java/com/facebook/fbreact/specs/NativeImageLoaderAndroidSpec.java b/ReactAndroid/src/main/java/com/facebook/fbreact/specs/NativeImageLoaderAndroidSpec.java index dd045e96e64d78..c45d320f3510ff 100644 --- a/ReactAndroid/src/main/java/com/facebook/fbreact/specs/NativeImageLoaderAndroidSpec.java +++ b/ReactAndroid/src/main/java/com/facebook/fbreact/specs/NativeImageLoaderAndroidSpec.java @@ -27,10 +27,10 @@ public NativeImageLoaderAndroidSpec(ReactApplicationContext reactContext) { } @ReactMethod - public abstract void getSize(String uri, Promise promise); + public abstract void abortRequest(double requestId); @ReactMethod - public abstract void abortRequest(double requestId); + public abstract void getSize(String uri, Promise promise); @ReactMethod public abstract void prefetchImage(String uri, double requestId, Promise promise); diff --git a/ReactAndroid/src/main/java/com/facebook/fbreact/specs/NativeImagePickerIOSSpec.java b/ReactAndroid/src/main/java/com/facebook/fbreact/specs/NativeImagePickerIOSSpec.java index 4c0ac13fa0d3a5..b49706aab7edea 100644 --- a/ReactAndroid/src/main/java/com/facebook/fbreact/specs/NativeImagePickerIOSSpec.java +++ b/ReactAndroid/src/main/java/com/facebook/fbreact/specs/NativeImagePickerIOSSpec.java @@ -30,11 +30,11 @@ public abstract void openCameraDialog(ReadableMap config, Callback successCallba Callback cancelCallback); @ReactMethod - public abstract void openSelectDialog(ReadableMap config, Callback successCallback, - Callback cancelCallback); + public abstract void canUseCamera(Callback callback); @ReactMethod - public abstract void canUseCamera(Callback callback); + public abstract void openSelectDialog(ReadableMap config, Callback successCallback, + Callback cancelCallback); @ReactMethod public abstract void canRecordVideos(Callback callback); diff --git a/ReactAndroid/src/main/java/com/facebook/fbreact/specs/NativeLinkingSpec.java b/ReactAndroid/src/main/java/com/facebook/fbreact/specs/NativeLinkingSpec.java index fda26bec4a84bb..de6e7143dd22ba 100644 --- a/ReactAndroid/src/main/java/com/facebook/fbreact/specs/NativeLinkingSpec.java +++ b/ReactAndroid/src/main/java/com/facebook/fbreact/specs/NativeLinkingSpec.java @@ -26,10 +26,10 @@ public NativeLinkingSpec(ReactApplicationContext reactContext) { } @ReactMethod - public abstract void sendIntent(String action, ReadableArray extras, Promise promise); + public abstract void openURL(String url, Promise promise); @ReactMethod - public abstract void openURL(String url, Promise promise); + public abstract void sendIntent(String action, ReadableArray extras, Promise promise); @ReactMethod public abstract void removeListeners(double count); diff --git a/ReactAndroid/src/main/java/com/facebook/fbreact/specs/NativePermissionsAndroidSpec.java b/ReactAndroid/src/main/java/com/facebook/fbreact/specs/NativePermissionsAndroidSpec.java index 0c9f8adec51fd2..7a9bb302562a34 100644 --- a/ReactAndroid/src/main/java/com/facebook/fbreact/specs/NativePermissionsAndroidSpec.java +++ b/ReactAndroid/src/main/java/com/facebook/fbreact/specs/NativePermissionsAndroidSpec.java @@ -26,10 +26,10 @@ public NativePermissionsAndroidSpec(ReactApplicationContext reactContext) { } @ReactMethod - public abstract void requestPermission(String permission, Promise promise); + public abstract void checkPermission(String permission, Promise promise); @ReactMethod - public abstract void checkPermission(String permission, Promise promise); + public abstract void requestPermission(String permission, Promise promise); @ReactMethod public abstract void shouldShowRequestPermissionRationale(String permission, Promise promise); diff --git a/ReactAndroid/src/main/java/com/facebook/fbreact/specs/NativePushNotificationManagerIOSSpec.java b/ReactAndroid/src/main/java/com/facebook/fbreact/specs/NativePushNotificationManagerIOSSpec.java index a2b10ddcc259f3..30d38661fd0ebd 100644 --- a/ReactAndroid/src/main/java/com/facebook/fbreact/specs/NativePushNotificationManagerIOSSpec.java +++ b/ReactAndroid/src/main/java/com/facebook/fbreact/specs/NativePushNotificationManagerIOSSpec.java @@ -28,10 +28,10 @@ public NativePushNotificationManagerIOSSpec(ReactApplicationContext reactContext } @ReactMethod - public abstract void removeListeners(double count); + public abstract void getInitialNotification(Promise promise); @ReactMethod - public abstract void getInitialNotification(Promise promise); + public abstract void removeListeners(double count); @ReactMethod public abstract void setApplicationIconBadgeNumber(double num); @@ -40,13 +40,13 @@ public NativePushNotificationManagerIOSSpec(ReactApplicationContext reactContext public abstract void scheduleLocalNotification(ReadableMap notification); @ReactMethod - public abstract void getScheduledLocalNotifications(Callback callback); + public abstract void requestPermissions(ReadableMap permission, Promise promise); @ReactMethod public abstract void checkPermissions(Callback callback); @ReactMethod - public abstract void requestPermissions(ReadableMap permission, Promise promise); + public abstract void getScheduledLocalNotifications(Callback callback); @ReactMethod public abstract void removeAllDeliveredNotifications(); @@ -54,18 +54,18 @@ public NativePushNotificationManagerIOSSpec(ReactApplicationContext reactContext @ReactMethod public abstract void onFinishRemoteNotification(String notificationId, String fetchResult); - @ReactMethod - public abstract void cancelLocalNotifications(ReadableMap userInfo); - @ReactMethod public abstract void abandonPermissions(); @ReactMethod - public abstract void removeDeliveredNotifications(ReadableArray identifiers); + public abstract void cancelLocalNotifications(ReadableMap userInfo); @ReactMethod public abstract void cancelAllLocalNotifications(); + @ReactMethod + public abstract void removeDeliveredNotifications(ReadableArray identifiers); + @ReactMethod public abstract void getDeliveredNotifications(Callback callback); @@ -73,8 +73,8 @@ public NativePushNotificationManagerIOSSpec(ReactApplicationContext reactContext public abstract void getApplicationIconBadgeNumber(Callback callback); @ReactMethod - public abstract void addListener(String eventType); + public abstract void presentLocalNotification(ReadableMap notification); @ReactMethod - public abstract void presentLocalNotification(ReadableMap notification); + public abstract void addListener(String eventType); } diff --git a/ReactAndroid/src/main/java/com/facebook/fbreact/specs/NativeToastAndroidSpec.java b/ReactAndroid/src/main/java/com/facebook/fbreact/specs/NativeToastAndroidSpec.java index d9bf4efc8c2f02..058f5f4806eaa3 100644 --- a/ReactAndroid/src/main/java/com/facebook/fbreact/specs/NativeToastAndroidSpec.java +++ b/ReactAndroid/src/main/java/com/facebook/fbreact/specs/NativeToastAndroidSpec.java @@ -30,11 +30,11 @@ public NativeToastAndroidSpec(ReactApplicationContext reactContext) { } @ReactMethod - public abstract void showWithGravityAndOffset(String message, double duration, double gravity, - double xOffset, double yOffset); + public abstract void show(String message, double duration); @ReactMethod - public abstract void show(String message, double duration); + public abstract void showWithGravityAndOffset(String message, double duration, double gravity, + double xOffset, double yOffset); @ReactMethod public abstract void showWithGravity(String message, double duration, double gravity); diff --git a/ReactAndroid/src/main/java/com/facebook/fbreact/specs/NativeUIManagerSpec.java b/ReactAndroid/src/main/java/com/facebook/fbreact/specs/NativeUIManagerSpec.java index 03e3fe9bb0ce48..9f7f8697760fc9 100644 --- a/ReactAndroid/src/main/java/com/facebook/fbreact/specs/NativeUIManagerSpec.java +++ b/ReactAndroid/src/main/java/com/facebook/fbreact/specs/NativeUIManagerSpec.java @@ -43,10 +43,10 @@ public abstract void configureNextLayoutAnimation(ReadableMap config, Callback c Callback errorCallback); @ReactMethod - public abstract void blur(Double reactTag); + public abstract void focus(Double reactTag); @ReactMethod - public abstract void focus(Double reactTag); + public abstract void blur(Double reactTag); @ReactMethod public abstract void removeSubviewsFromContainerWithID(double containerID); @@ -54,13 +54,13 @@ public abstract void configureNextLayoutAnimation(ReadableMap config, Callback c @ReactMethod public abstract void setJSResponder(Double reactTag, boolean blockNativeResponder); - @ReactMethod - public abstract void clearJSResponder(); - @ReactMethod public abstract void measureLayout(Double reactTag, Double ancestorReactTag, Callback errorCallback, Callback callback); + @ReactMethod + public abstract void clearJSResponder(); + @ReactMethod( isBlockingSynchronousMethod = true ) @@ -77,21 +77,21 @@ public abstract void dispatchViewManagerCommand(Double reactTag, double commandI public abstract void createView(Double reactTag, String viewName, double rootTag, ReadableMap props); - @ReactMethod - public abstract void sendAccessibilityEvent(Double reactTag, double eventType); - @ReactMethod public abstract void measureInWindow(Double reactTag, Callback callback); @ReactMethod - public abstract void viewIsDescendantOf(Double reactTag, Double ancestorReactTag, - Callback callback); + public abstract void sendAccessibilityEvent(Double reactTag, double eventType); @ReactMethod( isBlockingSynchronousMethod = true ) public abstract WritableMap lazilyLoadView(String name); + @ReactMethod + public abstract void viewIsDescendantOf(Double reactTag, Double ancestorReactTag, + Callback callback); + @ReactMethod public abstract void findSubviewIn(Double reactTag, ReadableArray point, Callback callback); diff --git a/ReactAndroid/src/main/java/com/facebook/fbreact/specs/NativeWebSocketModuleSpec.java b/ReactAndroid/src/main/java/com/facebook/fbreact/specs/NativeWebSocketModuleSpec.java index 6eeddd2fe00b28..765bdd925de1d9 100644 --- a/ReactAndroid/src/main/java/com/facebook/fbreact/specs/NativeWebSocketModuleSpec.java +++ b/ReactAndroid/src/main/java/com/facebook/fbreact/specs/NativeWebSocketModuleSpec.java @@ -35,10 +35,10 @@ public NativeWebSocketModuleSpec(ReactApplicationContext reactContext) { public abstract void ping(double socketID); @ReactMethod - public abstract void close(double code, String reason, double socketID); + public abstract void send(String message, double forSocketID); @ReactMethod - public abstract void send(String message, double forSocketID); + public abstract void close(double code, String reason, double socketID); @ReactMethod public abstract void connect(String url, ReadableArray protocols, ReadableMap options, From 982272932cee3be599076bd18b290bc812285533 Mon Sep 17 00:00:00 2001 From: Tim Yung Date: Tue, 25 Aug 2020 14:12:19 -0700 Subject: [PATCH 0063/1238] RN: Remove `fbjs/warning` Dependency Summary: Replaces `fbjs/warning` call sites in React Native with `console.warn`. A few warnings will now log as warnings without the "Warning:" prefix. Changelog: [General][Changed] - Some warnings changed to use `console.warn` without the "Warning:" prefix. Reviewed By: TheSavior, cpojer Differential Revision: D22445946 fbshipit-source-id: 96b01e1bdee52b89ff3b808bc9d6cd494f6787f5 --- IntegrationTests/LoggingTestModule.js | 3 +-- .../ToastAndroid/ToastAndroid.ios.js | 8 +++----- Libraries/Core/Timers/JSTimers.js | 11 +++++----- .../Core/Timers/__tests__/JSTimers-test.js | 20 +++++++++---------- Libraries/Lists/FillRateHelper.js | 7 +++---- Libraries/Lists/VirtualizedList.js | 12 +++++------ Libraries/Network/XMLHttpRequest.js | 4 +--- .../Network/__tests__/XMLHttpRequest-test.js | 8 ++++---- .../getNativeComponentAttributes.js | 3 +-- .../Utilities/__tests__/warnOnce-test.js | 10 +++++----- Libraries/Utilities/warnOnce.js | 4 +--- .../RCTLoggingTests.m | 2 +- 12 files changed, 41 insertions(+), 51 deletions(-) diff --git a/IntegrationTests/LoggingTestModule.js b/IntegrationTests/LoggingTestModule.js index 6eab2d7337fab7..dc1dfb8ac03360 100644 --- a/IntegrationTests/LoggingTestModule.js +++ b/IntegrationTests/LoggingTestModule.js @@ -11,7 +11,6 @@ const BatchedBridge = require('react-native/Libraries/BatchedBridge/BatchedBridge'); -const warning = require('fbjs/lib/warning'); const invariant = require('invariant'); const LoggingTestModule = { @@ -24,7 +23,7 @@ const LoggingTestModule = { }, timeout_ms); }, warning: function(str) { - warning(false, str); + console.warn(str); }, invariant: function(str) { invariant(false, str); diff --git a/Libraries/Components/ToastAndroid/ToastAndroid.ios.js b/Libraries/Components/ToastAndroid/ToastAndroid.ios.js index d0528ff65dc35e..611e50fe87b5b1 100644 --- a/Libraries/Components/ToastAndroid/ToastAndroid.ios.js +++ b/Libraries/Components/ToastAndroid/ToastAndroid.ios.js @@ -10,11 +10,9 @@ 'use strict'; -const warning = require('fbjs/lib/warning'); - const ToastAndroid = { show: function(message: string, duration: number): void { - warning(false, 'ToastAndroid is not supported on this platform.'); + console.warn('ToastAndroid is not supported on this platform.'); }, showWithGravity: function( @@ -22,7 +20,7 @@ const ToastAndroid = { duration: number, gravity: number, ): void { - warning(false, 'ToastAndroid is not supported on this platform.'); + console.warn('ToastAndroid is not supported on this platform.'); }, showWithGravityAndOffset: function( @@ -32,7 +30,7 @@ const ToastAndroid = { xOffset: number, yOffset: number, ): void { - warning(false, 'ToastAndroid is not supported on this platform.'); + console.warn('ToastAndroid is not supported on this platform.'); }, }; diff --git a/Libraries/Core/Timers/JSTimers.js b/Libraries/Core/Timers/JSTimers.js index 00a25d93d9146c..9c5d2a099e3887 100644 --- a/Libraries/Core/Timers/JSTimers.js +++ b/Libraries/Core/Timers/JSTimers.js @@ -81,11 +81,12 @@ function _allocateCallback(func: Function, type: JSTimerType): number { * recurring (setInterval). */ function _callTimer(timerID: number, frameTime: number, didTimeout: ?boolean) { - require('fbjs/lib/warning')( - timerID <= GUID, - 'Tried to call timer with ID %s but no such timer exists.', - timerID, - ); + if (timerID > GUID) { + console.warn( + 'Tried to call timer with ID %s but no such timer exists.', + timerID, + ); + } // timerIndex of -1 means that no timer with that ID exists. There are // two situations when this happens, when a garbage timer ID was given diff --git a/Libraries/Core/Timers/__tests__/JSTimers-test.js b/Libraries/Core/Timers/__tests__/JSTimers-test.js index baa281f03e6bcd..46fbd0d10236fe 100644 --- a/Libraries/Core/Timers/__tests__/JSTimers-test.js +++ b/Libraries/Core/Timers/__tests__/JSTimers-test.js @@ -16,11 +16,8 @@ const NativeTiming = { setSendIdleEvents: jest.fn(), }; -const warning = jest.fn(); - jest .enableAutomock() - .mock('fbjs/lib/warning', () => warning, {virtual: true}) .mock('../NativeTiming', () => ({ __esModule: true, default: NativeTiming, @@ -30,14 +27,15 @@ jest const JSTimers = require('../JSTimers'); describe('JSTimers', function() { - const firstArgumentOfTheLastCallTo = function(func) { - return func.mock.calls[func.mock.calls.length - 1][0]; - }; - beforeEach(function() { + jest.spyOn(console, 'warn'); global.setTimeout = JSTimers.setTimeout; }); + afterEach(() => { + console.warn.mockRestore(); + }); + it('should call function with setTimeout', function() { let didCall = false; const id = JSTimers.setTimeout(function() { @@ -277,12 +275,12 @@ describe('JSTimers', function() { JSTimers.clearTimeout(timerID); JSTimers.callTimers([timerID]); expect(callback).not.toBeCalled(); - expect(firstArgumentOfTheLastCallTo(warning)).toBe(true); + expect(console.warn).not.toBeCalled(); }); it('should warn when callTimers is called with garbage timer id', function() { JSTimers.callTimers([1337]); - expect(firstArgumentOfTheLastCallTo(warning)).toBe(false); + expect(console.warn).toBeCalled(); }); it('should only call callback once for setTimeout', function() { @@ -294,7 +292,7 @@ describe('JSTimers', function() { // Second time it should be ignored JSTimers.callTimers([timerID]); expect(callback).toBeCalledTimes(1); - expect(firstArgumentOfTheLastCallTo(warning)).toBe(true); + expect(console.warn).not.toBeCalled(); }); it('should only call callback once for requestAnimationFrame', function() { @@ -306,7 +304,7 @@ describe('JSTimers', function() { // Second time it should be ignored JSTimers.callTimers([timerID]); expect(callback).toBeCalledTimes(1); - expect(firstArgumentOfTheLastCallTo(warning)).toBe(true); + expect(console.warn).not.toBeCalled(); }); it('should re-throw first exception', function() { diff --git a/Libraries/Lists/FillRateHelper.js b/Libraries/Lists/FillRateHelper.js index e9c579e656e2f2..671d61a37dc6de 100644 --- a/Libraries/Lists/FillRateHelper.js +++ b/Libraries/Lists/FillRateHelper.js @@ -59,10 +59,9 @@ class FillRateHelper { static addListener( callback: FillRateInfo => void, ): {remove: () => void, ...} { - warning( - _sampleRate !== null, - 'Call `FillRateHelper.setSampleRate` before `addListener`.', - ); + if (_sampleRate === null) { + console.warn('Call `FillRateHelper.setSampleRate` before `addListener`.'); + } _listeners.push(callback); return { remove: () => { diff --git a/Libraries/Lists/VirtualizedList.js b/Libraries/Lists/VirtualizedList.js index ee07cf321a1dee..2249d54c4aaa94 100644 --- a/Libraries/Lists/VirtualizedList.js +++ b/Libraries/Lists/VirtualizedList.js @@ -22,7 +22,6 @@ const ViewabilityHelper = require('./ViewabilityHelper'); const flattenStyle = require('../StyleSheet/flattenStyle'); const infoLog = require('../Utilities/infoLog'); const invariant = require('invariant'); -const warning = require('fbjs/lib/warning'); const {computeWindowedRenderLimits} = require('./VirtualizeUtils'); @@ -850,11 +849,12 @@ class VirtualizedList extends React.PureComponent { render(): React.Node { if (__DEV__) { const flatStyles = flattenStyle(this.props.contentContainerStyle); - warning( - flatStyles == null || flatStyles.flexWrap !== 'wrap', - '`flexWrap: `wrap`` is not supported with the `VirtualizedList` components.' + - 'Consider using `numColumns` with `FlatList` instead.', - ); + if (flatStyles != null && flatStyles.flexWrap === 'wrap') { + console.warn( + '`flexWrap: `wrap`` is not supported with the `VirtualizedList` components.' + + 'Consider using `numColumns` with `FlatList` instead.', + ); + } } const { ListEmptyComponent, diff --git a/Libraries/Network/XMLHttpRequest.js b/Libraries/Network/XMLHttpRequest.js index 7bfb0ffa35830d..27df314c5244eb 100644 --- a/Libraries/Network/XMLHttpRequest.js +++ b/Libraries/Network/XMLHttpRequest.js @@ -17,7 +17,6 @@ const RCTNetworking = require('./RCTNetworking'); const base64 = require('base64-js'); const invariant = require('invariant'); -const warning = require('fbjs/lib/warning'); const DEBUG_NETWORK_SEND_DELAY: false = false; // Set to a number of milliseconds when debugging @@ -184,8 +183,7 @@ class XMLHttpRequest extends (EventTarget(...XHR_EVENTS): any) { ); } if (!SUPPORTED_RESPONSE_TYPES.hasOwnProperty(responseType)) { - warning( - false, + console.warn( `The provided value '${responseType}' is not a valid 'responseType'.`, ); return; diff --git a/Libraries/Network/__tests__/XMLHttpRequest-test.js b/Libraries/Network/__tests__/XMLHttpRequest-test.js index 4c0f8a889176e5..f7f1bfcf32d56f 100644 --- a/Libraries/Network/__tests__/XMLHttpRequest-test.js +++ b/Libraries/Network/__tests__/XMLHttpRequest-test.js @@ -95,16 +95,16 @@ describe('XMLHttpRequest', function() { it('should expose responseType correctly', function() { expect(xhr.responseType).toBe(''); - jest.spyOn(console, 'error').mockImplementationOnce(() => {}); + jest.spyOn(console, 'warn').mockReturnValue(undefined); // Setting responseType to an unsupported value has no effect. xhr.responseType = 'arrayblobbuffertextfile'; expect(xhr.responseType).toBe(''); - expect(console.error).toBeCalledWith( - "Warning: The provided value 'arrayblobbuffertextfile' is not a valid 'responseType'.", + expect(console.warn).toBeCalledWith( + "The provided value 'arrayblobbuffertextfile' is not a valid 'responseType'.", ); - console.error.mockRestore(); + console.warn.mockRestore(); xhr.responseType = 'arraybuffer'; expect(xhr.responseType).toBe('arraybuffer'); diff --git a/Libraries/ReactNative/getNativeComponentAttributes.js b/Libraries/ReactNative/getNativeComponentAttributes.js index 226e3ba9342b42..2ec8950379d766 100644 --- a/Libraries/ReactNative/getNativeComponentAttributes.js +++ b/Libraries/ReactNative/getNativeComponentAttributes.js @@ -21,7 +21,6 @@ const processColor = require('../StyleSheet/processColor'); const processColorArray = require('../StyleSheet/processColorArray'); const resolveAssetSource = require('../Image/resolveAssetSource'); const sizesDiffer = require('../Utilities/differ/sizesDiffer'); -const warning = require('fbjs/lib/warning'); function getNativeComponentAttributes(uiViewClassName: string): any { const viewConfig = UIManager.getViewManagerConfig(uiViewClassName); @@ -39,7 +38,7 @@ function getNativeComponentAttributes(uiViewClassName: string): any { while (baseModuleName) { const baseModule = UIManager.getViewManagerConfig(baseModuleName); if (!baseModule) { - warning(false, 'Base module "%s" does not exist', baseModuleName); + console.warn('Base module "%s" does not exist', baseModuleName); baseModuleName = null; } else { bubblingEventTypes = { diff --git a/Libraries/Utilities/__tests__/warnOnce-test.js b/Libraries/Utilities/__tests__/warnOnce-test.js index ee66723c7cf517..f37d8955d5afd9 100644 --- a/Libraries/Utilities/__tests__/warnOnce-test.js +++ b/Libraries/Utilities/__tests__/warnOnce-test.js @@ -14,14 +14,14 @@ describe('warnOnce', () => { const warnOnce = require('../warnOnce'); it('logs warning messages to the console exactly once', () => { - console.error = jest.fn(); + jest.spyOn(console, 'warn').mockReturnValue(undefined); warnOnce('test-message', 'This is a log message'); warnOnce('test-message', 'This is a second log message'); - expect(console.error).toHaveBeenCalledWith( - 'Warning: This is a log message', - ); - expect(console.error).toHaveBeenCalledTimes(1); + expect(console.warn).toHaveBeenCalledWith('This is a log message'); + expect(console.warn).toHaveBeenCalledTimes(1); + + console.warn.mockRestore(); }); }); diff --git a/Libraries/Utilities/warnOnce.js b/Libraries/Utilities/warnOnce.js index adbc64ebc8598a..244cfbe59060c4 100644 --- a/Libraries/Utilities/warnOnce.js +++ b/Libraries/Utilities/warnOnce.js @@ -10,8 +10,6 @@ 'use strict'; -const warning = require('fbjs/lib/warning'); - const warnedKeys: {[string]: boolean, ...} = {}; /** @@ -26,7 +24,7 @@ function warnOnce(key: string, message: string) { return; } - warning(false, message); + console.warn(message); warnedKeys[key] = true; } diff --git a/packages/rn-tester/RNTesterIntegrationTests/RCTLoggingTests.m b/packages/rn-tester/RNTesterIntegrationTests/RCTLoggingTests.m index 9d7844fe713833..3c04e32fe1bc7b 100644 --- a/packages/rn-tester/RNTesterIntegrationTests/RCTLoggingTests.m +++ b/packages/rn-tester/RNTesterIntegrationTests/RCTLoggingTests.m @@ -83,7 +83,7 @@ - (void)testLogging XCTAssertEqual(_lastLogLevel, RCTLogLevelWarning); XCTAssertEqual(_lastLogSource, RCTLogSourceJavaScript); - XCTAssertEqualObjects(_lastLogMessage, @"Warning: Generating warning"); + XCTAssertEqualObjects(_lastLogMessage, @"Generating warning"); [_bridge enqueueJSCall:@"LoggingTestModule.invariant" args:@[@"Invariant failed"]]; dispatch_semaphore_wait(_logSem, DISPATCH_TIME_FOREVER); From 279b8e7678d36d142f1b600c0acf3416f9c24150 Mon Sep 17 00:00:00 2001 From: Tim Yung Date: Tue, 25 Aug 2020 14:12:19 -0700 Subject: [PATCH 0064/1238] RN: Remove `fbjs/requestAnimationFrame` Dependency Summary: Removes `fbjs/requestAnimationFrame` call sites from React Native. It is already available globally. Changelog: [Internal] Reviewed By: cpojer Differential Revision: D22445947 fbshipit-source-id: d85418ac055eddd15ba7de4a586de1d31445e95c --- IntegrationTests/IntegrationTestHarnessTest.js | 1 - IntegrationTests/SimpleSnapshotTest.js | 2 -- 2 files changed, 3 deletions(-) diff --git a/IntegrationTests/IntegrationTestHarnessTest.js b/IntegrationTests/IntegrationTestHarnessTest.js index 148462286d6228..fbc1ef8d472440 100644 --- a/IntegrationTests/IntegrationTestHarnessTest.js +++ b/IntegrationTests/IntegrationTestHarnessTest.js @@ -13,7 +13,6 @@ const React = require('react'); const ReactNative = require('react-native'); -const requestAnimationFrame = require('fbjs/lib/requestAnimationFrame'); const {Text, View, StyleSheet} = ReactNative; const {TestModule} = ReactNative.NativeModules; diff --git a/IntegrationTests/SimpleSnapshotTest.js b/IntegrationTests/SimpleSnapshotTest.js index db50c75e2fad69..e7d91aa4b7021d 100644 --- a/IntegrationTests/SimpleSnapshotTest.js +++ b/IntegrationTests/SimpleSnapshotTest.js @@ -13,8 +13,6 @@ const React = require('react'); const ReactNative = require('react-native'); -const requestAnimationFrame = require('fbjs/lib/requestAnimationFrame'); - const {StyleSheet, View} = ReactNative; const {TestModule} = ReactNative.NativeModules; From 9c9e677918a35e42f11ac9a824593d8239bc93c4 Mon Sep 17 00:00:00 2001 From: Tim Yung Date: Tue, 25 Aug 2020 14:12:19 -0700 Subject: [PATCH 0065/1238] RN: Remove `react-animated` Legacy Package Summary: Removes the legacy `react-animated` package configuration and collapses the `Animated/src/` directory into `Animated/`. Also, reconfigures all references to `Animated/src/` to just be `Animated/`. Changelog: [Internal] Reviewed By: cpojer Differential Revision: D22450848 fbshipit-source-id: 9fd4861e9f357d817d82e9fec71967a2936a3830 --- Libraries/Animated/{src => }/Animated.js | 2 +- Libraries/Animated/{src => }/AnimatedEvent.js | 2 +- .../{src => }/AnimatedImplementation.js | 0 Libraries/Animated/{src => }/AnimatedMock.js | 0 Libraries/Animated/{src => }/AnimatedWeb.js | 0 Libraries/Animated/{src => }/Easing.js | 0 .../{src => }/NativeAnimatedHelper.js | 4 +- .../{src => }/NativeAnimatedModule.js | 4 +- .../{src => }/NativeAnimatedTurboModule.js | 4 +- Libraries/Animated/{src => }/SpringConfig.js | 0 .../{src => }/__tests__/Animated-test.js | 8 +- .../{src => }/__tests__/AnimatedMock-test.js | 0 .../__tests__/AnimatedNative-test.js | 6 +- .../{src => }/__tests__/Easing-test.js | 0 .../{src => }/__tests__/Interpolation-test.js | 0 .../__tests__/TimingAnimation-test.js | 0 .../{src => }/__tests__/bezier-test.js | 0 .../{src => }/animations/Animation.js | 0 .../{src => }/animations/DecayAnimation.js | 0 .../{src => }/animations/SpringAnimation.js | 0 .../{src => }/animations/TimingAnimation.js | 0 Libraries/Animated/{src => }/bezier.js | 0 .../{src => }/components/AnimatedFlatList.js | 2 +- .../{src => }/components/AnimatedImage.js | 2 +- .../components/AnimatedScrollView.js | 2 +- .../components/AnimatedSectionList.js | 2 +- .../{src => }/components/AnimatedText.js | 2 +- .../{src => }/components/AnimatedView.js | 2 +- .../{src => }/createAnimatedComponent.js | 6 +- Libraries/Animated/examples/demo.html | 712 ------------------ Libraries/Animated/examples/pic1.jpg | Bin 18446 -> 0 bytes Libraries/Animated/examples/pic2.jpg | Bin 22628 -> 0 bytes Libraries/Animated/examples/pic3.jpg | Bin 20286 -> 0 bytes Libraries/Animated/examples/style.css | 88 --- .../{src => }/nodes/AnimatedAddition.js | 0 .../{src => }/nodes/AnimatedDiffClamp.js | 0 .../{src => }/nodes/AnimatedDivision.js | 0 .../{src => }/nodes/AnimatedInterpolation.js | 2 +- .../{src => }/nodes/AnimatedModulo.js | 0 .../{src => }/nodes/AnimatedMultiplication.js | 0 .../Animated/{src => }/nodes/AnimatedNode.js | 0 .../Animated/{src => }/nodes/AnimatedProps.js | 2 +- .../Animated/{src => }/nodes/AnimatedStyle.js | 2 +- .../{src => }/nodes/AnimatedSubtraction.js | 0 .../{src => }/nodes/AnimatedTracking.js | 0 .../{src => }/nodes/AnimatedTransform.js | 0 .../Animated/{src => }/nodes/AnimatedValue.js | 2 +- .../{src => }/nodes/AnimatedValueXY.js | 0 .../{src => }/nodes/AnimatedWithChildren.js | 0 .../{src => }/polyfills/InteractionManager.js | 0 Libraries/Animated/{src => }/polyfills/Set.js | 0 .../{src => }/polyfills/flattenStyle.js | 0 Libraries/Animated/release/.gitignore | 2 - Libraries/Animated/release/gulpfile.js | 155 ---- Libraries/Animated/release/package.json | 34 - Libraries/Components/ScrollView/ScrollView.js | 2 +- .../ScrollView/ScrollViewStickyHeader.js | 2 +- .../Components/Touchable/TouchableOpacity.js | 4 +- .../UI/LogBoxInspectorSourceMapStatus.js | 4 +- Libraries/StyleSheet/StyleSheetTypes.js | 2 +- index.js | 8 +- 61 files changed, 39 insertions(+), 1030 deletions(-) rename Libraries/Animated/{src => }/Animated.js (96%) rename Libraries/Animated/{src => }/AnimatedEvent.js (98%) rename Libraries/Animated/{src => }/AnimatedImplementation.js (100%) rename Libraries/Animated/{src => }/AnimatedMock.js (100%) rename Libraries/Animated/{src => }/AnimatedWeb.js (100%) rename Libraries/Animated/{src => }/Easing.js (100%) rename Libraries/Animated/{src => }/NativeAnimatedHelper.js (99%) rename Libraries/Animated/{src => }/NativeAnimatedModule.js (94%) rename Libraries/Animated/{src => }/NativeAnimatedTurboModule.js (94%) rename Libraries/Animated/{src => }/SpringConfig.js (100%) rename Libraries/Animated/{src => }/__tests__/Animated-test.js (99%) rename Libraries/Animated/{src => }/__tests__/AnimatedMock-test.js (100%) rename Libraries/Animated/{src => }/__tests__/AnimatedNative-test.js (99%) rename Libraries/Animated/{src => }/__tests__/Easing-test.js (100%) rename Libraries/Animated/{src => }/__tests__/Interpolation-test.js (100%) rename Libraries/Animated/{src => }/__tests__/TimingAnimation-test.js (100%) rename Libraries/Animated/{src => }/__tests__/bezier-test.js (100%) rename Libraries/Animated/{src => }/animations/Animation.js (100%) rename Libraries/Animated/{src => }/animations/DecayAnimation.js (100%) rename Libraries/Animated/{src => }/animations/SpringAnimation.js (100%) rename Libraries/Animated/{src => }/animations/TimingAnimation.js (100%) rename Libraries/Animated/{src => }/bezier.js (100%) rename Libraries/Animated/{src => }/components/AnimatedFlatList.js (93%) rename Libraries/Animated/{src => }/components/AnimatedImage.js (92%) rename Libraries/Animated/{src => }/components/AnimatedScrollView.js (91%) rename Libraries/Animated/{src => }/components/AnimatedSectionList.js (93%) rename Libraries/Animated/{src => }/components/AnimatedText.js (92%) rename Libraries/Animated/{src => }/components/AnimatedView.js (91%) rename Libraries/Animated/{src => }/createAnimatedComponent.js (98%) delete mode 100644 Libraries/Animated/examples/demo.html delete mode 100644 Libraries/Animated/examples/pic1.jpg delete mode 100644 Libraries/Animated/examples/pic2.jpg delete mode 100644 Libraries/Animated/examples/pic3.jpg delete mode 100644 Libraries/Animated/examples/style.css rename Libraries/Animated/{src => }/nodes/AnimatedAddition.js (100%) rename Libraries/Animated/{src => }/nodes/AnimatedDiffClamp.js (100%) rename Libraries/Animated/{src => }/nodes/AnimatedDivision.js (100%) rename Libraries/Animated/{src => }/nodes/AnimatedInterpolation.js (99%) rename Libraries/Animated/{src => }/nodes/AnimatedModulo.js (100%) rename Libraries/Animated/{src => }/nodes/AnimatedMultiplication.js (100%) rename Libraries/Animated/{src => }/nodes/AnimatedNode.js (100%) rename Libraries/Animated/{src => }/nodes/AnimatedProps.js (98%) rename Libraries/Animated/{src => }/nodes/AnimatedStyle.js (98%) rename Libraries/Animated/{src => }/nodes/AnimatedSubtraction.js (100%) rename Libraries/Animated/{src => }/nodes/AnimatedTracking.js (100%) rename Libraries/Animated/{src => }/nodes/AnimatedTransform.js (100%) rename Libraries/Animated/{src => }/nodes/AnimatedValue.js (99%) rename Libraries/Animated/{src => }/nodes/AnimatedValueXY.js (100%) rename Libraries/Animated/{src => }/nodes/AnimatedWithChildren.js (100%) rename Libraries/Animated/{src => }/polyfills/InteractionManager.js (100%) rename Libraries/Animated/{src => }/polyfills/Set.js (100%) rename Libraries/Animated/{src => }/polyfills/flattenStyle.js (100%) delete mode 100644 Libraries/Animated/release/.gitignore delete mode 100644 Libraries/Animated/release/gulpfile.js delete mode 100644 Libraries/Animated/release/package.json diff --git a/Libraries/Animated/src/Animated.js b/Libraries/Animated/Animated.js similarity index 96% rename from Libraries/Animated/src/Animated.js rename to Libraries/Animated/Animated.js index 53dd63c4709566..e7d43e650b2fe0 100644 --- a/Libraries/Animated/src/Animated.js +++ b/Libraries/Animated/Animated.js @@ -10,7 +10,7 @@ 'use strict'; -import Platform from '../../Utilities/Platform'; +import Platform from '../Utilities/Platform'; import typeof AnimatedFlatList from './components/AnimatedFlatList'; import typeof AnimatedImage from './components/AnimatedImage'; import typeof AnimatedScrollView from './components/AnimatedScrollView'; diff --git a/Libraries/Animated/src/AnimatedEvent.js b/Libraries/Animated/AnimatedEvent.js similarity index 98% rename from Libraries/Animated/src/AnimatedEvent.js rename to Libraries/Animated/AnimatedEvent.js index 91eb29ce413e29..98ff42eb197071 100644 --- a/Libraries/Animated/src/AnimatedEvent.js +++ b/Libraries/Animated/AnimatedEvent.js @@ -12,7 +12,7 @@ const AnimatedValue = require('./nodes/AnimatedValue'); const NativeAnimatedHelper = require('./NativeAnimatedHelper'); -const ReactNative = require('../../Renderer/shims/ReactNative'); +const ReactNative = require('../Renderer/shims/ReactNative'); const invariant = require('invariant'); diff --git a/Libraries/Animated/src/AnimatedImplementation.js b/Libraries/Animated/AnimatedImplementation.js similarity index 100% rename from Libraries/Animated/src/AnimatedImplementation.js rename to Libraries/Animated/AnimatedImplementation.js diff --git a/Libraries/Animated/src/AnimatedMock.js b/Libraries/Animated/AnimatedMock.js similarity index 100% rename from Libraries/Animated/src/AnimatedMock.js rename to Libraries/Animated/AnimatedMock.js diff --git a/Libraries/Animated/src/AnimatedWeb.js b/Libraries/Animated/AnimatedWeb.js similarity index 100% rename from Libraries/Animated/src/AnimatedWeb.js rename to Libraries/Animated/AnimatedWeb.js diff --git a/Libraries/Animated/src/Easing.js b/Libraries/Animated/Easing.js similarity index 100% rename from Libraries/Animated/src/Easing.js rename to Libraries/Animated/Easing.js diff --git a/Libraries/Animated/src/NativeAnimatedHelper.js b/Libraries/Animated/NativeAnimatedHelper.js similarity index 99% rename from Libraries/Animated/src/NativeAnimatedHelper.js rename to Libraries/Animated/NativeAnimatedHelper.js index 9e1b2cb400802d..653301ef5d9314 100644 --- a/Libraries/Animated/src/NativeAnimatedHelper.js +++ b/Libraries/Animated/NativeAnimatedHelper.js @@ -12,8 +12,8 @@ import NativeAnimatedNonTurboModule from './NativeAnimatedModule'; import NativeAnimatedTurboModule from './NativeAnimatedTurboModule'; -import NativeEventEmitter from '../../EventEmitter/NativeEventEmitter'; -import Platform from '../../Utilities/Platform'; +import NativeEventEmitter from '../EventEmitter/NativeEventEmitter'; +import Platform from '../Utilities/Platform'; import type {EventConfig} from './AnimatedEvent'; import type { EventMapping, diff --git a/Libraries/Animated/src/NativeAnimatedModule.js b/Libraries/Animated/NativeAnimatedModule.js similarity index 94% rename from Libraries/Animated/src/NativeAnimatedModule.js rename to Libraries/Animated/NativeAnimatedModule.js index 35367d8a0727c4..a42e7ba5b12bed 100644 --- a/Libraries/Animated/src/NativeAnimatedModule.js +++ b/Libraries/Animated/NativeAnimatedModule.js @@ -10,8 +10,8 @@ 'use strict'; -import type {TurboModule} from '../../TurboModule/RCTExport'; -import * as TurboModuleRegistry from '../../TurboModule/TurboModuleRegistry'; +import type {TurboModule} from '../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; type EndResult = {finished: boolean, ...}; type EndCallback = (result: EndResult) => void; diff --git a/Libraries/Animated/src/NativeAnimatedTurboModule.js b/Libraries/Animated/NativeAnimatedTurboModule.js similarity index 94% rename from Libraries/Animated/src/NativeAnimatedTurboModule.js rename to Libraries/Animated/NativeAnimatedTurboModule.js index 7224b2097837eb..ac6c50b45069ac 100644 --- a/Libraries/Animated/src/NativeAnimatedTurboModule.js +++ b/Libraries/Animated/NativeAnimatedTurboModule.js @@ -10,8 +10,8 @@ 'use strict'; -import type {TurboModule} from '../../TurboModule/RCTExport'; -import * as TurboModuleRegistry from '../../TurboModule/TurboModuleRegistry'; +import type {TurboModule} from '../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; type EndResult = {finished: boolean, ...}; type EndCallback = (result: EndResult) => void; diff --git a/Libraries/Animated/src/SpringConfig.js b/Libraries/Animated/SpringConfig.js similarity index 100% rename from Libraries/Animated/src/SpringConfig.js rename to Libraries/Animated/SpringConfig.js diff --git a/Libraries/Animated/src/__tests__/Animated-test.js b/Libraries/Animated/__tests__/Animated-test.js similarity index 99% rename from Libraries/Animated/src/__tests__/Animated-test.js rename to Libraries/Animated/__tests__/Animated-test.js index 061fd449925fac..aa32306b7f5985 100644 --- a/Libraries/Animated/src/__tests__/Animated-test.js +++ b/Libraries/Animated/__tests__/Animated-test.js @@ -13,7 +13,7 @@ import TestRenderer from 'react-test-renderer'; import * as React from 'react'; -jest.mock('../../../BatchedBridge/NativeModules', () => ({ +jest.mock('../../BatchedBridge/NativeModules', () => ({ NativeAnimatedModule: {}, PlatformConstants: { getConstants() { @@ -689,13 +689,13 @@ describe('Animated tests', () => { let InteractionManager; beforeEach(() => { - jest.mock('../../../Interaction/InteractionManager'); + jest.mock('../../Interaction/InteractionManager'); Animated = require('../Animated'); - InteractionManager = require('../../../Interaction/InteractionManager'); + InteractionManager = require('../../Interaction/InteractionManager'); }); afterEach(() => { - jest.unmock('../../../Interaction/InteractionManager'); + jest.unmock('../../Interaction/InteractionManager'); }); it('registers an interaction by default', () => { diff --git a/Libraries/Animated/src/__tests__/AnimatedMock-test.js b/Libraries/Animated/__tests__/AnimatedMock-test.js similarity index 100% rename from Libraries/Animated/src/__tests__/AnimatedMock-test.js rename to Libraries/Animated/__tests__/AnimatedMock-test.js diff --git a/Libraries/Animated/src/__tests__/AnimatedNative-test.js b/Libraries/Animated/__tests__/AnimatedNative-test.js similarity index 99% rename from Libraries/Animated/src/__tests__/AnimatedNative-test.js rename to Libraries/Animated/__tests__/AnimatedNative-test.js index f2de0c3d4a6fdd..ceb93dccd332fe 100644 --- a/Libraries/Animated/src/__tests__/AnimatedNative-test.js +++ b/Libraries/Animated/__tests__/AnimatedNative-test.js @@ -12,7 +12,7 @@ jest .clearAllMocks() - .mock('../../../BatchedBridge/NativeModules', () => ({ + .mock('../../BatchedBridge/NativeModules', () => ({ NativeAnimatedModule: {}, PlatformConstants: { getConstants() { @@ -21,9 +21,9 @@ jest }, })) .mock('../NativeAnimatedModule') - .mock('../../../EventEmitter/NativeEventEmitter') + .mock('../../EventEmitter/NativeEventEmitter') // findNodeHandle is imported from ReactNative so mock that whole module. - .setMock('../../../Renderer/shims/ReactNative', {findNodeHandle: () => 1}); + .setMock('../../Renderer/shims/ReactNative', {findNodeHandle: () => 1}); import TestRenderer from 'react-test-renderer'; import * as React from 'react'; diff --git a/Libraries/Animated/src/__tests__/Easing-test.js b/Libraries/Animated/__tests__/Easing-test.js similarity index 100% rename from Libraries/Animated/src/__tests__/Easing-test.js rename to Libraries/Animated/__tests__/Easing-test.js diff --git a/Libraries/Animated/src/__tests__/Interpolation-test.js b/Libraries/Animated/__tests__/Interpolation-test.js similarity index 100% rename from Libraries/Animated/src/__tests__/Interpolation-test.js rename to Libraries/Animated/__tests__/Interpolation-test.js diff --git a/Libraries/Animated/src/__tests__/TimingAnimation-test.js b/Libraries/Animated/__tests__/TimingAnimation-test.js similarity index 100% rename from Libraries/Animated/src/__tests__/TimingAnimation-test.js rename to Libraries/Animated/__tests__/TimingAnimation-test.js diff --git a/Libraries/Animated/src/__tests__/bezier-test.js b/Libraries/Animated/__tests__/bezier-test.js similarity index 100% rename from Libraries/Animated/src/__tests__/bezier-test.js rename to Libraries/Animated/__tests__/bezier-test.js diff --git a/Libraries/Animated/src/animations/Animation.js b/Libraries/Animated/animations/Animation.js similarity index 100% rename from Libraries/Animated/src/animations/Animation.js rename to Libraries/Animated/animations/Animation.js diff --git a/Libraries/Animated/src/animations/DecayAnimation.js b/Libraries/Animated/animations/DecayAnimation.js similarity index 100% rename from Libraries/Animated/src/animations/DecayAnimation.js rename to Libraries/Animated/animations/DecayAnimation.js diff --git a/Libraries/Animated/src/animations/SpringAnimation.js b/Libraries/Animated/animations/SpringAnimation.js similarity index 100% rename from Libraries/Animated/src/animations/SpringAnimation.js rename to Libraries/Animated/animations/SpringAnimation.js diff --git a/Libraries/Animated/src/animations/TimingAnimation.js b/Libraries/Animated/animations/TimingAnimation.js similarity index 100% rename from Libraries/Animated/src/animations/TimingAnimation.js rename to Libraries/Animated/animations/TimingAnimation.js diff --git a/Libraries/Animated/src/bezier.js b/Libraries/Animated/bezier.js similarity index 100% rename from Libraries/Animated/src/bezier.js rename to Libraries/Animated/bezier.js diff --git a/Libraries/Animated/src/components/AnimatedFlatList.js b/Libraries/Animated/components/AnimatedFlatList.js similarity index 93% rename from Libraries/Animated/src/components/AnimatedFlatList.js rename to Libraries/Animated/components/AnimatedFlatList.js index ca2922aaf4cd5f..64ba6c200beea0 100644 --- a/Libraries/Animated/src/components/AnimatedFlatList.js +++ b/Libraries/Animated/components/AnimatedFlatList.js @@ -12,7 +12,7 @@ import * as React from 'react'; -const FlatList = require('../../../Lists/FlatList'); +const FlatList = require('../../Lists/FlatList'); const createAnimatedComponent = require('../createAnimatedComponent'); import type {AnimatedComponentType} from '../createAnimatedComponent'; diff --git a/Libraries/Animated/src/components/AnimatedImage.js b/Libraries/Animated/components/AnimatedImage.js similarity index 92% rename from Libraries/Animated/src/components/AnimatedImage.js rename to Libraries/Animated/components/AnimatedImage.js index f5e801845f32b2..56cdb7d18f7908 100644 --- a/Libraries/Animated/src/components/AnimatedImage.js +++ b/Libraries/Animated/components/AnimatedImage.js @@ -12,7 +12,7 @@ import * as React from 'react'; -const Image = require('../../../Image/Image'); +const Image = require('../../Image/Image'); const createAnimatedComponent = require('../createAnimatedComponent'); import type {AnimatedComponentType} from '../createAnimatedComponent'; diff --git a/Libraries/Animated/src/components/AnimatedScrollView.js b/Libraries/Animated/components/AnimatedScrollView.js similarity index 91% rename from Libraries/Animated/src/components/AnimatedScrollView.js rename to Libraries/Animated/components/AnimatedScrollView.js index afed39b31cfa06..259cbb81b0ee2f 100644 --- a/Libraries/Animated/src/components/AnimatedScrollView.js +++ b/Libraries/Animated/components/AnimatedScrollView.js @@ -12,7 +12,7 @@ import * as React from 'react'; -const ScrollView = require('../../../Components/ScrollView/ScrollView'); +const ScrollView = require('../../Components/ScrollView/ScrollView'); const createAnimatedComponent = require('../createAnimatedComponent'); import type {AnimatedComponentType} from '../createAnimatedComponent'; diff --git a/Libraries/Animated/src/components/AnimatedSectionList.js b/Libraries/Animated/components/AnimatedSectionList.js similarity index 93% rename from Libraries/Animated/src/components/AnimatedSectionList.js rename to Libraries/Animated/components/AnimatedSectionList.js index 002f8a14c7646b..9beef55e879488 100644 --- a/Libraries/Animated/src/components/AnimatedSectionList.js +++ b/Libraries/Animated/components/AnimatedSectionList.js @@ -12,7 +12,7 @@ import * as React from 'react'; -const SectionList = require('../../../Lists/SectionList'); +const SectionList = require('../../Lists/SectionList'); const createAnimatedComponent = require('../createAnimatedComponent'); import type {AnimatedComponentType} from '../createAnimatedComponent'; diff --git a/Libraries/Animated/src/components/AnimatedText.js b/Libraries/Animated/components/AnimatedText.js similarity index 92% rename from Libraries/Animated/src/components/AnimatedText.js rename to Libraries/Animated/components/AnimatedText.js index 55b8fb8c42fd01..5a184e0626fe17 100644 --- a/Libraries/Animated/src/components/AnimatedText.js +++ b/Libraries/Animated/components/AnimatedText.js @@ -12,7 +12,7 @@ import * as React from 'react'; -const Text = require('../../../Text/Text'); +const Text = require('../../Text/Text'); const createAnimatedComponent = require('../createAnimatedComponent'); import type {AnimatedComponentType} from '../createAnimatedComponent'; diff --git a/Libraries/Animated/src/components/AnimatedView.js b/Libraries/Animated/components/AnimatedView.js similarity index 91% rename from Libraries/Animated/src/components/AnimatedView.js rename to Libraries/Animated/components/AnimatedView.js index 6e7badcced34d7..0ce54601fe9990 100644 --- a/Libraries/Animated/src/components/AnimatedView.js +++ b/Libraries/Animated/components/AnimatedView.js @@ -12,7 +12,7 @@ import * as React from 'react'; -const View = require('../../../Components/View/View'); +const View = require('../../Components/View/View'); const createAnimatedComponent = require('../createAnimatedComponent'); import type {AnimatedComponentType} from '../createAnimatedComponent'; diff --git a/Libraries/Animated/src/createAnimatedComponent.js b/Libraries/Animated/createAnimatedComponent.js similarity index 98% rename from Libraries/Animated/src/createAnimatedComponent.js rename to Libraries/Animated/createAnimatedComponent.js index 4b5a75566e01c3..d5dc89b7f81f8d 100644 --- a/Libraries/Animated/src/createAnimatedComponent.js +++ b/Libraries/Animated/createAnimatedComponent.js @@ -10,15 +10,15 @@ 'use strict'; -const View = require('../../Components/View/View'); -const Platform = require('../../Utilities/Platform'); +const View = require('../Components/View/View'); +const Platform = require('../Utilities/Platform'); const {AnimatedEvent} = require('./AnimatedEvent'); const AnimatedProps = require('./nodes/AnimatedProps'); const React = require('react'); const NativeAnimatedHelper = require('./NativeAnimatedHelper'); const invariant = require('invariant'); -const setAndForwardRef = require('../../Utilities/setAndForwardRef'); +const setAndForwardRef = require('../Utilities/setAndForwardRef'); let animatedComponentNextId = 1; diff --git a/Libraries/Animated/examples/demo.html b/Libraries/Animated/examples/demo.html deleted file mode 100644 index 4f95e114fa86a9..00000000000000 --- a/Libraries/Animated/examples/demo.html +++ /dev/null @@ -1,712 +0,0 @@ - - - - - - Animated - - - - - - - - - - - -
- -

Animated

-

Animations have for a long time been a weak point of the React ecosystem. The Animated library aims at solving this problem. It embraces the declarative aspect of React and obtains performance by using raw DOM manipulation behind the scenes instead of the usual diff.

- -

Animated.Value

- -

The basic building block of this library is Animated.Value. This is a variable that's going to drive the animation. You use it like a normal value in style attribute. Only animated components such as Animated.div will understand it.

- - - -

setValue

- -

As you can see, the value is being used inside of render() as you would expect. However, you don't call setState() in order to update the value. Instead, you can call setValue() directly on the value itself. We are using a form of data binding.

- -

The Animated.div component when rendered tracks which animated values it received. This way, whenever that value changes, we don't need to re-render the entire component, we can directly update the specific style attribute that changed.

- - - -

Animated.timing

- -

Now that we understand how the system works, let's play with some animations! The hello world of animations is to move the element somewhere else. To do that, we're going to animate the value from the current value 0 to the value 400.

- -

On every frame (via requestAnimationFrame), the timing animation is going to figure out the new value based on the current time, update the animated value which in turn is going to update the corresponding DOM node.

- - - -

Interrupt Animations

- -

As a developer, the mental model is that most animations are fire and forget. When the user presses the button, you want it to shrink to 80% and when she releases, you want it to go back to 100%.

- -

There are multiple challenges to implement this correctly. You need to stop the current animation, grab the current value and restart an animation from there. As this is pretty tedious to do manually, Animated will do that automatically for you.

- - - -

Animated.spring

- -

Unfortunately, the timing animation doesn't feel good. The main reason is that no matter how far you are in the animation, it will trigger a new one with always the same duration.

- -

The commonly used solution for this problem is to use the equation of a real-world spring. Imagine that you attach a spring to the target value, stretch it to the current value and let it go. The spring movement is going to be the same as the update.

- -

It turns out that this model is useful in a very wide range of animations. I highly recommend you to always start with a spring animation instead of a timing animation. It will make your interface feels much better.

- - - -

interpolate

- -

It is very common to animate multiple attributes during the same animation. The usual way to implement it is to start a separate animation for each of the attribute. The downside is that you now have to manage a different state per attribute which is not ideal.

- -

With Animated, you can use a single state variable and render it in multiple attributes. When the value is updated, all the places will reflect the change.

- -

In the following example, we're going to model the animation with a variable where 1 means fully visible and 0 means fully hidden. We can pass it directly to the scale attribute as the ranges match. But for the rotation, we need to convert [0 ; 1] range to [260deg ; 0deg]. This is where interpolate() comes handy.

- - - -

stopAnimation

- -

The reason why we can get away with not calling render() and instead modify the DOM directly on updates is because the animated values are opaque. In render, you cannot know the current value, which prevents you from being able to modify the structure of the DOM.

- -

Animated can offload the animation to a different thread (CoreAnimation, CSS transitions, main thread...) and we don't have a good way to know the real value. If you try to query the value then modify it, you are going to be out of sync and the result will look terrible.

- -

There's however one exception: when you want to stop the current animation. You need to know where it stopped in order to continue from there. We cannot know the value synchronously so we give it via a callback in stopAnimation. It will not suffer from being out of sync since the animation is no longer running.

- - - - -

Gesture-based Animations

- -

Most animations libraries only deal with time-based animations. But, as we move to mobile, a lot of animations are also gesture driven. Even more problematic, they often switch between both modes: once the gesture is over, you start a time-based animation using the same interpolations.

- -

Animated has been designed with this use case in mind. The key aspect is that there are three distinct and separate concepts: inputs, value, output. The same value can be updated either from a time-based animation or a gesture-based one. Because we use this intermediate representation for the animation, we can keep the same rendering as output.

- -

HorizontalPan

- -

The code needed to drag elements around is very messy with the DOM APIs. On mousedown, you need to register a mousemove listener on window otherwise you may drop touches if you move too fast. removeEventListener takes the same arguments as addEventListener instead of an id like clearTimeout. It's also really easy to forget to remove a listener and have a leak. And finally, you need to store the current position and value at the beginning and update only compared to it.

- -

We introduce a little helper called HorizontalPan which handles all this annoying code for us. It takes an Animated.Value as first argument and returns the event handlers required for it to work. We just have to bind this value to the left attribute and we're good to go.

- - - -

Animated.decay

- -

One of the big breakthrough of the iPhone is the fact that when you release the finger while scrolling, it will not abruptly stop but instead keep going for some time.

- -

In order to implement this effect, we are using a second real-world simulation: an object moving on an icy surface. All it needs is two values: the current velocity and a deceleration coefficient. It is implemented by Animated.decay.

- - - -

Animation Chaining

- -

The target for an animation is usually a number but sometimes it is convenient to use another value as a target. This way, the first value will track the second. Using a spring animation, we can get a nice trailing effect.

- - - -

addListener

- -

As I said earlier, if you track a spring

- - - - -

Animated.sequence

- -

It is very common to animate

- - - - - - - - - - - - - -
- - diff --git a/Libraries/Animated/examples/pic1.jpg b/Libraries/Animated/examples/pic1.jpg deleted file mode 100644 index a9f2e824fe6903b452270e3c16a14ea6f908dee7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18446 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�PA2Pc?8@jWG$7r6}14@@%=9$juRhCD5p?GG>gw zC51@}ODvQ;j~`+UZoG(~oXF-jCxfO5Wsn%%kd<|p{XQUz7vFL zB)pC5+rdJOn2TYo3m>FfpU}f?k(;3mMZG^>uf=0)LXl%!^we}|%6Ttd3m|(fY zG)4>WjNuJF#t|{O#N0MK{{Z08?WISkBxa$=Ir3=?1JfL)u!JR{a``qSgwh~PHe`mB zq8i<1*r@*i>l8Mc4T$MYt&w_y(>xCt7L&-={{ZmGLp{{IviA0A69EfRYwq^p*#DaW~*sxc79BP54SenS!*ud^7 z8z3hhiD*oZu(T8Rf(-11yo7f$c4@_*1oOn3{3w@M;N2Rt1t_xF2u@cuGYLjL){c{E z${LZ{nPDAQ*_CSsO;54TlO9(>i!4}4u)hBQK<3ZW*^S-9B@!B~kJ1;B{2LR>dNHJU z1Lz)6u5?K|ALb5aY;$vCR6vy;1&BKIS7)f~8Jh4eg$i*hVjVU(o(!9c8ha_REe4!p z)(G%Armq9QiHc?+2AUrD?CXV^+C**vu}Ms)fmAZR3RsSWHv%;CI~axi5gF4-wmYdw z`5gSzW+wU`Q)#DAzLK~g@WYrcMo(pR2b_tX!K}(D*z{y^Zxr zK8+2B5iKGqHzM$%P}>z^n2}(ULapG*tmvf0kzuWHz-CdkWX&1|>KJ98qT?u>$y6f< zNw_FAlR|%{i4bUGP-=}52?gYED@@+mTVW?pCBrx;g}`Z{DVA>pmJ&)~j1JBwE$kfa zv0=vENVPIqA7*z1%NIoKw}!=mxHUzQlr}*L>{?Vdcm4{ITVhl2&`p*h=J+sM=i-@sG&3Zz(sl5s)dryMdy tW5|bNGKuCSk{dF4@;ZlO!1>hBT&p~RJiZkLp@{Lrc^h span { - color: #333; - font-size: 13px; -} - -.example { - position: relative; - height: 60px; -} - -.code pre { - margin: 0; - font-size: 11px; - line-height: 1; -} - -.highlight { - background: rgb(228, 254, 253); -} diff --git a/Libraries/Animated/src/nodes/AnimatedAddition.js b/Libraries/Animated/nodes/AnimatedAddition.js similarity index 100% rename from Libraries/Animated/src/nodes/AnimatedAddition.js rename to Libraries/Animated/nodes/AnimatedAddition.js diff --git a/Libraries/Animated/src/nodes/AnimatedDiffClamp.js b/Libraries/Animated/nodes/AnimatedDiffClamp.js similarity index 100% rename from Libraries/Animated/src/nodes/AnimatedDiffClamp.js rename to Libraries/Animated/nodes/AnimatedDiffClamp.js diff --git a/Libraries/Animated/src/nodes/AnimatedDivision.js b/Libraries/Animated/nodes/AnimatedDivision.js similarity index 100% rename from Libraries/Animated/src/nodes/AnimatedDivision.js rename to Libraries/Animated/nodes/AnimatedDivision.js diff --git a/Libraries/Animated/src/nodes/AnimatedInterpolation.js b/Libraries/Animated/nodes/AnimatedInterpolation.js similarity index 99% rename from Libraries/Animated/src/nodes/AnimatedInterpolation.js rename to Libraries/Animated/nodes/AnimatedInterpolation.js index a32bb9c2a7c190..63dfa670f1705e 100644 --- a/Libraries/Animated/src/nodes/AnimatedInterpolation.js +++ b/Libraries/Animated/nodes/AnimatedInterpolation.js @@ -17,7 +17,7 @@ const AnimatedWithChildren = require('./AnimatedWithChildren'); const NativeAnimatedHelper = require('../NativeAnimatedHelper'); const invariant = require('invariant'); -const normalizeColor = require('../../../StyleSheet/normalizeColor'); +const normalizeColor = require('../../StyleSheet/normalizeColor'); type ExtrapolateType = 'extend' | 'identity' | 'clamp'; diff --git a/Libraries/Animated/src/nodes/AnimatedModulo.js b/Libraries/Animated/nodes/AnimatedModulo.js similarity index 100% rename from Libraries/Animated/src/nodes/AnimatedModulo.js rename to Libraries/Animated/nodes/AnimatedModulo.js diff --git a/Libraries/Animated/src/nodes/AnimatedMultiplication.js b/Libraries/Animated/nodes/AnimatedMultiplication.js similarity index 100% rename from Libraries/Animated/src/nodes/AnimatedMultiplication.js rename to Libraries/Animated/nodes/AnimatedMultiplication.js diff --git a/Libraries/Animated/src/nodes/AnimatedNode.js b/Libraries/Animated/nodes/AnimatedNode.js similarity index 100% rename from Libraries/Animated/src/nodes/AnimatedNode.js rename to Libraries/Animated/nodes/AnimatedNode.js diff --git a/Libraries/Animated/src/nodes/AnimatedProps.js b/Libraries/Animated/nodes/AnimatedProps.js similarity index 98% rename from Libraries/Animated/src/nodes/AnimatedProps.js rename to Libraries/Animated/nodes/AnimatedProps.js index be630133f1a471..578ed6718d213f 100644 --- a/Libraries/Animated/src/nodes/AnimatedProps.js +++ b/Libraries/Animated/nodes/AnimatedProps.js @@ -14,7 +14,7 @@ const {AnimatedEvent} = require('../AnimatedEvent'); const AnimatedNode = require('./AnimatedNode'); const AnimatedStyle = require('./AnimatedStyle'); const NativeAnimatedHelper = require('../NativeAnimatedHelper'); -const ReactNative = require('../../../Renderer/shims/ReactNative'); +const ReactNative = require('../../Renderer/shims/ReactNative'); const invariant = require('invariant'); diff --git a/Libraries/Animated/src/nodes/AnimatedStyle.js b/Libraries/Animated/nodes/AnimatedStyle.js similarity index 98% rename from Libraries/Animated/src/nodes/AnimatedStyle.js rename to Libraries/Animated/nodes/AnimatedStyle.js index a9405edd38e0c3..6ccd56263a799d 100644 --- a/Libraries/Animated/src/nodes/AnimatedStyle.js +++ b/Libraries/Animated/nodes/AnimatedStyle.js @@ -15,7 +15,7 @@ const AnimatedTransform = require('./AnimatedTransform'); const AnimatedWithChildren = require('./AnimatedWithChildren'); const NativeAnimatedHelper = require('../NativeAnimatedHelper'); -const flattenStyle = require('../../../StyleSheet/flattenStyle'); +const flattenStyle = require('../../StyleSheet/flattenStyle'); class AnimatedStyle extends AnimatedWithChildren { _style: Object; diff --git a/Libraries/Animated/src/nodes/AnimatedSubtraction.js b/Libraries/Animated/nodes/AnimatedSubtraction.js similarity index 100% rename from Libraries/Animated/src/nodes/AnimatedSubtraction.js rename to Libraries/Animated/nodes/AnimatedSubtraction.js diff --git a/Libraries/Animated/src/nodes/AnimatedTracking.js b/Libraries/Animated/nodes/AnimatedTracking.js similarity index 100% rename from Libraries/Animated/src/nodes/AnimatedTracking.js rename to Libraries/Animated/nodes/AnimatedTracking.js diff --git a/Libraries/Animated/src/nodes/AnimatedTransform.js b/Libraries/Animated/nodes/AnimatedTransform.js similarity index 100% rename from Libraries/Animated/src/nodes/AnimatedTransform.js rename to Libraries/Animated/nodes/AnimatedTransform.js diff --git a/Libraries/Animated/src/nodes/AnimatedValue.js b/Libraries/Animated/nodes/AnimatedValue.js similarity index 99% rename from Libraries/Animated/src/nodes/AnimatedValue.js rename to Libraries/Animated/nodes/AnimatedValue.js index 3528e2fdbe1b0a..b9d757e1026d9e 100644 --- a/Libraries/Animated/src/nodes/AnimatedValue.js +++ b/Libraries/Animated/nodes/AnimatedValue.js @@ -12,7 +12,7 @@ const AnimatedInterpolation = require('./AnimatedInterpolation'); const AnimatedWithChildren = require('./AnimatedWithChildren'); -const InteractionManager = require('../../../Interaction/InteractionManager'); +const InteractionManager = require('../../Interaction/InteractionManager'); const NativeAnimatedHelper = require('../NativeAnimatedHelper'); import type Animation, {EndCallback} from '../animations/Animation'; diff --git a/Libraries/Animated/src/nodes/AnimatedValueXY.js b/Libraries/Animated/nodes/AnimatedValueXY.js similarity index 100% rename from Libraries/Animated/src/nodes/AnimatedValueXY.js rename to Libraries/Animated/nodes/AnimatedValueXY.js diff --git a/Libraries/Animated/src/nodes/AnimatedWithChildren.js b/Libraries/Animated/nodes/AnimatedWithChildren.js similarity index 100% rename from Libraries/Animated/src/nodes/AnimatedWithChildren.js rename to Libraries/Animated/nodes/AnimatedWithChildren.js diff --git a/Libraries/Animated/src/polyfills/InteractionManager.js b/Libraries/Animated/polyfills/InteractionManager.js similarity index 100% rename from Libraries/Animated/src/polyfills/InteractionManager.js rename to Libraries/Animated/polyfills/InteractionManager.js diff --git a/Libraries/Animated/src/polyfills/Set.js b/Libraries/Animated/polyfills/Set.js similarity index 100% rename from Libraries/Animated/src/polyfills/Set.js rename to Libraries/Animated/polyfills/Set.js diff --git a/Libraries/Animated/src/polyfills/flattenStyle.js b/Libraries/Animated/polyfills/flattenStyle.js similarity index 100% rename from Libraries/Animated/src/polyfills/flattenStyle.js rename to Libraries/Animated/polyfills/flattenStyle.js diff --git a/Libraries/Animated/release/.gitignore b/Libraries/Animated/release/.gitignore deleted file mode 100644 index 3d2bc62692c4b0..00000000000000 --- a/Libraries/Animated/release/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/dist/ -/node_modules/ diff --git a/Libraries/Animated/release/gulpfile.js b/Libraries/Animated/release/gulpfile.js deleted file mode 100644 index 291f3236303d87..00000000000000 --- a/Libraries/Animated/release/gulpfile.js +++ /dev/null @@ -1,155 +0,0 @@ -/** - * 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. - * - * @format - */ - -'use strict'; - -var babel = require('gulp-babel'); -var babelPluginDEV = require('fbjs-scripts/babel/dev-expression'); -var babelPluginModules = require('fbjs-scripts/babel/rewrite-modules'); -var del = require('del'); -var derequire = require('gulp-derequire'); -var flatten = require('gulp-flatten'); -var gulp = require('gulp'); -var gulpUtil = require('gulp-util'); -var header = require('gulp-header'); -var objectAssign = require('object-assign'); -var runSequence = require('run-sequence'); -var webpackStream = require('webpack-stream'); - -var DEVELOPMENT_HEADER = - ['/**', ' * Animated v<%= version %>', ' */'].join('\n') + '\n'; -var PRODUCTION_HEADER = - [ - '/**', - ' * Animated v<%= version %>', - ' *', - ' * Copyright (c) 2013-present, Facebook, Inc.', - ' *', - ' * This source code is licensed under the MIT license found in the', - ' * LICENSE file in the root directory of this source tree.', - ' */', - ].join('\n') + '\n'; - -var babelOpts = { - nonStandard: true, - loose: ['es6.classes'], - stage: 1, - plugins: [babelPluginDEV, babelPluginModules], - _moduleMap: objectAssign({}, require('fbjs/module-map'), { - React: 'react', - }), -}; - -var buildDist = function(opts) { - var webpackOpts = { - debug: opts.debug, - externals: { - react: 'React', - }, - module: { - loaders: [{test: /\.js$/, loader: 'babel'}], - }, - output: { - filename: opts.output, - library: 'Animated', - }, - plugins: [ - new webpackStream.webpack.DefinePlugin({ - 'process.env.NODE_ENV': JSON.stringify( - opts.debug ? 'development' : 'production', - ), - }), - new webpackStream.webpack.optimize.OccurenceOrderPlugin(), - new webpackStream.webpack.optimize.DedupePlugin(), - ], - }; - if (!opts.debug) { - webpackOpts.plugins.push( - new webpackStream.webpack.optimize.UglifyJsPlugin({ - compress: { - hoist_vars: true, - screw_ie8: true, - warnings: false, - }, - }), - ); - } - return webpackStream(webpackOpts, null, function(err, stats) { - if (err) { - throw new gulpUtil.PluginError('webpack', err); - } - if (stats.compilation.errors.length) { - throw new gulpUtil.PluginError('webpack', stats.toString()); - } - }); -}; - -var paths = { - dist: 'dist', - entry: 'lib/AnimatedWeb.js', - lib: 'lib', - src: [ - '*src/**/*.js', - '!src/**/__tests__/**/*.js', - '!src/**/__mocks__/**/*.js', - ], -}; - -gulp.task('clean', function(cb) { - del([paths.dist, paths.lib], cb); -}); - -gulp.task('modules', function() { - return gulp - .src(paths.src, {cwd: '../'}) - .pipe(babel(babelOpts)) - .pipe(flatten()) - .pipe(gulp.dest(paths.lib)); -}); - -gulp.task('dist', ['modules'], function() { - var distOpts = { - debug: true, - output: 'animated.js', - }; - return gulp - .src(paths.entry) - .pipe(buildDist(distOpts)) - .pipe(derequire()) - .pipe( - header(DEVELOPMENT_HEADER, { - version: process.env.npm_package_version, - }), - ) - .pipe(gulp.dest(paths.dist)); -}); - -gulp.task('dist:min', ['modules'], function() { - var distOpts = { - debug: false, - output: 'animated.min.js', - }; - return gulp - .src(paths.entry) - .pipe(buildDist(distOpts)) - .pipe( - header(PRODUCTION_HEADER, { - version: process.env.npm_package_version, - }), - ) - .pipe(gulp.dest(paths.dist)); -}); - -gulp.task('watch', function() { - gulp.watch(paths.src, ['modules']); -}); - -gulp.task('default', function(cb) { - runSequence('clean', 'modules', ['dist', 'dist:min'], cb); -}); diff --git a/Libraries/Animated/release/package.json b/Libraries/Animated/release/package.json deleted file mode 100644 index ec7fec05fd599f..00000000000000 --- a/Libraries/Animated/release/package.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "name": "react-animated", - "description": "Animated provides powerful mechanisms for animating your React views", - "version": "0.1.0", - "keywords": [ - "react", - "animated", - "animation" - ], - "license": "MIT", - "main": "Animated.js", - "dependencies": { - "fbjs": "^1.0.0" - }, - "scripts": { - "build": "gulp" - }, - "devDependencies": { - "babel-core": "^5.8.25", - "babel-loader": "^5.3.2", - "del": "^1.2.0", - "fbjs-scripts": "^1.1.0", - "gulp": "^3.9.0", - "gulp-babel": "^5.1.0", - "gulp-derequire": "^2.1.0", - "gulp-flatten": "^0.1.0", - "gulp-header": "^1.2.2", - "gulp-util": "^3.0.6", - "object-assign": "^3.0.0", - "run-sequence": "^1.1.2", - "webpack": "1.11.0", - "webpack-stream": "^2.1.0" - } -} diff --git a/Libraries/Components/ScrollView/ScrollView.js b/Libraries/Components/ScrollView/ScrollView.js index c6a90fb05fd18a..4da263df2e56a6 100644 --- a/Libraries/Components/ScrollView/ScrollView.js +++ b/Libraries/Components/ScrollView/ScrollView.js @@ -10,7 +10,7 @@ 'use strict'; -import AnimatedImplementation from '../../Animated/src/AnimatedImplementation'; +import AnimatedImplementation from '../../Animated/AnimatedImplementation'; import Platform from '../../Utilities/Platform'; import * as React from 'react'; import ReactNative from '../../Renderer/shims/ReactNative'; diff --git a/Libraries/Components/ScrollView/ScrollViewStickyHeader.js b/Libraries/Components/ScrollView/ScrollViewStickyHeader.js index 2ee76a40c0a8bf..3bafcabcdb5c7d 100644 --- a/Libraries/Components/ScrollView/ScrollViewStickyHeader.js +++ b/Libraries/Components/ScrollView/ScrollViewStickyHeader.js @@ -10,7 +10,7 @@ 'use strict'; -import AnimatedImplementation from '../../Animated/src/AnimatedImplementation'; +import AnimatedImplementation from '../../Animated/AnimatedImplementation'; import * as React from 'react'; import StyleSheet from '../../StyleSheet/StyleSheet'; import View from '../View/View'; diff --git a/Libraries/Components/Touchable/TouchableOpacity.js b/Libraries/Components/Touchable/TouchableOpacity.js index a621a7192d41a8..f1d09510e03cb8 100644 --- a/Libraries/Components/Touchable/TouchableOpacity.js +++ b/Libraries/Components/Touchable/TouchableOpacity.js @@ -16,8 +16,8 @@ import Pressability, { import {PressabilityDebugView} from '../../Pressability/PressabilityDebug'; import TVTouchable from './TVTouchable'; import typeof TouchableWithoutFeedback from './TouchableWithoutFeedback'; -import Animated from 'react-native/Libraries/Animated/src/Animated'; -import Easing from 'react-native/Libraries/Animated/src/Easing'; +import Animated from 'react-native/Libraries/Animated/Animated'; +import Easing from 'react-native/Libraries/Animated/Easing'; import type {ViewStyleProp} from 'react-native/Libraries/StyleSheet/StyleSheet'; import flattenStyle from 'react-native/Libraries/StyleSheet/flattenStyle'; import Platform from '../../Utilities/Platform'; diff --git a/Libraries/LogBox/UI/LogBoxInspectorSourceMapStatus.js b/Libraries/LogBox/UI/LogBoxInspectorSourceMapStatus.js index 3ca8ebfcd9e105..4327ac8e0681c2 100644 --- a/Libraries/LogBox/UI/LogBoxInspectorSourceMapStatus.js +++ b/Libraries/LogBox/UI/LogBoxInspectorSourceMapStatus.js @@ -10,8 +10,8 @@ 'use strict'; -import Animated from '../../Animated/src/Animated'; -import Easing from '../../Animated/src/Easing'; +import Animated from '../../Animated/Animated'; +import Easing from '../../Animated/Easing'; import * as React from 'react'; import StyleSheet from '../../StyleSheet/StyleSheet'; import Text from '../../Text/Text'; diff --git a/Libraries/StyleSheet/StyleSheetTypes.js b/Libraries/StyleSheet/StyleSheetTypes.js index d92728984483dd..95ed2b8a2cced7 100644 --- a/Libraries/StyleSheet/StyleSheetTypes.js +++ b/Libraries/StyleSheet/StyleSheetTypes.js @@ -10,7 +10,7 @@ 'use strict'; -const AnimatedNode = require('../Animated/src/nodes/AnimatedNode'); +const AnimatedNode = require('../Animated/nodes/AnimatedNode'); import type {NativeColorValue} from './PlatformColorValueTypes'; diff --git a/index.js b/index.js index dbac8b116b1a38..43a866ff770862 100644 --- a/index.js +++ b/index.js @@ -47,7 +47,7 @@ import typeof VirtualizedList from './Libraries/Lists/VirtualizedList'; import typeof VirtualizedSectionList from './Libraries/Lists/VirtualizedSectionList'; import typeof ActionSheetIOS from './Libraries/ActionSheetIOS/ActionSheetIOS'; import typeof Alert from './Libraries/Alert/Alert'; -import typeof Animated from './Libraries/Animated/src/Animated'; +import typeof Animated from './Libraries/Animated/Animated'; import typeof Appearance from './Libraries/Utilities/Appearance'; import typeof AppRegistry from './Libraries/ReactNative/AppRegistry'; import typeof AppState from './Libraries/AppState/AppState'; @@ -58,7 +58,7 @@ import typeof DatePickerAndroid from './Libraries/Components/DatePickerAndroid/D import typeof DeviceInfo from './Libraries/Utilities/DeviceInfo'; import typeof DevSettings from './Libraries/Utilities/DevSettings'; import typeof Dimensions from './Libraries/Utilities/Dimensions'; -import typeof Easing from './Libraries/Animated/src/Easing'; +import typeof Easing from './Libraries/Animated/Easing'; import typeof ReactNative from './Libraries/Renderer/shims/ReactNative'; import typeof I18nManager from './Libraries/ReactNative/I18nManager'; import typeof ImagePickerIOS from './Libraries/Image/ImagePickerIOS'; @@ -278,7 +278,7 @@ module.exports = { return require('./Libraries/Alert/Alert'); }, get Animated(): Animated { - return require('./Libraries/Animated/src/Animated'); + return require('./Libraries/Animated/Animated'); }, get Appearance(): Appearance { return require('./Libraries/Utilities/Appearance'); @@ -330,7 +330,7 @@ module.exports = { return require('./Libraries/Utilities/Dimensions'); }, get Easing(): Easing { - return require('./Libraries/Animated/src/Easing'); + return require('./Libraries/Animated/Easing'); }, get findNodeHandle(): $PropertyType { return require('./Libraries/Renderer/shims/ReactNative').findNodeHandle; From 206ea36253146727b5c858ddf37d7ec2fb2e12ef Mon Sep 17 00:00:00 2001 From: Tim Yung Date: Tue, 25 Aug 2020 14:12:19 -0700 Subject: [PATCH 0066/1238] RN: Delete `Animated/polyfills` Summary: Deletes `Animated/polyfills` which is no longer necessary (and only creates extra configuration burden). Changelog: [Internal] Reviewed By: cpojer Differential Revision: D22451963 fbshipit-source-id: 7a9a48b96b3783f2f6340226bdafd2eaa43f32e7 --- .../Animated/polyfills/InteractionManager.js | 15 ----------- Libraries/Animated/polyfills/Set.js | 26 ------------------- Libraries/Animated/polyfills/flattenStyle.js | 13 ---------- 3 files changed, 54 deletions(-) delete mode 100644 Libraries/Animated/polyfills/InteractionManager.js delete mode 100644 Libraries/Animated/polyfills/Set.js delete mode 100644 Libraries/Animated/polyfills/flattenStyle.js diff --git a/Libraries/Animated/polyfills/InteractionManager.js b/Libraries/Animated/polyfills/InteractionManager.js deleted file mode 100644 index c2247c762a3da0..00000000000000 --- a/Libraries/Animated/polyfills/InteractionManager.js +++ /dev/null @@ -1,15 +0,0 @@ -/** - * 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. - * - * @format - */ - -'use strict'; - -module.exports = { - createInteractionHandle: function() {}, - clearInteractionHandle: function() {}, -}; diff --git a/Libraries/Animated/polyfills/Set.js b/Libraries/Animated/polyfills/Set.js deleted file mode 100644 index 39205b8f9f9920..00000000000000 --- a/Libraries/Animated/polyfills/Set.js +++ /dev/null @@ -1,26 +0,0 @@ -/** - * 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. - * - * @format - */ - -'use strict'; - -function SetPolyfill() { - this._cache = []; -} - -SetPolyfill.prototype.add = function(e) { - if (this._cache.indexOf(e) === -1) { - this._cache.push(e); - } -}; - -SetPolyfill.prototype.forEach = function(cb) { - this._cache.forEach(cb); -}; - -module.exports = SetPolyfill; diff --git a/Libraries/Animated/polyfills/flattenStyle.js b/Libraries/Animated/polyfills/flattenStyle.js deleted file mode 100644 index b50057af28435f..00000000000000 --- a/Libraries/Animated/polyfills/flattenStyle.js +++ /dev/null @@ -1,13 +0,0 @@ -/** - * 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. - * - * @format - */ - -'use strict'; -module.exports = function(style) { - return style; -}; From 19cd630f044a57f3ed652494313dece32aca1e89 Mon Sep 17 00:00:00 2001 From: Samuel Susla Date: Tue, 25 Aug 2020 14:46:18 -0700 Subject: [PATCH 0067/1238] Clone node with state in yogaNodeCloneCallbackConnector Summary: Changelog: [Internal] Reviewed By: shergin Differential Revision: D23317682 fbshipit-source-id: c273804efbe48143dcecd7c62c4edced0a746bc6 --- .../renderer/components/view/YogaLayoutableShadowNode.cpp | 4 +++- ReactCommon/react/renderer/core/ConcreteShadowNode.h | 1 - .../react/renderer/core/tests/ConcreteShadowNodeTest.cpp | 5 +++++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/ReactCommon/react/renderer/components/view/YogaLayoutableShadowNode.cpp b/ReactCommon/react/renderer/components/view/YogaLayoutableShadowNode.cpp index cc783e2824ab13..11352bb9d23b66 100644 --- a/ReactCommon/react/renderer/components/view/YogaLayoutableShadowNode.cpp +++ b/ReactCommon/react/renderer/components/view/YogaLayoutableShadowNode.cpp @@ -445,7 +445,9 @@ YGNode *YogaLayoutableShadowNode::yogaNodeCloneCallbackConnector( auto oldNode = static_cast(oldYogaNode->getContext()); - auto clonedNode = oldNode->clone({}); + auto clonedNode = oldNode->clone({ShadowNodeFragment::propsPlaceholder(), + ShadowNodeFragment::childrenPlaceholder(), + oldNode->getState()}); parentNode->replaceChild(*oldNode, clonedNode, childIndex); return &static_cast(*clonedNode).yogaNode_; } diff --git a/ReactCommon/react/renderer/core/ConcreteShadowNode.h b/ReactCommon/react/renderer/core/ConcreteShadowNode.h index e2c601a8858a1d..e6b842f3c820b9 100644 --- a/ReactCommon/react/renderer/core/ConcreteShadowNode.h +++ b/ReactCommon/react/renderer/core/ConcreteShadowNode.h @@ -134,7 +134,6 @@ class ConcreteShadowNode : public BaseShadowNodeT { Sealable::ensureUnsealed(); state_ = std::make_shared( std::make_shared(std::move(data)), *state_); - BaseShadowNodeT::getFamily().setMostRecentState(state_); } }; diff --git a/ReactCommon/react/renderer/core/tests/ConcreteShadowNodeTest.cpp b/ReactCommon/react/renderer/core/tests/ConcreteShadowNodeTest.cpp index 44d2ad76783c8d..de48a4b6e7b566 100644 --- a/ReactCommon/react/renderer/core/tests/ConcreteShadowNodeTest.cpp +++ b/ReactCommon/react/renderer/core/tests/ConcreteShadowNodeTest.cpp @@ -28,6 +28,11 @@ TEST(ConcreteShadowNodeTest, testSetStateData) { shadowNode->setStateData({{10, 11}, {{21, 22}, {301, 302}}}); + EXPECT_NE( + shadowNode->getState(), shadowNode->getFamily().getMostRecentState()); + + shadowNode->setMounted(true); + EXPECT_EQ( shadowNode->getState(), shadowNode->getFamily().getMostRecentState()); From 9b973f32e4d81713a10a186e42ee57d6e1d414d3 Mon Sep 17 00:00:00 2001 From: Samuel Susla Date: Tue, 25 Aug 2020 15:39:55 -0700 Subject: [PATCH 0068/1238] Fix TextInput value not restoring after reuse Summary: Changelog: [Internal] # Problem The problem was setting `_backedTextInputView.attributedText` to nil inside `[RCTTextInputComponentView prepareForRecycle]`. Ordinarily this isn't a problem becase `UIManager::updateState` drops the update if the ShadowNode no longer exists. But in certain cases the ShadowNode can exist, empty string being set as its value # Fix Fix is trivial, invalidate state before nullifying `_backedTextInputView`. This prevents the state update from being dispatched. # Discussion We should go over all other components and make sure state is invalidated as first thing in `[RCTViewComponentView prepareForRecycle]`. Reviewed By: shergin Differential Revision: D23324929 fbshipit-source-id: 9568e920d99683ad95f965ef4b63c529f50f3283 --- .../ComponentViews/TextInput/RCTTextInputComponentView.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm b/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm index 6652b065b03770..013226237a6436 100644 --- a/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm +++ b/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm @@ -249,9 +249,9 @@ - (void)updateLayoutMetrics:(LayoutMetrics const &)layoutMetrics - (void)prepareForRecycle { [super prepareForRecycle]; + _stateTeller.invalidate(); _backedTextInputView.attributedText = nil; _mostRecentEventCount = 0; - _stateTeller.invalidate(); _comingFromJS = NO; _lastStringStateWasUpdatedWith = nil; _ignoreNextTextInputCall = NO; From 1270873ed65ae32596c3094a3a9e165bb61c5ce1 Mon Sep 17 00:00:00 2001 From: Ankit Tiwari Date: Tue, 25 Aug 2020 19:27:39 -0700 Subject: [PATCH 0069/1238] RNTester UI Redesign (#29685) Summary: This Pull request adds the UI changes to the RNTester app as discussed in the MLH Fellowship. This list is not exhaustive. - The initial App screen is redesigned. - A bottom Navbar has been added. - Filter pills are added. - The list card UI is updated. - The example page UI is updated. - Recently Viewed Sections are added. It shows the last 5 recently viewed components/APIs. - Bookmarking functionality is added. - The documentation URL is added to the example page. - RNTester doesn't lose its state on a hard refresh (even on iOS). Pull Request resolved: https://github.com/facebook/react-native/pull/29685 Test Plan: Imported from GitHub, without a `Test Plan:` line. {F302717939} Note: this failed **before** this diff too: {F302745716} Reviewed By: mdvacca, cpojer Differential Revision: D23240434 fbshipit-source-id: 65e2766a6a097eca0e0d0fda8dadf6871e9276c2 Co-authored-by: agarwalmanya Co-authored-by: chirag-singhal Co-authored-by: Ansh Godha Co-authored-by: Yash Kumar Verma Co-authored-by: Sanskar Jethi Co-authored-by: Aniketh Saha Co-authored-by: Xtremilicious Co-authored-by: Jani Evakallio --- .../rn-tester/e2e/__tests__/Button-test.js | 4 +- .../e2e/__tests__/DatePickerIOS-test.js | 4 +- .../rn-tester/e2e/__tests__/Picker-test.js | 4 +- .../rn-tester/e2e/__tests__/TextInput-test.js | 2 +- .../rn-tester/e2e/__tests__/Touchable-test.js | 4 +- packages/rn-tester/e2e/test-init.js | 2 +- packages/rn-tester/js/RNTesterApp.android.js | 282 ++++++------- packages/rn-tester/js/RNTesterApp.ios.js | 183 +++++++-- .../rn-tester/js/assets/bookmark-filled.png | Bin 0 -> 217 bytes .../js/assets/bookmark-outline-blue.png | Bin 0 -> 1034 bytes .../js/assets/bookmark-outline-gray.png | Bin 0 -> 1076 bytes .../rn-tester/js/assets/bookmark-outline.png | Bin 0 -> 260 bytes .../js/assets/bottom-nav-apis-icon-active.png | Bin 0 -> 1870 bytes .../assets/bottom-nav-apis-icon-inactive.png | Bin 0 -> 1953 bytes .../js/assets/bottom-nav-bookmark-fill.png | Bin 0 -> 768 bytes .../js/assets/bottom-nav-bookmark-outline.png | Bin 0 -> 929 bytes .../js/assets/bottom-nav-center-box.png | Bin 0 -> 1340 bytes .../bottom-nav-components-icon-active.png | Bin 0 -> 1047 bytes .../bottom-nav-components-icon-inactive.png | Bin 0 -> 1026 bytes .../rn-tester/js/assets/documentation.png | Bin 0 -> 314 bytes packages/rn-tester/js/assets/empty.png | Bin 0 -> 22827 bytes .../js/assets/header-back-button.png | Bin 0 -> 446 bytes packages/rn-tester/js/assets/search-icon.png | Bin 0 -> 1728 bytes .../rn-tester/js/components/ExamplePage.js | 100 +++++ .../rn-tester/js/components/RNTesterBlock.js | 102 ++--- .../js/components/RNTesterBookmark.js | 38 ++ .../js/components/RNTesterBookmarkButton.js | 62 +++ .../js/components/RNTesterComponentTitle.js | 45 ++ .../js/components/RNTesterDocumentationURL.js | 39 ++ .../js/components/RNTesterExampleContainer.js | 38 +- .../js/components/RNTesterExampleFilter.js | 150 +++++-- .../js/components/RNTesterExampleList.js | 386 +++++++++++++++--- .../js/components/RNTesterListFilters.js | 94 +++++ .../rn-tester/js/components/RNTesterNavbar.js | 194 +++++++++ .../rn-tester/js/components/RNTesterTheme.js | 6 + .../rn-tester/js/components/TextLegend.js | 3 +- packages/rn-tester/js/components/UseCase.js | 40 ++ .../Accessibility/AccessibilityExample.js | 1 + .../ActionSheetIOS/ActionSheetIOSExample.js | 1 + .../ActivityIndicatorExample.js | 4 +- .../js/examples/Alert/AlertExample.js | 1 + .../js/examples/Animated/AnimatedExample.js | 2 + .../js/examples/AppState/AppStateExample.js | 2 + .../examples/Appearance/AppearanceExample.js | 2 + .../AsyncStorage/AsyncStorageExample.js | 103 ----- .../js/examples/Border/BorderExample.js | 1 + .../js/examples/BoxShadow/BoxShadowExample.js | 1 + .../js/examples/Button/ButtonExample.js | 4 +- .../js/examples/Clipboard/ClipboardExample.js | 68 --- .../js/examples/Crash/CrashExample.js | 1 + .../DatePicker/DatePickerAndroidExample.js | 170 -------- .../DatePicker/DatePickerIOSExample.js | 150 ------- .../DevSettings/DevSettingsExample.js | 2 + .../examples/Dimensions/DimensionsExample.js | 2 + .../js/examples/FlatList/FlatListExample.js | 4 +- .../js/examples/Image/ImageExample.js | 4 +- .../InputAccessoryViewExample.js | 2 +- .../JSResponderHandlerExample.js | 3 +- .../KeyboardAvoidingViewExample.js | 4 +- .../examples/Layout/LayoutAnimationExample.js | 2 + .../js/examples/Layout/LayoutEventsExample.js | 1 + .../js/examples/Layout/LayoutExample.js | 1 + .../js/examples/Linking/LinkingExample.js | 2 + .../examples/MaskedView/MaskedViewExample.js | 236 ----------- .../js/examples/Modal/ModalExample.js | 4 +- .../MultiColumn/MultiColumnExample.js | 3 +- .../NativeAnimationsExample.js | 1 + .../OrientationChangeExample.js | 1 + .../PanResponder/PanResponderExample.js | 2 + .../PermissionsAndroid/PermissionsExample.js | 1 + .../js/examples/Picker/PickerExample.js | 220 ---------- .../js/examples/Picker/PickerIOSExample.js | 190 --------- .../PlatformColor/PlatformColorExample.js | 2 + .../PointerEvents/PointerEventsExample.js | 1 + .../js/examples/Pressable/PressableExample.js | 4 +- .../ProgressBarAndroidExample.android.js | 94 ----- .../ProgressViewIOS/ProgressViewIOSExample.js | 103 ----- .../PushNotificationIOSExample.js | 267 ------------ .../RCTRootView/RCTRootViewIOSExample.js | 1 + .../rn-tester/js/examples/RTL/RTLExample.js | 9 +- .../RefreshControl/RefreshControlExample.js | 4 +- .../SafeAreaView/SafeAreaViewExample.js | 4 +- .../ScrollView/ScrollViewAnimatedExample.js | 3 +- .../examples/ScrollView/ScrollViewExample.js | 4 +- .../ScrollView/ScrollViewSimpleExample.js | 3 +- .../SectionList/SectionListExample.js | 4 +- .../SegmentedControlExampleComponents.js | 114 ------ .../SegmentedControlIOSExample.js | 63 --- .../js/examples/Share/ShareExample.js | 2 + .../js/examples/Slider/SliderExample.js | 136 ------ .../js/examples/Snapshot/SnapshotExample.js | 1 + .../js/examples/StatusBar/StatusBarExample.js | 4 +- .../js/examples/Switch/SwitchExample.js | 4 +- .../TVEventHandler/TVEventHandlerExample.js | 1 + .../js/examples/Text/TextExample.android.js | 4 +- .../js/examples/Text/TextExample.ios.js | 4 +- .../TextInput/TextInputExample.android.js | 4 +- .../TextInput/TextInputExample.ios.js | 4 +- .../js/examples/Timer/TimerExample.js | 1 + .../ToastAndroidExample.android.js | 1 + .../js/examples/Touchable/TouchableExample.js | 4 +- .../js/examples/Transform/TransformExample.js | 2 + .../TransparentHitTestExample.js | 3 +- .../TurboModule/TurboModuleExample.js | 1 + .../js/examples/Vibration/VibrationExample.js | 2 + .../rn-tester/js/examples/View/ViewExample.js | 4 +- .../js/examples/WebSocket/WebSocketExample.js | 1 + .../rn-tester/js/examples/XHR/XHRExample.js | 1 + packages/rn-tester/js/types/RNTesterTypes.js | 5 + .../rn-tester/js/utils/RNTesterActions.js | 8 +- .../utils/RNTesterAsyncStorageAbstraction.js | 190 +++++++++ .../js/utils/RNTesterList.android.js | 70 ++-- .../rn-tester/js/utils/RNTesterList.ios.js | 111 +++-- .../js/utils/RNTesterNavigationReducer.js | 31 +- .../js/utils/RNTesterStatePersister.js | 2 +- 115 files changed, 1854 insertions(+), 2405 deletions(-) create mode 100755 packages/rn-tester/js/assets/bookmark-filled.png create mode 100644 packages/rn-tester/js/assets/bookmark-outline-blue.png create mode 100644 packages/rn-tester/js/assets/bookmark-outline-gray.png create mode 100755 packages/rn-tester/js/assets/bookmark-outline.png create mode 100644 packages/rn-tester/js/assets/bottom-nav-apis-icon-active.png create mode 100644 packages/rn-tester/js/assets/bottom-nav-apis-icon-inactive.png create mode 100644 packages/rn-tester/js/assets/bottom-nav-bookmark-fill.png create mode 100644 packages/rn-tester/js/assets/bottom-nav-bookmark-outline.png create mode 100644 packages/rn-tester/js/assets/bottom-nav-center-box.png create mode 100644 packages/rn-tester/js/assets/bottom-nav-components-icon-active.png create mode 100644 packages/rn-tester/js/assets/bottom-nav-components-icon-inactive.png create mode 100644 packages/rn-tester/js/assets/documentation.png create mode 100644 packages/rn-tester/js/assets/empty.png create mode 100644 packages/rn-tester/js/assets/header-back-button.png create mode 100644 packages/rn-tester/js/assets/search-icon.png create mode 100644 packages/rn-tester/js/components/ExamplePage.js create mode 100644 packages/rn-tester/js/components/RNTesterBookmark.js create mode 100644 packages/rn-tester/js/components/RNTesterBookmarkButton.js create mode 100644 packages/rn-tester/js/components/RNTesterComponentTitle.js create mode 100644 packages/rn-tester/js/components/RNTesterDocumentationURL.js create mode 100644 packages/rn-tester/js/components/RNTesterListFilters.js create mode 100644 packages/rn-tester/js/components/RNTesterNavbar.js create mode 100644 packages/rn-tester/js/components/UseCase.js delete mode 100644 packages/rn-tester/js/examples/AsyncStorage/AsyncStorageExample.js delete mode 100644 packages/rn-tester/js/examples/Clipboard/ClipboardExample.js delete mode 100644 packages/rn-tester/js/examples/DatePicker/DatePickerAndroidExample.js delete mode 100644 packages/rn-tester/js/examples/DatePicker/DatePickerIOSExample.js delete mode 100644 packages/rn-tester/js/examples/MaskedView/MaskedViewExample.js delete mode 100644 packages/rn-tester/js/examples/Picker/PickerExample.js delete mode 100644 packages/rn-tester/js/examples/Picker/PickerIOSExample.js delete mode 100644 packages/rn-tester/js/examples/ProgressBarAndroid/ProgressBarAndroidExample.android.js delete mode 100644 packages/rn-tester/js/examples/ProgressViewIOS/ProgressViewIOSExample.js delete mode 100644 packages/rn-tester/js/examples/PushNotificationIOS/PushNotificationIOSExample.js delete mode 100644 packages/rn-tester/js/examples/SegmentedControlIOS/SegmentedControlExampleComponents.js delete mode 100644 packages/rn-tester/js/examples/SegmentedControlIOS/SegmentedControlIOSExample.js delete mode 100644 packages/rn-tester/js/examples/Slider/SliderExample.js create mode 100644 packages/rn-tester/js/utils/RNTesterAsyncStorageAbstraction.js diff --git a/packages/rn-tester/e2e/__tests__/Button-test.js b/packages/rn-tester/e2e/__tests__/Button-test.js index c43fdb05d6b87f..53588b168a525a 100644 --- a/packages/rn-tester/e2e/__tests__/Button-test.js +++ b/packages/rn-tester/e2e/__tests__/Button-test.js @@ -18,8 +18,8 @@ describe('Button', () => { beforeAll(async () => { await device.reloadReactNative(); await openComponentWithLabel( - '