initial commit with merge conflicts
This commit is contained in:
Коммит
be6e83889f
|
@ -30,17 +30,16 @@ install:
|
|||
- appveyor DownloadFile "%NDK_TOOLS_URL%" -FileName "%TMP%/ndk.zip"
|
||||
- 7z x "%TMP%/ndk.zip" -o"%ANDROID_HOME%" > nul
|
||||
|
||||
- ps: Install-Product node $env:nodejs_version
|
||||
- node --version
|
||||
- yarn --version
|
||||
- ps: Install-Product node $env:nodejs_version x64
|
||||
- npx envinfo@latest
|
||||
- appveyor-retry yarn install
|
||||
|
||||
build_script:
|
||||
- yarn run flow-check-android
|
||||
- yarn run flow-check-ios
|
||||
- yarn run test
|
||||
- gradlew.bat RNTester:android:app:assembleRelease
|
||||
|
||||
test_script:
|
||||
- npm test
|
||||
|
||||
cache:
|
||||
- node_modules
|
||||
- "%LOCALAPPDATA%/Yarn"
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
# Docker Test Environment
|
||||
|
||||
This is a high-level overview of the test configuration using Docker.
|
||||
It explains how to run the tests locally.
|
||||
|
||||
## Docker Installation
|
||||
|
||||
It is required to have Docker running on your machine in order to build and run the tests in the Dockerfiles.
|
||||
See <https://docs.docker.com/engine/installation/> for more information on how to install.
|
||||
|
||||
## Convenience Scripts
|
||||
|
||||
We have added a number of default run scripts to the `package.json` file to simplify building and running your tests.
|
||||
|
||||
### Configuring Docker Images
|
||||
|
||||
The following two scripts need to be run first before you can move on to testing:
|
||||
|
||||
- `yarn run docker-setup-android`: Pulls down the React Native Community Android image that serves as a base image when building the actual test image.
|
||||
|
||||
- `yarn run docker-build-android`: Builds a test image with the latest dependencies and React Native library code, including a compiled Android test app.
|
||||
|
||||
### Running Tests
|
||||
|
||||
Once the test image has been built, it can be used to run our Android tests.
|
||||
|
||||
- `yarn run test-android-run-unit` runs the unit tests, as defined in `scripts/run-android-docker-unit-tests.sh`.
|
||||
- `yarn run test-android-run-e2e` runs the end to end tests, as defined in `scripts/run-ci-e2e-tests.sh`.
|
||||
- `yarn run test-android-run-instrumentation` runs the instrumentation tests, as defined in `scripts/run-android-docker-instrumentation-tests.sh`.
|
||||
|
||||
#### Instrumentation Tests
|
||||
|
||||
The instrumentation test script accepts the following flags in order to customize the execution of the tests:
|
||||
|
||||
`--filter` - A regex that filters which instrumentation tests will be run. (Defaults to .*)
|
||||
|
||||
`--package` - Name of the java package containing the instrumentation tests (Defaults to com.facebook.react.tests)
|
||||
|
||||
`--path` - Path to the directory containing the instrumentation tests. (Defaults to ./ReactAndroid/src/androidTest/java/com/facebook/react/tests)
|
||||
|
||||
`--retries` - Number of times to retry a failed test before declaring a failure (Defaults to 2)
|
||||
|
||||
For example, if locally you only wanted to run the InitialPropsTestCase, you could do the following:
|
||||
`yarn run test-android-run-instrumentation -- --filter="InitialPropsTestCase"`
|
||||
|
||||
## Detailed Android Setup
|
||||
|
||||
There are two Dockerfiles for use with the Android codebase.
|
||||
The base image used to build `reactnativecommunity/react-native-android` is located in the https://github.com/react-native-community/docker-android GitHub repository.
|
||||
It contains all the necessary prerequisites required to run the React Android tests.
|
||||
It is separated out into a separate Dockerfile because these are dependencies that rarely change and also because it is quite a beastly image since it contains all the Android dependencies for running Android and the emulators (~9GB).
|
||||
|
||||
The good news is you should rarely have to build or pull down the base image!
|
||||
All iterative code updates happen as part of the `Dockerfile.android` image build.
|
||||
|
||||
Lets break it down...
|
||||
|
||||
First, you'll need to pull the base image.
|
||||
You can use `docker pull` to grab the latest version of the `reactnativecommunity/react-native-android` base image.
|
||||
This is what you get when you run `yarn run docker-setup-android`.
|
||||
|
||||
This will take quite some time depending on your connection and you need to ensure you have ~10GB of free disk space.
|
||||
|
||||
Once you have downloaded the base image, the test image can be built using `docker build -t reactnativeci/android -f ./.circleci/Dockerfiles/Dockerfile.android .`. This is what `yarn run docker-build-android` does. Note that the `-t` flag is how you tell Docker what to name this image locally. You can then use `docker run -t reactnativeci/android` to run this image.
|
||||
|
||||
Now that you've built the test image, you can run unit tests using what you've learned so far:
|
||||
|
||||
```bash
|
||||
docker run --cap-add=SYS_ADMIN -it reactnativeci/android bash .circleci/Dockerfiles/scripts/run-android-docker-unit-tests.sh
|
||||
```
|
||||
|
||||
> Note: `--cap-add=SYS_ADMIN` flag is required for the `.circleci/Dockerfiles/scripts/run-android-docker-unit-tests.sh` and `.circleci/Dockerfiles/scripts/run-android-docker-instrumentation-tests.sh` in order to allow the remounting of `/dev/shm` as writeable so the `buck` build system may write temporary output to that location.
|
||||
|
||||
Every time you make any modifications to the codebase, including changes to the test scripts inside `.circleci/Dockerfiles/scripts`, you should re-run the `docker build ...` command in order for your updates to be included in your local docker test image.
|
||||
|
||||
For rapid iteration, it's useful to keep in mind that Docker can pass along arbitrary commands to an image.
|
||||
For example, you can alternatively use Gradle in this manner:
|
||||
|
||||
```bash
|
||||
docker run --cap-add=SYS_ADMIN -it reactnativeci/android ./gradlew RNTester:android:app:assembleRelease
|
||||
```
|
|
@ -2,16 +2,21 @@
|
|||
#
|
||||
# This source code is licensed under the MIT license found in the
|
||||
# LICENSE file in the root directory of this source tree.
|
||||
|
||||
# React Native Android Unit Tests
|
||||
#
|
||||
# This image builds upon the React Native Base Android Development Environment
|
||||
# image. Ideally, this image would be rebuilt with any new commit to the master
|
||||
# branch. Doing so will catch issues such as BUCK failing to fetch dependencies
|
||||
# or run tests, as well as unit test failures.
|
||||
FROM react-native-community/react-native
|
||||
# This image builds upon the React Native Community Android image:
|
||||
# https://github.com/react-native-community/docker-android
|
||||
#
|
||||
# The base image is expected to remain relatively stable, and only
|
||||
# needs to be updated when major dependencies such as the Android
|
||||
# SDK or NDK are updated.
|
||||
#
|
||||
# In this Android Test image, we download the latest dependencies
|
||||
# and build a Android application that can be used to run the
|
||||
# tests specified in the scripts/ directory.
|
||||
#
|
||||
FROM reactnativecommunity/react-native-android
|
||||
|
||||
LABEL Description="This image prepares and runs React Native's Android tests."
|
||||
LABEL Description="React Native Android Test Image"
|
||||
LABEL maintainer="Héctor Ramos <hector@fb.com>"
|
||||
|
||||
ARG BUCK_BUILD
|
||||
|
@ -19,16 +24,21 @@ ARG BUCK_BUILD
|
|||
ENV GRADLE_OPTS="-Dorg.gradle.daemon=false -Dorg.gradle.jvmargs=\"-Xmx512m -XX:+HeapDumpOnOutOfMemoryError\""
|
||||
ENV JAVA_TOOL_OPTIONS="-Dfile.encoding=UTF8"
|
||||
|
||||
<<<<<<< HEAD:ContainerShip/Dockerfile.android
|
||||
ENV BUCK_BUILD="1"
|
||||
|
||||
# add ReactAndroid directory
|
||||
=======
|
||||
>>>>>>> v0.60.0:.circleci/Dockerfiles/Dockerfile.android
|
||||
ADD .buckconfig /app/.buckconfig
|
||||
ADD .buckjavaargs /app/.buckjavaargs
|
||||
ADD tools /app/tools
|
||||
ADD ReactAndroid /app/ReactAndroid
|
||||
ADD ReactCommon /app/ReactCommon
|
||||
ADD ReactNative /app/ReactNative
|
||||
ADD React /app/React
|
||||
ADD keystores /app/keystores
|
||||
|
||||
<<<<<<< HEAD:ContainerShip/Dockerfile.android
|
||||
# add third party dependencies
|
||||
ADD Folly /app/Folly
|
||||
ADD glog /app/glog
|
||||
|
@ -37,19 +47,20 @@ ADD jsc /app/jsc
|
|||
ADD v8 /app/v8
|
||||
|
||||
# set workdir
|
||||
=======
|
||||
>>>>>>> v0.60.0:.circleci/Dockerfiles/Dockerfile.android
|
||||
WORKDIR /app
|
||||
|
||||
# run buck fetches
|
||||
RUN buck fetch ReactAndroid/src/test/java/com/facebook/react/modules
|
||||
RUN buck fetch ReactAndroid/src/main/java/com/facebook/react
|
||||
RUN buck fetch ReactAndroid/src/main/java/com/facebook/react/shell
|
||||
RUN buck fetch ReactAndroid/src/test/...
|
||||
RUN buck fetch ReactAndroid/src/androidTest/...
|
||||
|
||||
# build app
|
||||
RUN buck build ReactAndroid/src/main/java/com/facebook/react
|
||||
RUN buck build ReactAndroid/src/main/java/com/facebook/react/shell
|
||||
|
||||
<<<<<<< HEAD:ContainerShip/Dockerfile.android
|
||||
ADD gradle /app/gradle
|
||||
ADD gradlew /app/gradlew
|
||||
ADD settings.gradle /app/settings.gradle
|
||||
|
@ -63,15 +74,13 @@ RUN ./gradlew :ReactAndroid:downloadBoost # :ReactAndroid:downloadDoubleConversi
|
|||
RUN ./gradlew :ReactAndroid:packageReactNdkLibsForBuck -Pjobs=1
|
||||
|
||||
# add all react-native code
|
||||
=======
|
||||
>>>>>>> v0.60.0:.circleci/Dockerfiles/Dockerfile.android
|
||||
ADD . /app
|
||||
WORKDIR /app
|
||||
|
||||
# build node dependencies
|
||||
RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
|
||||
RUN echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
|
||||
RUN apt-get install apt-transport-https
|
||||
RUN apt-get update
|
||||
RUN apt-get install yarn
|
||||
RUN yarn
|
||||
|
||||
WORKDIR /app
|
||||
RUN ./gradlew :ReactAndroid:downloadBoost :ReactAndroid:downloadDoubleConversion :ReactAndroid:downloadFolly :ReactAndroid:downloadGlog
|
||||
|
||||
RUN ./gradlew :ReactAndroid:packageReactNdkLibsForBuck -Pjobs=1
|
||||
|
|
@ -80,13 +80,13 @@ if (test_opts.COUNT != null && test_opts.OFFSET != null) {
|
|||
}
|
||||
}
|
||||
|
||||
return async.mapSeries(testClasses, (clazz, callback) => {
|
||||
async.mapSeries(testClasses, (clazz, callback) => {
|
||||
if (clazz.length > max_test_class_length) {
|
||||
max_test_class_length = clazz.length;
|
||||
}
|
||||
|
||||
return async.retry(test_opts.RETRIES, (retryCb) => {
|
||||
const test_process = child_process.spawn('./ContainerShip/scripts/run-instrumentation-tests-via-adb-shell.sh', [test_opts.PACKAGE, clazz], {
|
||||
const test_process = child_process.spawn('./.circleci/Dockerfiles/scripts/run-instrumentation-tests-via-adb-shell.sh', [test_opts.PACKAGE, clazz], {
|
||||
stdio: 'inherit',
|
||||
});
|
||||
|
|
@ -38,5 +38,5 @@ node cli.js bundle --platform android --dev true --entry-file ReactAndroid/src/a
|
|||
source ./scripts/android-setup.sh && NO_BUCKD=1 retry3 buck install ReactAndroid/src/androidTest/buck-runner:instrumentation-tests --config build.threads=1
|
||||
|
||||
# run installed apk with tests
|
||||
node ./ContainerShip/scripts/run-android-ci-instrumentation-tests.js "$*"
|
||||
node ./.circleci/Dockerfiles/scripts/run-android-ci-instrumentation-tests.js "$*"
|
||||
exit $?
|
|
@ -22,8 +22,6 @@ AVD_UUID=$(< /dev/urandom tr -dc 'a-zA-Z0-9' | fold -w 8 | head -n 1)
|
|||
ANDROID_NPM_DEPS="appium@1.5.1 mocha@2.4.5 wd@0.3.11 colors@1.0.3 pretty-data2@0.40.1"
|
||||
CLI_PACKAGE="$ROOT/react-native-cli/react-native-cli-*.tgz"
|
||||
PACKAGE="$ROOT/react-native-*.tgz"
|
||||
# Version of react-native-dummy to test against
|
||||
REACT_DUMMY_PLATFORM=react-native-dummy@0.1.0
|
||||
|
||||
# solve issue with max user watches limit
|
||||
echo 65536 | tee -a /proc/sys/fs/inotify/max_user_watches
|
||||
|
@ -250,20 +248,6 @@ function e2e_suite() {
|
|||
return 1
|
||||
fi
|
||||
|
||||
if ! retry "$RETRY_COUNT" npm install --save "$REACT_DUMMY_PLATFORM" --silent >> /dev/null
|
||||
then
|
||||
echo "Failed to install react-native-dummy"
|
||||
echo "Most common reason is npm registry connectivity, try again"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! react-native bundle --max-workers 1 --platform dummy --dev true --entry-file index.js --bundle-output dummy-bundle.js
|
||||
then
|
||||
echo "Could not build dummy bundle"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# directory cleanup
|
||||
rm "$IOS_MARKER"
|
||||
rm "$ANDROID_MARKER"
|
|
@ -1,7 +1,13 @@
|
|||
# -------------------------
|
||||
# ALIASES
|
||||
# -------------------------
|
||||
aliases:
|
||||
# Cache Management
|
||||
# -------------------------
|
||||
# ALIASES: Caches
|
||||
# -------------------------
|
||||
- &restore-yarn-cache
|
||||
keys:
|
||||
<<<<<<< HEAD
|
||||
- v2-yarn-cache-{{ arch }}-{{ checksum "package.json" }}
|
||||
- v2-yarn-cache-{{ arch }}
|
||||
- &save-yarn-cache
|
||||
|
@ -16,16 +22,21 @@ aliases:
|
|||
paths:
|
||||
- node_modules
|
||||
key: v2-node-modules-{{ arch }}-{{ checksum "package.json" }}
|
||||
=======
|
||||
- v1-yarn-cache-{{ arch }}-{{ checksum "package.json" }}{{ checksum "bots/package.json" }}
|
||||
- v1-yarn-cache-{{ arch }}
|
||||
|
||||
- &restore-cache-analysis
|
||||
keys:
|
||||
- v1-analysis-dependencies-{{ arch }}-{{ checksum "package.json" }}{{ checksum "bots/package.json" }}
|
||||
- &save-cache-analysis
|
||||
- &save-yarn-cache
|
||||
paths:
|
||||
- bots/node_modules
|
||||
- node_modules
|
||||
key: v1-analysis-dependencies-{{ arch }}-{{ checksum "package.json" }}{{ checksum "bots/package.json" }}
|
||||
- ~/.cache/yarn
|
||||
key: v1-yarn-cache-{{ arch }}-{{ checksum "package.json" }}{{ checksum "bots/package.json" }}
|
||||
>>>>>>> v0.60.0
|
||||
|
||||
- &restore-brew-cache
|
||||
keys:
|
||||
- v1-brew
|
||||
|
||||
<<<<<<< HEAD
|
||||
- &restore-cache-android-packages
|
||||
keys:
|
||||
- v1-android-sdkmanager-packages-api-28-alpha-{{ checksum "scripts/.tests.env" }}
|
||||
|
@ -54,36 +65,50 @@ aliases:
|
|||
paths:
|
||||
- /opt/ndk
|
||||
key: v3-android-ndk-r17c-{{ checksum "scripts/android-setup.sh" }}
|
||||
=======
|
||||
- &save-brew-cache
|
||||
paths:
|
||||
- /usr/local/Homebrew
|
||||
- ~/Library/Caches/Homebrew
|
||||
key: v1-brew
|
||||
>>>>>>> v0.60.0
|
||||
|
||||
- &restore-cache-downloads-buck
|
||||
# Android
|
||||
- &restore-buck-downloads-cache
|
||||
keys:
|
||||
<<<<<<< HEAD
|
||||
- v4-buck-v2019.01.10.01-{{ checksum "scripts/circleci/buck_fetch.sh" }}}
|
||||
- v4-buck-v2019.01.10.01-
|
||||
- &save-cache-downloads-buck
|
||||
=======
|
||||
- v3-buck-v2019.01.10.01-{{ checksum "scripts/circleci/buck_fetch.sh" }}}
|
||||
- v3-buck-v2019.01.10.01-
|
||||
- &save-buck-downloads-cache
|
||||
>>>>>>> v0.60.0
|
||||
paths:
|
||||
- ~/buck
|
||||
- ~/okbuck
|
||||
key: v4-buck-v2019.01.10.01-{{ checksum "scripts/circleci/buck_fetch.sh" }}
|
||||
|
||||
- &restore-cache-watchman
|
||||
keys:
|
||||
- v1-watchman-{{ arch }}-v4.9.0
|
||||
- &save-cache-watchman
|
||||
paths:
|
||||
- ~/watchman
|
||||
key: v1-watchman-{{ arch }}-v4.9.0
|
||||
|
||||
- &restore-cache-downloads-gradle
|
||||
- &restore-gradle-downloads-cache
|
||||
keys:
|
||||
<<<<<<< HEAD
|
||||
- v2-gradle-{{ checksum "ReactAndroid/build.gradle" }}-{{ checksum "scripts/circleci/gradle_download_deps.sh" }}
|
||||
- v2-gradle-
|
||||
- &save-cache-downloads-gradle
|
||||
=======
|
||||
- v1-gradle-{{ checksum "ReactAndroid/build.gradle" }}-{{ checksum "scripts/circleci/gradle_download_deps.sh" }}
|
||||
- v1-gradle-
|
||||
|
||||
- &save-gradle-downloads-cache
|
||||
>>>>>>> v0.60.0
|
||||
paths:
|
||||
- ~/.gradle
|
||||
- ReactAndroid/build/downloads
|
||||
- ReactAndroid/build/third-party-ndk
|
||||
key: v2-gradle-{{ checksum "ReactAndroid/build.gradle" }}-{{ checksum "scripts/circleci/gradle_download_deps.sh" }}
|
||||
|
||||
<<<<<<< HEAD
|
||||
- &restore-cache-homebrew
|
||||
keys:
|
||||
- v1-homebrew
|
||||
|
@ -120,6 +145,11 @@ aliases:
|
|||
name: Install Android NDK
|
||||
command: source scripts/android-setup.sh && getAndroidNDK
|
||||
|
||||
=======
|
||||
# -------------------------
|
||||
# ALIASES: Shared Commands
|
||||
# -------------------------
|
||||
>>>>>>> v0.60.0
|
||||
- &yarn
|
||||
name: Run Yarn
|
||||
command: |
|
||||
|
@ -129,6 +159,7 @@ aliases:
|
|||
yarn install --non-interactive --cache-folder ~/.cache/yarn
|
||||
fi
|
||||
|
||||
<<<<<<< HEAD
|
||||
- &install-yarn
|
||||
name: Install Yarn
|
||||
command: |
|
||||
|
@ -275,6 +306,8 @@ aliases:
|
|||
./tooling/junit/buck_to_junit.sh ~/react-native/reports/buck/all-results-raw.xml ~/react-native/reports/junit/all-results-junit.xml
|
||||
when: always
|
||||
|
||||
=======
|
||||
>>>>>>> v0.60.0
|
||||
- &setup-artifacts
|
||||
name: Initial Setup
|
||||
command: |
|
||||
|
@ -283,63 +316,100 @@ aliases:
|
|||
mkdir -p ~/react-native/reports/junit/
|
||||
mkdir -p ~/react-native/reports/outputs/
|
||||
|
||||
- &brew-install-watchman
|
||||
name: Install Watchman
|
||||
command: |
|
||||
brew install watchman
|
||||
touch .watchmanconfig
|
||||
# Android
|
||||
- &download-dependencies-buck
|
||||
name: Download Dependencies Using Buck
|
||||
command: ./scripts/circleci/buck_fetch.sh
|
||||
|
||||
- &boot-simulator-iphone
|
||||
name: Boot iPhone Simulator
|
||||
command: source scripts/.tests.env && xcrun simctl boot "$IOS_DEVICE" || true
|
||||
- &download-dependencies-gradle
|
||||
name: Download Dependencies Using Gradle
|
||||
command: ./scripts/circleci/gradle_download_deps.sh
|
||||
|
||||
- &run-objc-ios-tests
|
||||
name: iOS Test Suite
|
||||
command: ./scripts/objc-test-ios.sh test
|
||||
|
||||
- &display-broken-tests-warning
|
||||
name: Running broken tests (Ignore any failures past this point)
|
||||
command: |
|
||||
echo 'The following steps are known to be failing on master.'
|
||||
echo 'They will no-op for most users.'
|
||||
echo 'PRs that bring these back to green are appreciated.'
|
||||
# JavaScript
|
||||
- &run-js-tests
|
||||
name: JavaScript Test Suite
|
||||
command: yarn test-ci
|
||||
|
||||
# -------------------------
|
||||
# ALIASES: Disabled Tests
|
||||
# -------------------------
|
||||
- &run-podspec-tests
|
||||
name: Test CocoaPods (Disabled)
|
||||
command: ./scripts/circleci/exec_author_check.sh ./scripts/process-podspecs.sh
|
||||
|
||||
name: Test CocoaPods
|
||||
command: ./scripts/process-podspecs.sh
|
||||
- &run-e2e-tests
|
||||
name: End-to-End Test Suite (Disabled)
|
||||
command: ./scripts/circleci/exec_author_check.sh node ./scripts/run-ci-e2e-tests.js --android --ios --js --retries 3;
|
||||
|
||||
- &run-objc-ios-e2e-tests
|
||||
name: iOS End-to-End Test Suite (Disabled)
|
||||
command: ./scripts/circleci/exec_author_check.sh node ./scripts/run-ci-e2e-tests.js --ios --retries 3;
|
||||
|
||||
name: End-to-End Test Suite
|
||||
command: ./scripts/run-ci-e2e-tests.js --android --ios --js --retries 3;
|
||||
- &run-android-e2e-tests
|
||||
name: Android End-to-End Test Suite (Disabled)
|
||||
command: ./scripts/circleci/exec_author_check.sh node ./scripts/run-ci-e2e-tests.js --android --retries 3;
|
||||
name: Android End-to-End Test Suite
|
||||
command: node ./scripts/run-ci-e2e-tests.js --android --retries 3;
|
||||
|
||||
- &run-js-e2e-tests
|
||||
name: JavaScript End-to-End Test Suite
|
||||
command: node ./scripts/run-ci-e2e-tests.js --js --retries 3;
|
||||
|
||||
# -------------------------
|
||||
# ALIASES: Branch Filters
|
||||
# -------------------------
|
||||
- &filter-only-master
|
||||
branches:
|
||||
only: master
|
||||
|
||||
- &filter-only-master-stable
|
||||
branches:
|
||||
only:
|
||||
- /.*-stable/
|
||||
- master
|
||||
|
||||
- &filter-only-stable
|
||||
branches:
|
||||
only:
|
||||
- /.*-stable/
|
||||
|
||||
- &filter-ignore-gh-pages
|
||||
branches:
|
||||
ignore: gh-pages
|
||||
|
||||
- &filter-only-version-tags
|
||||
# Both of the following conditions must be included!
|
||||
# Ignore any commit on any branch by default.
|
||||
branches:
|
||||
ignore: /.*/
|
||||
# Only act on version tags.
|
||||
tags:
|
||||
only: /v[0-9]+(\.[0-9]+)*(\-rc(\.[0-9]+)?)?/
|
||||
|
||||
- &filter-only-forked-pull-requests
|
||||
branches:
|
||||
only: /^pull\/.*$/
|
||||
|
||||
# -------------------------
|
||||
# ALIASES: Workflows
|
||||
# -------------------------
|
||||
- &run-after-checkout
|
||||
filters: *filter-ignore-gh-pages
|
||||
requires:
|
||||
- checkout_code
|
||||
|
||||
# -------------------------
|
||||
# DEFAULTS
|
||||
# -------------------------
|
||||
defaults: &defaults
|
||||
working_directory: ~/react-native
|
||||
environment:
|
||||
- GIT_COMMIT_DESC: git log --format=oneline -n 1 $CIRCLE_SHA1
|
||||
|
||||
# JavaScript
|
||||
js_defaults: &js_defaults
|
||||
<<: *defaults
|
||||
docker:
|
||||
- image: circleci/node:8
|
||||
environment:
|
||||
- PATH: "/opt/yarn/yarn-v1.5.1/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
||||
- image: node:8
|
||||
|
||||
# Android
|
||||
android_defaults: &android_defaults
|
||||
<<: *defaults
|
||||
docker:
|
||||
<<<<<<< HEAD
|
||||
- image: circleci/android:api-28-node8-alpha
|
||||
=======
|
||||
- image: reactnativecommunity/react-native-android:2019-5-29
|
||||
>>>>>>> v0.60.0
|
||||
resource_class: "large"
|
||||
environment:
|
||||
- TERM: "dumb"
|
||||
|
@ -349,11 +419,15 @@ android_defaults: &android_defaults
|
|||
- ANDROID_NDK: '/opt/ndk/android-ndk-r17c'
|
||||
- BUILD_THREADS: 2
|
||||
|
||||
# iOS
|
||||
macos_defaults: &macos_defaults
|
||||
<<: *defaults
|
||||
macos:
|
||||
xcode: "10.1.0"
|
||||
xcode: "10.2.0"
|
||||
|
||||
# -------------------------
|
||||
# JOBS
|
||||
# -------------------------
|
||||
version: 2
|
||||
jobs:
|
||||
# Set up a Node environment for downstream jobs
|
||||
|
@ -367,30 +441,116 @@ jobs:
|
|||
- run: *yarn
|
||||
- save-cache: *save-yarn-cache
|
||||
|
||||
# Basic checks against the checkout, cache...
|
||||
- run: *run-sanity-checks
|
||||
|
||||
- persist_to_workspace:
|
||||
root: .
|
||||
paths: .
|
||||
|
||||
# Runs JavaScript lint and flow checks.
|
||||
# Currently will fail a PR if lint/flow raises issues.
|
||||
# -------------------------
|
||||
# JOBS: Analyze PR
|
||||
# -------------------------
|
||||
# Analyze pull request and raise any lint/flow issues.
|
||||
# Issues will be posted to the PR itself via GitHub bots.
|
||||
# This workflow should only fail if the bots fail to run.
|
||||
analyze_pr:
|
||||
<<: *defaults
|
||||
docker:
|
||||
- image: node:lts
|
||||
# The public github tokens are publicly visible by design
|
||||
environment:
|
||||
- PUBLIC_PULLBOT_GITHUB_TOKEN_A: "a6edf8e8d40ce4e8b11a"
|
||||
- PUBLIC_PULLBOT_GITHUB_TOKEN_B: "150e1341f4dd9c944d2a"
|
||||
- PUBLIC_ANALYSISBOT_GITHUB_TOKEN_A: "78a72af35445ca3f8180"
|
||||
- PUBLIC_ANALYSISBOT_GITHUB_TOKEN_B: "b1a98e0bbd56ff1ccba1"
|
||||
|
||||
steps:
|
||||
- checkout
|
||||
- run: *setup-artifacts
|
||||
|
||||
- restore-cache: *restore-yarn-cache
|
||||
- run: *yarn
|
||||
|
||||
- run:
|
||||
name: Analyze Shell Scripts
|
||||
command: |
|
||||
echo -e "\\x1B[36mInstalling additional dependencies\\x1B[0m"
|
||||
apt update && apt install -y shellcheck jq
|
||||
yarn add @octokit/rest@15.18.0
|
||||
echo -e "\\x1B[36mAnalyzing shell scripts\\x1B[0m"; \
|
||||
GITHUB_TOKEN="$PUBLIC_ANALYSISBOT_GITHUB_TOKEN_A""$PUBLIC_ANALYSISBOT_GITHUB_TOKEN_B" \
|
||||
GITHUB_OWNER="$CIRCLE_PROJECT_USERNAME" \
|
||||
GITHUB_REPO="$CIRCLE_PROJECT_REPONAME" \
|
||||
GITHUB_PR_NUMBER="$CIRCLE_PR_NUMBER" \
|
||||
./scripts/circleci/analyze_scripts.sh
|
||||
when: always
|
||||
|
||||
- run:
|
||||
name: Analyze Code
|
||||
command: |
|
||||
echo -e "\\x1B[36mInstalling additional dependencies\\x1B[0m"; yarn add @octokit/rest@15.18.0
|
||||
echo -e "\\x1B[36mAnalyzing code\\x1B[0m"; \
|
||||
GITHUB_TOKEN="$PUBLIC_ANALYSISBOT_GITHUB_TOKEN_A""$PUBLIC_ANALYSISBOT_GITHUB_TOKEN_B" \
|
||||
GITHUB_OWNER="$CIRCLE_PROJECT_USERNAME" \
|
||||
GITHUB_REPO="$CIRCLE_PROJECT_REPONAME" \
|
||||
GITHUB_PR_NUMBER="$CIRCLE_PR_NUMBER" \
|
||||
./scripts/circleci/analyze_code.sh
|
||||
when: always
|
||||
|
||||
- run:
|
||||
name: Analyze Pull Request
|
||||
command: |
|
||||
echo -e "\\x1B[36mInstalling additional dependencies\\x1B[0m"
|
||||
cd bots
|
||||
yarn install --non-interactive --cache-folder ~/.cache/yarn
|
||||
echo -e "\\x1B[36mAnalyzing pull request\\x1B[0m"; \
|
||||
DANGER_GITHUB_API_TOKEN="$PUBLIC_PULLBOT_GITHUB_TOKEN_A""$PUBLIC_PULLBOT_GITHUB_TOKEN_B" \
|
||||
yarn danger ci --use-github-checks
|
||||
when: always
|
||||
- save-cache: *save-yarn-cache
|
||||
|
||||
# -------------------------
|
||||
# JOBS: Analyze Code
|
||||
# -------------------------
|
||||
analyze:
|
||||
<<: *js_defaults
|
||||
steps:
|
||||
- attach_workspace:
|
||||
at: ~/react-native
|
||||
|
||||
- run: *run-lint-checks
|
||||
- run: *run-flow-checks-ios
|
||||
- run: *run-flow-checks-android
|
||||
- run:
|
||||
name: Lint code
|
||||
command: scripts/circleci/exec_swallow_error.sh yarn lint --format junit -o ~/react-native/reports/junit/eslint/results.xml
|
||||
when: always
|
||||
|
||||
- run:
|
||||
name: Check for errors in code using Flow (iOS)
|
||||
command: yarn flow-check-ios
|
||||
when: always
|
||||
|
||||
- run:
|
||||
name: Check for errors in code using Flow (Android)
|
||||
command: yarn flow-check-android
|
||||
when: always
|
||||
|
||||
- run:
|
||||
name: Sanity checks
|
||||
command: |
|
||||
./scripts/circleci/check_license.sh
|
||||
./scripts/circleci/validate_yarn_lockfile.sh
|
||||
when: always
|
||||
|
||||
- run:
|
||||
name: Check formatting
|
||||
command: yarn run format-check
|
||||
when: always
|
||||
|
||||
- store_test_results:
|
||||
path: ~/react-native/reports/junit
|
||||
- store_artifacts:
|
||||
path: ~/react-native/yarn.lock
|
||||
|
||||
# -------------------------
|
||||
# JOBS: Test JavaScript
|
||||
# -------------------------
|
||||
# Runs JavaScript tests on Node 8
|
||||
test_javascript:
|
||||
<<: *js_defaults
|
||||
|
@ -398,74 +558,223 @@ jobs:
|
|||
- attach_workspace:
|
||||
at: ~/react-native
|
||||
|
||||
- run: *run-js-tests
|
||||
- run:
|
||||
name: JavaScript Test Suite
|
||||
command: node ./scripts/run-ci-javascript-tests.js --maxWorkers 2
|
||||
|
||||
- store_test_results:
|
||||
path: ~/react-native/reports/junit
|
||||
|
||||
# Run JavaScript tests on Node 10
|
||||
test_node10:
|
||||
# Run JavaScript tests on Node LTS
|
||||
test_node_lts:
|
||||
<<: *defaults
|
||||
docker:
|
||||
- image: circleci/node:10
|
||||
environment:
|
||||
- PATH: "/opt/yarn/yarn-v1.5.1/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
||||
- image: node:lts
|
||||
steps:
|
||||
- checkout
|
||||
- run: *setup-artifacts
|
||||
|
||||
- run: *yarn
|
||||
- run: *run-js-tests
|
||||
- run: yarn run format-check
|
||||
|
||||
- run:
|
||||
name: JavaScript Test Suite
|
||||
command: node ./scripts/run-ci-javascript-tests.js --maxWorkers 2
|
||||
|
||||
- store_test_results:
|
||||
path: ~/react-native/reports/junit
|
||||
|
||||
# -------------------------
|
||||
# JOBS: Test iOS
|
||||
# -------------------------
|
||||
# Runs unit tests on iOS devices
|
||||
test_ios:
|
||||
<<: *macos_defaults
|
||||
environment:
|
||||
- REPORTS_DIR: "./reports"
|
||||
steps:
|
||||
- attach_workspace:
|
||||
at: ~/react-native
|
||||
|
||||
- run: *boot-simulator-iphone
|
||||
- run:
|
||||
name: Print Xcode environment
|
||||
command: xcodebuild -version
|
||||
|
||||
- restore-cache: *restore-cache-homebrew
|
||||
- run: *brew-install-watchman
|
||||
- save-cache: *save-cache-homebrew
|
||||
- run: *run-objc-ios-tests
|
||||
- run:
|
||||
name: List available devices
|
||||
command: instruments -s devices
|
||||
|
||||
- run:
|
||||
name: Boot iOS Simulator
|
||||
command: source scripts/.tests.env && xcrun simctl boot "$IOS_DEVICE" || true
|
||||
|
||||
- restore-cache: *restore-brew-cache
|
||||
- run:
|
||||
name: Install Watchman
|
||||
command: |
|
||||
HOMEBREW_NO_AUTO_UPDATE=1 brew install watchman >/dev/null
|
||||
touch .watchmanconfig
|
||||
- save-cache: *save-brew-cache
|
||||
|
||||
- run:
|
||||
name: Start Metro packager
|
||||
command: yarn start --max-workers=1 || echo "Can't start packager automatically"
|
||||
background: true
|
||||
|
||||
- run:
|
||||
name: Start WebSocket test server
|
||||
command: open "./IntegrationTests/launchWebSocketServer.command" || echo "Can't start web socket server automatically"
|
||||
background: true
|
||||
|
||||
- run:
|
||||
name: Verify RNTester can be built
|
||||
command: |
|
||||
source ./scripts/.tests.env
|
||||
xcodebuild \
|
||||
-project RNTester/RNTester.xcodeproj \
|
||||
-scheme RNTester \
|
||||
-sdk iphonesimulator \
|
||||
-destination "platform=iOS Simulator,name=$IOS_DEVICE,OS=$IOS_TARGET_OS" \
|
||||
-UseModernBuildSystem=NO \
|
||||
build | \
|
||||
xcpretty --report junit --output "$REPORTS_DIR/junit/ios_buiild/results.xml" && \
|
||||
exit "${PIPESTATUS[0]}"
|
||||
|
||||
- run:
|
||||
name: Wait for Metro packager
|
||||
command: |
|
||||
max_attempts=60
|
||||
attempt_num=1
|
||||
until curl -s http://localhost:8081/status | grep "packager-status:running" -q; do
|
||||
if (( attempt_num == max_attempts )); then
|
||||
echo "Packager did not respond in time. No more attempts left."
|
||||
exit 1
|
||||
else
|
||||
(( attempt_num++ ))
|
||||
echo "Packager did not respond. Retrying for attempt number $attempt_num..."
|
||||
sleep 1
|
||||
fi
|
||||
done
|
||||
echo "Packager is ready!"
|
||||
|
||||
- run:
|
||||
name: Preload the RNTesterApp bundles
|
||||
command: |
|
||||
curl --silent 'http://localhost:8081/RNTester/js/RNTesterApp.ios.bundle?platform=ios&dev=true' --output /dev/null
|
||||
curl --silent 'http://localhost:8081/RNTester/js/RNTesterApp.ios.bundle?platform=ios&dev=true&minify=false' --output /dev/null
|
||||
curl --silent 'http://localhost:8081/IntegrationTests/IntegrationTestsApp.bundle?platform=ios&dev=true' --output /dev/null
|
||||
curl --silent 'http://localhost:8081/IntegrationTests/RCTRootViewIntegrationTestApp.bundle?platform=ios&dev=true' --output /dev/null
|
||||
|
||||
- run:
|
||||
name: Run RNTester Unit Tests
|
||||
command: |
|
||||
source ./scripts/.tests.env
|
||||
xcodebuild \
|
||||
-project RNTester/RNTester.xcodeproj \
|
||||
-scheme RNTester \
|
||||
-sdk iphonesimulator \
|
||||
-destination "platform=iOS Simulator,name=$IOS_DEVICE,OS=$IOS_TARGET_OS" \
|
||||
-UseModernBuildSystem=NO \
|
||||
-only-testing:RNTesterUnitTests \
|
||||
build test | \
|
||||
xcpretty --report junit --output "$REPORTS_DIR/junit/ios_unit_tests/results.xml" && \
|
||||
exit "${PIPESTATUS[0]}"
|
||||
|
||||
- run:
|
||||
name: Run RNTester Integration Tests
|
||||
command: |
|
||||
source ./scripts/.tests.env
|
||||
xcodebuild \
|
||||
-project RNTester/RNTester.xcodeproj \
|
||||
-scheme RNTester \
|
||||
-sdk iphonesimulator \
|
||||
-destination "platform=iOS Simulator,name=$IOS_DEVICE,OS=$IOS_TARGET_OS" \
|
||||
-UseModernBuildSystem=NO \
|
||||
-only-testing:RNTesterIntegrationTests \
|
||||
build test | \
|
||||
xcpretty --report junit --output "$REPORTS_DIR/junit/ios_integration_tests/results.xml" && \
|
||||
exit "${PIPESTATUS[0]}"
|
||||
|
||||
- run:
|
||||
name: Stop Metro packager and WebSocket test server
|
||||
command: |
|
||||
# kill whatever is occupying port 8081 (packager)
|
||||
lsof -i tcp:8081 | awk 'NR!=1 {print $2}' | xargs kill
|
||||
# kill whatever is occupying port 5555 (web socket server)
|
||||
lsof -i tcp:5555 | awk 'NR!=1 {print $2}' | xargs kill
|
||||
|
||||
- store_test_results:
|
||||
path: ~/react-native/reports/junit
|
||||
|
||||
# Runs end to end tests (Detox)
|
||||
test_detox_end_to_end:
|
||||
# Runs end-to-end tests
|
||||
test_end_to_end:
|
||||
<<: *macos_defaults
|
||||
steps:
|
||||
- attach_workspace:
|
||||
at: ~/react-native
|
||||
- run: xcrun simctl boot "iPhone 5s" || true
|
||||
|
||||
- run:
|
||||
name: Boot iPhone Simulator
|
||||
command: source scripts/.tests.env && xcrun simctl boot "$IOS_DEVICE" || true
|
||||
|
||||
- run:
|
||||
name: Configure Environment Variables
|
||||
command: |
|
||||
echo 'export PATH=/usr/local/opt/node@8/bin:$PATH' >> $BASH_ENV
|
||||
source $BASH_ENV
|
||||
|
||||
# Brew
|
||||
- restore-cache: *restore-brew-cache
|
||||
- run:
|
||||
name: Install Node 8
|
||||
name: Configure Detox Environment
|
||||
command: |
|
||||
brew install node@8
|
||||
brew link node@8
|
||||
brew tap wix/brew
|
||||
brew install applesimutils
|
||||
HOMEBREW_NO_AUTO_UPDATE=1 brew install node@8 >/dev/null
|
||||
HOMEBREW_NO_AUTO_UPDATE=1 brew tap wix/brew >/dev/null
|
||||
HOMEBREW_NO_AUTO_UPDATE=1 brew install applesimutils >/dev/null
|
||||
touch .watchmanconfig
|
||||
node -v
|
||||
- save-cache: *save-brew-cache
|
||||
|
||||
# Yarn install
|
||||
- restore-cache: *restore-yarn-cache
|
||||
- run: *yarn
|
||||
- save-cache: *save-yarn-cache
|
||||
|
||||
# Xcode build
|
||||
- run:
|
||||
name: Build iOS app for simulator
|
||||
name: Build app for Detox iOS End-to-End Tests
|
||||
command: yarn run build-ios-e2e
|
||||
- run:
|
||||
name: Run Detox Tests
|
||||
command: yarn run test-ios-e2e
|
||||
|
||||
# Set up an Android environment for downstream jobs
|
||||
# Test
|
||||
- run:
|
||||
name: Run Detox iOS End-to-End Tests
|
||||
command: yarn run test-ios-e2e
|
||||
when: always
|
||||
|
||||
- run:
|
||||
name: Run JavaScript End-to-End Tests
|
||||
command: |
|
||||
# free up port 8081 for the packager before running tests
|
||||
set +eo pipefail
|
||||
lsof -i tcp:8081 | awk 'NR!=1 {print $2}' | xargs kill
|
||||
set -eo pipefail
|
||||
node ./scripts/run-ci-e2e-tests.js --js --retries 3
|
||||
when: always
|
||||
|
||||
- run:
|
||||
name: Run iOS End-to-End Tests
|
||||
command: |
|
||||
# free up port 8081 for the packager before running tests
|
||||
set +eo pipefail
|
||||
lsof -i tcp:8081 | awk 'NR!=1 {print $2}' | xargs kill
|
||||
set -eo pipefail
|
||||
node ./scripts/run-ci-e2e-tests.js --ios --retries 3;
|
||||
when: always
|
||||
|
||||
|
||||
# -------------------------
|
||||
# JOBS: Test Android
|
||||
# -------------------------
|
||||
# Run Android tests
|
||||
test_android:
|
||||
<<: *android_defaults
|
||||
steps:
|
||||
|
@ -482,14 +791,22 @@ jobs:
|
|||
- save-cache: *save-cache-android-packages
|
||||
|
||||
# Validate Android SDK installation and packages
|
||||
- run: *validate-android-sdk
|
||||
- run:
|
||||
name: Validate Android SDK Install
|
||||
command: ./scripts/validate-android-sdk.sh
|
||||
|
||||
# Starting emulator in advance as it takes some time to boot.
|
||||
- run: *create-avd
|
||||
- run: *launch-avd
|
||||
- run:
|
||||
name: Create Android Virtual Device
|
||||
command: source scripts/android-setup.sh && createAVD
|
||||
- run:
|
||||
name: Launch Android Virtual Device in Background
|
||||
command: source scripts/android-setup.sh && launchAVD
|
||||
background: true
|
||||
|
||||
# Keep configuring Android dependencies while AVD boots up
|
||||
|
||||
<<<<<<< HEAD
|
||||
# Install Android NDK
|
||||
- run: *create-ndk-directory
|
||||
- restore-cache: *restore-cache-ndk
|
||||
|
@ -500,29 +817,57 @@ jobs:
|
|||
- restore-cache: *restore-cache-downloads-buck
|
||||
- run: *install-buck
|
||||
- save-cache: *save-cache-downloads-buck
|
||||
=======
|
||||
- restore-cache: *restore-buck-downloads-cache
|
||||
- run:
|
||||
name: Install Buck
|
||||
command: |
|
||||
buck --version
|
||||
# Install related tooling
|
||||
if [[ ! -e ~/okbuck ]]; then
|
||||
git clone https://github.com/uber/okbuck.git ~/okbuck --depth=1
|
||||
fi
|
||||
mkdir -p ~/react-native/tooling/junit
|
||||
cp -R ~/okbuck/tooling/junit/* ~/react-native/tooling/junit/.
|
||||
- save-cache: *save-buck-downloads-cache
|
||||
>>>>>>> v0.60.0
|
||||
|
||||
# Validate Android test environment (including Buck)
|
||||
- run: *validate-android-test-env
|
||||
- run:
|
||||
name: Validate Android Test Environment
|
||||
command: ./scripts/validate-android-test-env.sh
|
||||
|
||||
# Download dependencies using Buck
|
||||
- run: *download-dependencies-buck
|
||||
|
||||
# Download dependencies using Gradle
|
||||
- restore-cache: *restore-cache-downloads-gradle
|
||||
- restore-cache: *restore-gradle-downloads-cache
|
||||
- run: *download-dependencies-gradle
|
||||
- save-cache: *save-cache-downloads-gradle
|
||||
- save-cache: *save-gradle-downloads-cache
|
||||
|
||||
# Build and compile
|
||||
- run: *build-android-app
|
||||
- run: *compile-native-libs
|
||||
- run:
|
||||
name: Build Android App
|
||||
command: |
|
||||
buck build ReactAndroid/src/main/java/com/facebook/react
|
||||
buck build ReactAndroid/src/main/java/com/facebook/react/shell
|
||||
- run:
|
||||
name: Compile Native Libs for Unit and Integration Tests
|
||||
command: ./gradlew :ReactAndroid:packageReactNdkLibsForBuck -Pjobs=$BUILD_THREADS
|
||||
no_output_timeout: 6m
|
||||
|
||||
# Build JavaScript Bundle for instrumentation tests
|
||||
- run: *build-js-bundle
|
||||
- run:
|
||||
name: Build JavaScript Bundle
|
||||
command: node cli.js bundle --max-workers 2 --platform android --dev true --entry-file ReactAndroid/src/androidTest/js/TestBundle.js --bundle-output ReactAndroid/src/androidTest/assets/AndroidTestBundle.js
|
||||
|
||||
# Wait for AVD to finish booting before running tests
|
||||
- run: *wait-for-avd
|
||||
- run:
|
||||
name: Wait for Android Virtual Device
|
||||
command: source scripts/android-setup.sh && waitForAVD
|
||||
|
||||
# Test Suite
|
||||
<<<<<<< HEAD
|
||||
- run: *run-android-unit-tests
|
||||
- run: *run-android-instrumentation-tests
|
||||
- run: *build-android-rntester-app
|
||||
|
@ -558,47 +903,59 @@ jobs:
|
|||
|
||||
- restore-cache: *restore-yarn-cache
|
||||
- run: *yarn
|
||||
=======
|
||||
- run:
|
||||
name: Run Unit Tests
|
||||
command: buck test ReactAndroid/src/test/... --config build.threads=$BUILD_THREADS --xml ~/react-native/reports/buck/all-results-raw.xml
|
||||
>>>>>>> v0.60.0
|
||||
|
||||
- run:
|
||||
name: Analyze Shell Scripts
|
||||
name: Run Instrumentation Tests
|
||||
command: |
|
||||
echo -e "\\x1B[36mInstalling additional dependencies\\x1B[0m"
|
||||
sudo apt-get install -y shellcheck
|
||||
yarn add @octokit/rest@15.18.0
|
||||
echo -e "\\x1B[36mAnalyzing shell scripts\\x1B[0m"; \
|
||||
GITHUB_TOKEN="$PUBLIC_ANALYSISBOT_GITHUB_TOKEN_A""$PUBLIC_ANALYSISBOT_GITHUB_TOKEN_B" \
|
||||
GITHUB_OWNER="$CIRCLE_PROJECT_USERNAME" \
|
||||
GITHUB_REPO="$CIRCLE_PROJECT_REPONAME" \
|
||||
GITHUB_PR_NUMBER="$CIRCLE_PR_NUMBER" \
|
||||
./scripts/circleci/analyze_scripts.sh
|
||||
when: always
|
||||
if [[ ! -e ReactAndroid/src/androidTest/assets/AndroidTestBundle.js ]]; then
|
||||
echo "JavaScript bundle missing, cannot run instrumentation tests. Verify Build JavaScript Bundle step completed successfully."; exit 1;
|
||||
fi
|
||||
source scripts/android-setup.sh && NO_BUCKD=1 retry3 timeout 300 buck install ReactAndroid/src/androidTest/buck-runner:instrumentation-tests --config build.threads=$BUILD_THREADS
|
||||
|
||||
- restore-cache: *restore-cache-analysis
|
||||
- run:
|
||||
name: Analyze Code
|
||||
command: |
|
||||
echo -e "\\x1B[36mInstalling additional dependencies\\x1B[0m"; yarn add @octokit/rest@15.18.0
|
||||
echo -e "\\x1B[36mAnalyzing code\\x1B[0m"; \
|
||||
GITHUB_TOKEN="$PUBLIC_ANALYSISBOT_GITHUB_TOKEN_A""$PUBLIC_ANALYSISBOT_GITHUB_TOKEN_B" \
|
||||
GITHUB_OWNER="$CIRCLE_PROJECT_USERNAME" \
|
||||
GITHUB_REPO="$CIRCLE_PROJECT_REPONAME" \
|
||||
GITHUB_PR_NUMBER="$CIRCLE_PR_NUMBER" \
|
||||
./scripts/circleci/analyze_code.sh
|
||||
when: always
|
||||
name: Build Android RNTester App
|
||||
command: ./gradlew RNTester:android:app:assembleRelease
|
||||
|
||||
# Collect Results
|
||||
- run:
|
||||
name: Analyze Pull Request
|
||||
name: Collect Test Results
|
||||
command: |
|
||||
echo -e "\\x1B[36mInstalling additional dependencies\\x1B[0m"
|
||||
cd bots
|
||||
yarn install --non-interactive --cache-folder ~/.cache/yarn
|
||||
echo -e "\\x1B[36mAnalyzing pull request\\x1B[0m"; \
|
||||
DANGER_GITHUB_API_TOKEN="$PUBLIC_PULLBOT_GITHUB_TOKEN_A""$PUBLIC_PULLBOT_GITHUB_TOKEN_B" \
|
||||
yarn danger ci --use-github-checks
|
||||
find . -type f -regex ".*/build/test-results/debug/.*xml" -exec cp {} ~/react-native/reports/build/ \;
|
||||
find . -type f -regex ".*/outputs/androidTest-results/connected/.*xml" -exec cp {} ~/react-native/reports/outputs/ \;
|
||||
find . -type f -regex ".*/buck-out/gen/ReactAndroid/src/test/.*/.*xml" -exec cp {} ~/react-native/reports/buck/ \;
|
||||
./tooling/junit/buck_to_junit.sh ~/react-native/reports/buck/all-results-raw.xml ~/react-native/reports/junit/all-results-junit.xml
|
||||
when: always
|
||||
- save-cache: *save-cache-analysis
|
||||
|
||||
# Test Coverage
|
||||
- store_test_results:
|
||||
path: ~/react-native/reports/junit
|
||||
|
||||
# -------------------------
|
||||
# JOBS: Test Docker Build
|
||||
# -------------------------
|
||||
test_docker_build:
|
||||
machine: true
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: Build Docker container for Android RNTester App
|
||||
command: |
|
||||
source ~/.bashrc
|
||||
nvm i node
|
||||
npm i -g yarn
|
||||
npx envinfo@latest
|
||||
yarn run docker-setup-android
|
||||
yarn run docker-build-android
|
||||
|
||||
# -------------------------
|
||||
# JOBS: Coverage
|
||||
# -------------------------
|
||||
# Collect JavaScript test coverage
|
||||
js_coverage:
|
||||
<<: *js_defaults
|
||||
environment:
|
||||
|
@ -610,10 +967,18 @@ jobs:
|
|||
- checkout
|
||||
- restore-cache: *restore-yarn-cache
|
||||
- run: *yarn
|
||||
- run: *js-coverage
|
||||
- run:
|
||||
name: Test coverage
|
||||
command: |
|
||||
yarn test --coverage --maxWorkers=2
|
||||
cat ./coverage/lcov.info | ./node_modules/.bin/coveralls
|
||||
when: always
|
||||
- store_artifacts:
|
||||
path: ~/react-native/coverage/
|
||||
|
||||
# -------------------------
|
||||
# JOBS: Releases
|
||||
# -------------------------
|
||||
# Publishes new version onto npm
|
||||
# Only works on stable branches when a properly tagged commit is pushed
|
||||
publish_npm_package:
|
||||
|
@ -634,10 +999,18 @@ jobs:
|
|||
- run: *install-ndk
|
||||
|
||||
# Fetch dependencies using Buck
|
||||
<<<<<<< HEAD
|
||||
- run: *install-buck
|
||||
- run: *download-dependencies-buck
|
||||
|
||||
# Fetch dependencies using Gradle
|
||||
=======
|
||||
- restore-cache: *restore-buck-downloads-cache
|
||||
- run: *download-dependencies-buck
|
||||
|
||||
# Fetch dependencies using Gradle
|
||||
- restore-cache: *restore-gradle-downloads-cache
|
||||
>>>>>>> v0.60.0
|
||||
- run: *download-dependencies-gradle
|
||||
|
||||
- run:
|
||||
|
@ -651,20 +1024,23 @@ jobs:
|
|||
git config --global user.name "npm Deployment Script"
|
||||
echo "machine github.com login react-native-bot password $GITHUB_TOKEN" > ~/.netrc
|
||||
|
||||
# Build and publish release. Requires an Android environment.
|
||||
- run:
|
||||
name: Publish React Native Package
|
||||
command: node ./scripts/publish-npm.js
|
||||
|
||||
# Workflows enables us to run multiple jobs in parallel
|
||||
# -------------------------
|
||||
# WORK FLOWS
|
||||
# -------------------------
|
||||
workflows:
|
||||
version: 2
|
||||
|
||||
tests:
|
||||
jobs:
|
||||
# Checkout repo and run Yarn
|
||||
- checkout_code:
|
||||
- test_node_lts:
|
||||
filters: *filter-ignore-gh-pages
|
||||
|
||||
<<<<<<< HEAD
|
||||
# Run lint, flow, and other checks
|
||||
- analyze:
|
||||
filters: *filter-ignore-gh-pages
|
||||
|
@ -694,36 +1070,34 @@ workflows:
|
|||
- checkout_code
|
||||
|
||||
- test_detox_end_to_end:
|
||||
=======
|
||||
- checkout_code:
|
||||
>>>>>>> v0.60.0
|
||||
filters: *filter-ignore-gh-pages
|
||||
requires:
|
||||
- checkout_code
|
||||
|
||||
# Tooling Compatibility Checks
|
||||
- test_node10:
|
||||
- analyze: *run-after-checkout
|
||||
- test_javascript: *run-after-checkout
|
||||
- test_android: *run-after-checkout
|
||||
- test_ios: *run-after-checkout
|
||||
- test_end_to_end: *run-after-checkout
|
||||
- test_docker_build:
|
||||
filters: *filter-ignore-gh-pages
|
||||
|
||||
releases:
|
||||
jobs:
|
||||
# Only runs on vX.X.X tags if all tests are green
|
||||
- checkout_code:
|
||||
filters: *filter-only-version-tags
|
||||
- publish_npm_package:
|
||||
filters:
|
||||
# ignore any commit on any branch by default
|
||||
branches:
|
||||
ignore: /.*/
|
||||
# only act on version tags
|
||||
tags:
|
||||
only: /v[0-9]+(\.[0-9]+)*(\-rc(\.[0-9]+)?)?/
|
||||
filters: *filter-only-version-tags
|
||||
requires:
|
||||
- checkout_code
|
||||
|
||||
analysis:
|
||||
jobs:
|
||||
# Run code checks on PRs from forks
|
||||
- analyze_pr:
|
||||
filters:
|
||||
branches:
|
||||
only: /^pull\/.*$/
|
||||
filters: *filter-only-forked-pull-requests
|
||||
|
||||
# Gather coverage on master
|
||||
- js_coverage:
|
||||
filters:
|
||||
branches:
|
||||
only: master
|
||||
filters: *filter-only-master
|
||||
|
|
|
@ -4,7 +4,8 @@
|
|||
**/main.js
|
||||
Libraries/vendor/**/*
|
||||
Libraries/Renderer/*
|
||||
packages/*/node_modules
|
||||
pr-inactivity-bookmarklet.js
|
||||
question-bookmarklet.js
|
||||
flow/
|
||||
danger/
|
||||
bots/node_modules
|
257
.eslintrc
257
.eslintrc
|
@ -1,263 +1,10 @@
|
|||
{
|
||||
"root": true,
|
||||
|
||||
"parser": "babel-eslint",
|
||||
|
||||
"env": {
|
||||
"es6": true,
|
||||
},
|
||||
|
||||
"plugins": [
|
||||
"eslint-comments",
|
||||
"flowtype",
|
||||
"prettier",
|
||||
"react",
|
||||
"react-hooks",
|
||||
"react-native",
|
||||
"jest",
|
||||
"extends": [
|
||||
"./packages/eslint-config-react-native-community/index.js"
|
||||
],
|
||||
|
||||
// Map from global var to bool specifying if it can be redefined
|
||||
"globals": {
|
||||
"__DEV__": true,
|
||||
"__dirname": false,
|
||||
"__fbBatchedBridgeConfig": false,
|
||||
"alert": false,
|
||||
"cancelAnimationFrame": false,
|
||||
"cancelIdleCallback": false,
|
||||
"clearImmediate": true,
|
||||
"clearInterval": false,
|
||||
"clearTimeout": false,
|
||||
"console": false,
|
||||
"document": false,
|
||||
"escape": false,
|
||||
"Event": false,
|
||||
"EventTarget": false,
|
||||
"exports": false,
|
||||
"fetch": false,
|
||||
"FormData": false,
|
||||
"global": false,
|
||||
"Map": true,
|
||||
"module": false,
|
||||
"navigator": false,
|
||||
"process": false,
|
||||
"Promise": true,
|
||||
"requestAnimationFrame": true,
|
||||
"requestIdleCallback": true,
|
||||
"require": false,
|
||||
"Set": true,
|
||||
"setImmediate": true,
|
||||
"setInterval": false,
|
||||
"setTimeout": false,
|
||||
"window": false,
|
||||
"XMLHttpRequest": false,
|
||||
},
|
||||
|
||||
"rules": {
|
||||
// General
|
||||
"comma-dangle": [1, "always-multiline"], // allow or disallow trailing commas
|
||||
"no-cond-assign": 1, // disallow assignment in conditional expressions
|
||||
"no-console": 0, // disallow use of console (off by default in the node environment)
|
||||
"no-const-assign": 2, // disallow assignment to const-declared variables
|
||||
"no-constant-condition": 0, // disallow use of constant expressions in conditions
|
||||
"no-control-regex": 1, // disallow control characters in regular expressions
|
||||
"no-debugger": 1, // disallow use of debugger
|
||||
"no-dupe-class-members": 2, // Disallow duplicate name in class members
|
||||
"no-dupe-keys": 2, // disallow duplicate keys when creating object literals
|
||||
"no-empty": 0, // disallow empty statements
|
||||
"no-ex-assign": 1, // disallow assigning to the exception in a catch block
|
||||
"no-extra-boolean-cast": 1, // disallow double-negation boolean casts in a boolean context
|
||||
"no-extra-parens": 0, // disallow unnecessary parentheses (off by default)
|
||||
"no-extra-semi": 1, // disallow unnecessary semicolons
|
||||
"no-func-assign": 1, // disallow overwriting functions written as function declarations
|
||||
"no-inner-declarations": 0, // disallow function or variable declarations in nested blocks
|
||||
"no-invalid-regexp": 1, // disallow invalid regular expression strings in the RegExp constructor
|
||||
"no-negated-in-lhs": 1, // disallow negation of the left operand of an in expression
|
||||
"no-obj-calls": 1, // disallow the use of object properties of the global object (Math and JSON) as functions
|
||||
"no-regex-spaces": 1, // disallow multiple spaces in a regular expression literal
|
||||
"no-reserved-keys": 0, // disallow reserved words being used as object literal keys (off by default)
|
||||
"no-sparse-arrays": 1, // disallow sparse arrays
|
||||
"no-unreachable": 2, // disallow unreachable statements after a return, throw, continue, or break statement
|
||||
"use-isnan": 1, // disallow comparisons with the value NaN
|
||||
"valid-jsdoc": 0, // Ensure JSDoc comments are valid (off by default)
|
||||
"valid-typeof": 1, // Ensure that the results of typeof are compared against a valid string
|
||||
|
||||
// Best Practices
|
||||
// These are rules designed to prevent you from making mistakes. They either prescribe a better way of doing something or help you avoid footguns.
|
||||
|
||||
"block-scoped-var": 0, // treat var statements as if they were block scoped (off by default)
|
||||
"complexity": 0, // specify the maximum cyclomatic complexity allowed in a program (off by default)
|
||||
"consistent-return": 0, // require return statements to either always or never specify values
|
||||
"curly": 1, // specify curly brace conventions for all control statements
|
||||
"default-case": 0, // require default case in switch statements (off by default)
|
||||
"dot-notation": 1, // encourages use of dot notation whenever possible
|
||||
"eqeqeq": [1, "allow-null"], // require the use of === and !==
|
||||
"guard-for-in": 0, // make sure for-in loops have an if statement (off by default)
|
||||
"no-alert": 1, // disallow the use of alert, confirm, and prompt
|
||||
"no-caller": 1, // disallow use of arguments.caller or arguments.callee
|
||||
"no-div-regex": 1, // disallow division operators explicitly at beginning of regular expression (off by default)
|
||||
"no-else-return": 0, // disallow else after a return in an if (off by default)
|
||||
"no-eq-null": 0, // disallow comparisons to null without a type-checking operator (off by default)
|
||||
"no-eval": 2, // disallow use of eval()
|
||||
"no-extend-native": 1, // disallow adding to native types
|
||||
"no-extra-bind": 1, // disallow unnecessary function binding
|
||||
"no-fallthrough": 1, // disallow fallthrough of case statements
|
||||
"no-floating-decimal": 1, // disallow the use of leading or trailing decimal points in numeric literals (off by default)
|
||||
"no-implied-eval": 1, // disallow use of eval()-like methods
|
||||
"no-labels": 1, // disallow use of labeled statements
|
||||
"no-iterator": 1, // disallow usage of __iterator__ property
|
||||
"no-lone-blocks": 1, // disallow unnecessary nested blocks
|
||||
"no-loop-func": 0, // disallow creation of functions within loops
|
||||
"no-multi-str": 0, // disallow use of multiline strings
|
||||
"no-native-reassign": 0, // disallow reassignments of native objects
|
||||
"no-new": 1, // disallow use of new operator when not part of the assignment or comparison
|
||||
"no-new-func": 2, // disallow use of new operator for Function object
|
||||
"no-new-wrappers": 1, // disallows creating new instances of String,Number, and Boolean
|
||||
"no-octal": 1, // disallow use of octal literals
|
||||
"no-octal-escape": 1, // disallow use of octal escape sequences in string literals, such as var foo = "Copyright \251";
|
||||
"no-proto": 1, // disallow usage of __proto__ property
|
||||
"no-redeclare": 0, // disallow declaring the same variable more then once
|
||||
"no-return-assign": 1, // disallow use of assignment in return statement
|
||||
"no-script-url": 1, // disallow use of javascript: urls.
|
||||
"no-self-compare": 1, // disallow comparisons where both sides are exactly the same (off by default)
|
||||
"no-sequences": 1, // disallow use of comma operator
|
||||
"no-unused-expressions": 0, // disallow usage of expressions in statement position
|
||||
"no-void": 1, // disallow use of void operator (off by default)
|
||||
"no-warning-comments": 0, // disallow usage of configurable warning terms in comments": 1, // e.g. TODO or FIXME (off by default)
|
||||
"no-with": 1, // disallow use of the with statement
|
||||
"radix": 1, // require use of the second argument for parseInt() (off by default)
|
||||
"semi-spacing": 1, // require a space after a semi-colon
|
||||
"vars-on-top": 0, // requires to declare all vars on top of their containing scope (off by default)
|
||||
"wrap-iife": 0, // require immediate function invocation to be wrapped in parentheses (off by default)
|
||||
"yoda": 1, // require or disallow Yoda conditions
|
||||
|
||||
// Variables
|
||||
// These rules have to do with variable declarations.
|
||||
|
||||
"no-catch-shadow": 1, // disallow the catch clause parameter name being the same as a variable in the outer scope (off by default in the node environment)
|
||||
"no-delete-var": 1, // disallow deletion of variables
|
||||
"no-label-var": 1, // disallow labels that share a name with a variable
|
||||
"no-shadow": 1, // disallow declaration of variables already declared in the outer scope
|
||||
"no-shadow-restricted-names": 1, // disallow shadowing of names such as arguments
|
||||
"no-undef": 2, // disallow use of undeclared variables unless mentioned in a /*global */ block
|
||||
"no-undefined": 0, // disallow use of undefined variable (off by default)
|
||||
"no-undef-init": 1, // disallow use of undefined when initializing variables
|
||||
"no-unused-vars": [1, {"vars": "all", "args": "none", ignoreRestSiblings: true}], // disallow declaration of variables that are not used in the code
|
||||
"no-use-before-define": 0, // disallow use of variables before they are defined
|
||||
|
||||
// Node.js
|
||||
// These rules are specific to JavaScript running on Node.js.
|
||||
|
||||
"handle-callback-err": 1, // enforces error handling in callbacks (off by default) (on by default in the node environment)
|
||||
"no-mixed-requires": 1, // disallow mixing regular variable and require declarations (off by default) (on by default in the node environment)
|
||||
"no-new-require": 1, // disallow use of new operator with the require function (off by default) (on by default in the node environment)
|
||||
"no-path-concat": 1, // disallow string concatenation with __dirname and __filename (off by default) (on by default in the node environment)
|
||||
"no-process-exit": 0, // disallow process.exit() (on by default in the node environment)
|
||||
"no-restricted-modules": 1, // restrict usage of specified node modules (off by default)
|
||||
"no-sync": 0, // disallow use of synchronous methods (off by default)
|
||||
|
||||
// ESLint Comments Plugin
|
||||
// The following rules are made available via `eslint-plugin-eslint-comments`
|
||||
"eslint-comments/no-aggregating-enable": 1, // disallows eslint-enable comments for multiple eslint-disable comments
|
||||
"eslint-comments/no-unlimited-disable": 1, // disallows eslint-disable comments without rule names
|
||||
"eslint-comments/no-unused-disable": 1, // disallow disables that don't cover any errors
|
||||
"eslint-comments/no-unused-enable": 1, // // disallow enables that don't enable anything or enable rules that weren't disabled
|
||||
|
||||
// Flow Plugin
|
||||
// The following rules are made available via `eslint-plugin-flowtype`
|
||||
"flowtype/define-flow-type": 1,
|
||||
"flowtype/use-flow-type": 1,
|
||||
|
||||
// Prettier Plugin
|
||||
// https://github.com/prettier/eslint-plugin-prettier
|
||||
"prettier/prettier": [2, "fb", "@format"],
|
||||
|
||||
// Stylistic Issues
|
||||
// These rules are purely matters of style and are quite subjective.
|
||||
|
||||
"key-spacing": 0,
|
||||
"keyword-spacing": 1, // enforce spacing before and after keywords
|
||||
"jsx-quotes": [1, "prefer-double"], // enforces the usage of double quotes for all JSX attribute values which doesn’t contain a double quote
|
||||
"comma-spacing": 0,
|
||||
"no-multi-spaces": 0,
|
||||
"brace-style": 0, // enforce one true brace style (off by default)
|
||||
"camelcase": 0, // require camel case names
|
||||
"consistent-this": 1, // enforces consistent naming when capturing the current execution context (off by default)
|
||||
"eol-last": 1, // enforce newline at the end of file, with no multiple empty lines
|
||||
"func-names": 0, // require function expressions to have a name (off by default)
|
||||
"func-style": 0, // enforces use of function declarations or expressions (off by default)
|
||||
"new-cap": 0, // require a capital letter for constructors
|
||||
"new-parens": 1, // disallow the omission of parentheses when invoking a constructor with no arguments
|
||||
"no-nested-ternary": 0, // disallow nested ternary expressions (off by default)
|
||||
"no-array-constructor": 1, // disallow use of the Array constructor
|
||||
"no-empty-character-class": 1, // disallow the use of empty character classes in regular expressions
|
||||
"no-lonely-if": 0, // disallow if as the only statement in an else block (off by default)
|
||||
"no-new-object": 1, // disallow use of the Object constructor
|
||||
"no-spaced-func": 1, // disallow space between function identifier and application
|
||||
"no-ternary": 0, // disallow the use of ternary operators (off by default)
|
||||
"no-trailing-spaces": 1, // disallow trailing whitespace at the end of lines
|
||||
"no-underscore-dangle": 0, // disallow dangling underscores in identifiers
|
||||
"no-mixed-spaces-and-tabs": 1, // disallow mixed spaces and tabs for indentation
|
||||
"quotes": [1, "single", "avoid-escape"], // specify whether double or single quotes should be used
|
||||
"quote-props": 0, // require quotes around object literal property names (off by default)
|
||||
"semi": 1, // require or disallow use of semicolons instead of ASI
|
||||
"sort-vars": 0, // sort variables within the same declaration block (off by default)
|
||||
"space-in-brackets": 0, // require or disallow spaces inside brackets (off by default)
|
||||
"space-in-parens": 0, // require or disallow spaces inside parentheses (off by default)
|
||||
"space-infix-ops": 1, // require spaces around operators
|
||||
"space-unary-ops": [1, { "words": true, "nonwords": false }], // require or disallow spaces before/after unary operators (words on by default, nonwords off by default)
|
||||
"max-nested-callbacks": 0, // specify the maximum depth callbacks can be nested (off by default)
|
||||
"one-var": 0, // allow just one var statement per function (off by default)
|
||||
"wrap-regex": 0, // require regex literals to be wrapped in parentheses (off by default)
|
||||
|
||||
// Legacy
|
||||
// The following rules are included for compatibility with JSHint and JSLint. While the names of the rules may not match up with the JSHint/JSLint counterpart, the functionality is the same.
|
||||
|
||||
"max-depth": 0, // specify the maximum depth that blocks can be nested (off by default)
|
||||
"max-len": 0, // specify the maximum length of a line in your program (off by default)
|
||||
"max-params": 0, // limits the number of parameters that can be used in the function declaration. (off by default)
|
||||
"max-statements": 0, // specify the maximum number of statement allowed in a function (off by default)
|
||||
"no-bitwise": 1, // disallow use of bitwise operators (off by default)
|
||||
"no-plusplus": 0, // disallow use of unary operators, ++ and -- (off by default)
|
||||
|
||||
// React Plugin
|
||||
// The following rules are made available via `eslint-plugin-react`.
|
||||
|
||||
"react/display-name": 0,
|
||||
"react/jsx-boolean-value": 0,
|
||||
"react/jsx-no-comment-textnodes": 1,
|
||||
"react/jsx-no-duplicate-props": 2,
|
||||
"react/jsx-no-undef": 2,
|
||||
"react/jsx-sort-props": 0,
|
||||
"react/jsx-uses-react": 1,
|
||||
"react/jsx-uses-vars": 1,
|
||||
"react/no-did-mount-set-state": 1,
|
||||
"react/no-did-update-set-state": 1,
|
||||
"react/no-multi-comp": 0,
|
||||
"react/no-string-refs": 1,
|
||||
"react/no-unknown-property": 0,
|
||||
"react/prop-types": 0,
|
||||
"react/react-in-jsx-scope": 1,
|
||||
"react/self-closing-comp": 1,
|
||||
"react/wrap-multilines": 0,
|
||||
|
||||
// React-Hooks Plugin
|
||||
// The following rules are made available via `eslint-plugin-react-hooks`
|
||||
"react-hooks/rules-of-hooks": "error",
|
||||
|
||||
// React-Native Plugin
|
||||
// The following rules are made available via `eslint-plugin-react-native`
|
||||
|
||||
"react-native/no-inline-styles": 1,
|
||||
|
||||
// Jest Plugin
|
||||
// The following rules are made available via `eslint-plugin-jest`.
|
||||
"jest/no-disabled-tests": 1,
|
||||
"jest/no-focused-tests": 1,
|
||||
"jest/no-identical-title": 1,
|
||||
"jest/valid-expect": 1,
|
||||
},
|
||||
|
||||
"overrides": [
|
||||
{
|
||||
"files": [
|
||||
|
|
11
.flowconfig
11
.flowconfig
|
@ -33,6 +33,9 @@
|
|||
; require from fbjs/lib instead: require('fbjs/lib/warning')
|
||||
.*/node_modules/warning/.*
|
||||
|
||||
; Flow doesn't support platforms
|
||||
.*/Libraries/Utilities/HMRLoadingView.js
|
||||
|
||||
[untyped]
|
||||
.*/node_modules/@react-native-community/cli/.*/.*
|
||||
|
||||
|
@ -48,6 +51,10 @@ emoji=true
|
|||
esproposal.optional_chaining=enable
|
||||
esproposal.nullish_coalescing=enable
|
||||
|
||||
module.file_ext=.js
|
||||
module.file_ext=.json
|
||||
module.file_ext=.ios.js
|
||||
|
||||
module.system=haste
|
||||
module.system.haste.use_name_reducers=true
|
||||
# keep the following in sync with server/haste/hasteImpl.js
|
||||
|
@ -79,7 +86,6 @@ suppress_type=$FlowFixMeState
|
|||
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(<VERSION>\\)? *\\(site=[a-z,_]*react_native\\(_ios\\)?_\\(oss\\|fb\\)[a-z,_]*\\)?)\\)
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(<VERSION>\\)? *\\(site=[a-z,_]*react_native\\(_ios\\)?_\\(oss\\|fb\\)[a-z,_]*\\)?)\\)?:? #[0-9]+
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError
|
||||
|
||||
[lints]
|
||||
|
@ -92,7 +98,6 @@ deprecated-type=warn
|
|||
unsafe-getters-setters=warn
|
||||
inexact-spread=warn
|
||||
unnecessary-invariant=warn
|
||||
deprecated-call-syntax=warn
|
||||
signature-verification-failure=warn
|
||||
deprecated-utility=error
|
||||
|
||||
|
@ -106,4 +111,4 @@ untyped-import
|
|||
untyped-type-import
|
||||
|
||||
[version]
|
||||
^0.92.0
|
||||
^0.98.0
|
||||
|
|
|
@ -35,6 +35,9 @@
|
|||
; require from fbjs/lib instead: require('fbjs/lib/warning')
|
||||
.*/node_modules/warning/.*
|
||||
|
||||
; Flow doesn't support platforms
|
||||
.*/Libraries/Utilities/HMRLoadingView.js
|
||||
|
||||
[untyped]
|
||||
.*/node_modules/@react-native-community/cli/.*/.*
|
||||
|
||||
|
@ -50,6 +53,10 @@ emoji=true
|
|||
esproposal.optional_chaining=enable
|
||||
esproposal.nullish_coalescing=enable
|
||||
|
||||
module.file_ext=.js
|
||||
module.file_ext=.json
|
||||
module.file_ext=.android.js
|
||||
|
||||
module.system=haste
|
||||
module.system.haste.use_name_reducers=true
|
||||
# keep the following in sync with server/haste/hasteImpl.js
|
||||
|
@ -80,7 +87,6 @@ suppress_type=$FlowFixMeState
|
|||
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(<VERSION>\\)? *\\(site=[a-z,_]*react_native\\(_android\\)?_\\(oss\\|fb\\)[a-z,_]*\\)?)\\)
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(<VERSION>\\)? *\\(site=[a-z,_]*react_native\\(_android\\)?_\\(oss\\|fb\\)[a-z,_]*\\)?)\\)?:? #[0-9]+
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError
|
||||
|
||||
[lints]
|
||||
|
@ -93,7 +99,6 @@ deprecated-type=warn
|
|||
unsafe-getters-setters=warn
|
||||
inexact-spread=warn
|
||||
unnecessary-invariant=warn
|
||||
deprecated-call-syntax=warn
|
||||
signature-verification-failure=warn
|
||||
deprecated-utility=error
|
||||
|
||||
|
@ -107,4 +112,4 @@ untyped-import
|
|||
untyped-type-import
|
||||
|
||||
[version]
|
||||
^0.92.0
|
||||
^0.98.0
|
||||
|
|
|
@ -1 +1,41 @@
|
|||
<<<<<<< HEAD
|
||||
** @acoates-ms
|
||||
=======
|
||||
# See https://help.github.com/en/articles/about-code-owners
|
||||
# to learn more about code owners.
|
||||
# Order is important; the last matching pattern takes the most
|
||||
# precedence. You may specify either a GitHub username, or an
|
||||
# email address if you prefer, as the code owner.
|
||||
|
||||
# Any Markdown file anywhere in the repository
|
||||
**/*.md @hramos @cpojer
|
||||
|
||||
# GitHub Settings, Bots
|
||||
/.github/ @hramos
|
||||
/bots @hramos
|
||||
|
||||
# Continuous Integration
|
||||
/.circleci/ @hramos
|
||||
/.circleci/Dockerfiles @gengjiawen
|
||||
/.appveyor/ @gengjiawen
|
||||
|
||||
# Internals
|
||||
React/Base/* @shergin
|
||||
React/Views/* @shergin
|
||||
React/Modules/* @shergin
|
||||
React/CxxBridge/* @mhorowitz
|
||||
|
||||
# Components and APIs
|
||||
ReactAndroid/src/main/java/com/facebook/react/animated/* @janicduplessis
|
||||
Libraries/Animated/* @janicduplessis
|
||||
Libraries/NativeAnimation/* @janicduplessis
|
||||
Libraries/Image/* @shergin
|
||||
Libraries/Text/* @shergin
|
||||
|
||||
# Modifications to package.json typically require
|
||||
# additional effort from a Facebook employee to land
|
||||
/package.json @hramos @cpojer
|
||||
|
||||
# These should not be modified through a GitHub PR
|
||||
LICENSE* @hramos @cpojer @yungsters
|
||||
>>>>>>> v0.60.0
|
||||
|
|
|
@ -1,35 +1,40 @@
|
|||
---
|
||||
name: 🐛 Bug Report
|
||||
about: You want to report a reproducible bug or regression in React Native.
|
||||
labels: "Type: Bug Report"
|
||||
name: "🐛 Bug Report"
|
||||
about: Report a reproducible bug or regression in React Native.
|
||||
title: ''
|
||||
labels: 'Bug'
|
||||
|
||||
---
|
||||
|
||||
## 🐛 Bug Report
|
||||
<!--
|
||||
A clear and concise description of what the bug is.
|
||||
Please provide a clear and concise description of what the bug is.
|
||||
Include screenshots if needed.
|
||||
Please test using the latest React Native release to make sure your issue has not already been fixed: http://facebook.github.io/react-native/docs/upgrading.html
|
||||
-->
|
||||
|
||||
## To Reproduce
|
||||
React Native version:
|
||||
<!--
|
||||
Steps to reproduce the behavior.
|
||||
Run `react-native info` in your terminal and copy the results here.
|
||||
-->
|
||||
|
||||
## Expected Behavior
|
||||
## Steps To Reproduce
|
||||
|
||||
1.
|
||||
2.
|
||||
|
||||
<!--
|
||||
A clear and concise description of what you expected to happen.
|
||||
Issues without reproduction steps or code are likely to stall.
|
||||
-->
|
||||
|
||||
## Code Example
|
||||
Describe what you expected to happen:
|
||||
|
||||
|
||||
Snack, code example, or link to a repository:
|
||||
|
||||
|
||||
<!--
|
||||
Please provide a Snack (https://snack.expo.io/), a link to a repository on GitHub, or
|
||||
provide a minimal code example that reproduces the problem.
|
||||
Here are some tips for providing a minimal example: https://stackoverflow.com/help/mcve.
|
||||
|
||||
Issues without a reproduction link are likely to stall.
|
||||
-->
|
||||
|
||||
## Environment
|
||||
<!--
|
||||
Run `react-native info` in your terminal and copy the results here.
|
||||
-->
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
---
|
||||
name: 🚀 Discussion
|
||||
about: You have an idea that could make React Native better, or you want to discuss some aspect of the framework.
|
||||
labels: "Type: Discussion"
|
||||
---
|
||||
|
||||
If you want to participate in casual discussions about the use of React Native, consider participating in one of the following forums:
|
||||
- Discord Community: https://discord.gg/0ZcbPKXt5bZjGY5n
|
||||
- Spectrum Chat: https://spectrum.chat/react-native
|
||||
- Facebook Group: https://www.facebook.com/groups/react.native.community
|
||||
|
||||
For a full list of community resources:
|
||||
- http://facebook.github.io/react-native/help
|
||||
|
||||
If you'd like to discuss topics related to the future of React Native, please check out the discussions and proposals repo:
|
||||
- https://github.com/react-native-community/discussions-and-proposals
|
||||
|
||||
### Please note that discussions opened as issues in the core React Native repository will be closed.
|
|
@ -1,12 +1,14 @@
|
|||
---
|
||||
name: 📃 Documentation Bug
|
||||
about: You want to report something that is wrong or missing from the documentation.
|
||||
labels: "Type: Docs"
|
||||
name: "📃 Documentation Issue"
|
||||
about: Documentation issues are handled in https://github.com/facebook/react-native-website.
|
||||
title: 'Docs:'
|
||||
labels: 'Type: Docs'
|
||||
|
||||
---
|
||||
|
||||
🚨 Please do not open a documentation issue in the core React Native repository. 🚨
|
||||
|
||||
The React Native website is hosted on a separate repository. You may let the
|
||||
team know about any issues with the documentation by opening an issue there:
|
||||
- https://github.com/facebook/react-native-website
|
||||
- https://github.com/facebook/react-native-website/issues
|
||||
|
||||
### Please do not open a documentation issue in the core React Native repository.
|
|
@ -1,15 +1,34 @@
|
|||
---
|
||||
name: 💬 Questions and Help
|
||||
about: You need help writing your React Native app.
|
||||
labels: "Type: Question"
|
||||
name: "🤔 Questions and Help"
|
||||
about: The issue tracker is not for questions. Please ask questions on https://stackoverflow.com/questions/tagged/react-native.
|
||||
title: 'Question: '
|
||||
labels: 'Type: Question'
|
||||
|
||||
---
|
||||
|
||||
GitHub Issues in the `facebook/react-native` repository are used exclusively for tracking bugs in the React Native framework. Please do not submit support requests through GitHub.
|
||||
🚨 The issue tracker is not for questions. 🚨
|
||||
|
||||
For questions or help, please see:
|
||||
- The React Native help page: http://facebook.github.io/react-native/help
|
||||
- The React Native channel in Reactiflux: https://discord.gg/0ZcbPKXt5bZjGY5n
|
||||
- The react-native tag on Stack Overflow: http://stackoverflow.com/questions/tagged/react-native
|
||||
As it happens, support requests that are created as issues are likely to be closed. We want to make sure you are able to find the help you seek. Please take a look at the following resources.
|
||||
|
||||
## Coding Questions
|
||||
|
||||
### https://stackoverflow.com/questions/tagged/react-native
|
||||
|
||||
If you have a coding question related to React Native, it might be better suited for Stack Overflow. It's a great place to browse through frequent questions about using React Native, as well as ask for help with specific questions.
|
||||
|
||||
|
||||
### Please note that this issue tracker is not a help forum and requests for help will be closed.
|
||||
## Talk to other React Native developers
|
||||
|
||||
### https://www.reactiflux.com/
|
||||
|
||||
Reactiflux is an active community of React and React Native developers. If you are looking for immediate assistance or have a general question about React Native, the #react-native channel is a good place to start.
|
||||
|
||||
If you want to participate in casual discussions about the use of React Native, consider participating in one of the following forums:
|
||||
- Discord Community: https://discord.gg/0ZcbPKXt5bZjGY5n
|
||||
- Spectrum Chat: https://spectrum.chat/react-native
|
||||
- Facebook Group: https://www.facebook.com/groups/react.native.community
|
||||
|
||||
If you'd like to discuss topics related to the future of React Native, or would like to propose a new feature or change before sending a pull request, please check out the discussions and proposals repo:
|
||||
- https://github.com/react-native-community/discussions-and-proposals
|
||||
|
||||
> For a full list of community resources, check out React Native's Community page at https://facebook.github.io/react-native/help.
|
||||
|
|
|
@ -1,42 +0,0 @@
|
|||
---
|
||||
name: 💥 Regression Report
|
||||
about: You want to report unexpected behavior that worked in previous releases.
|
||||
labels: "Type: Bug Report", "Impact: Regression"
|
||||
---
|
||||
|
||||
## 💥 Regression Report
|
||||
<!--
|
||||
A clear and concise description of what the regression is.
|
||||
-->
|
||||
|
||||
## Last working version
|
||||
|
||||
Worked up to version:
|
||||
|
||||
Stopped working in version:
|
||||
|
||||
## To Reproduce
|
||||
|
||||
<!--
|
||||
Steps to reproduce the behavior.
|
||||
-->
|
||||
|
||||
## Expected Behavior
|
||||
|
||||
<!--
|
||||
A clear and concise description of what you expected to happen.
|
||||
-->
|
||||
|
||||
## Code Example
|
||||
<!--
|
||||
Please provide a Snack (https://snack.expo.io/), a link to a repository on GitHub, or
|
||||
provide a minimal code example that reproduces the problem.
|
||||
Here are some tips for providing a minimal example: https://stackoverflow.com/help/mcve.
|
||||
|
||||
Issues without a reproduction link are likely to stall.
|
||||
-->
|
||||
|
||||
## Environment
|
||||
<!--
|
||||
Run `react-native info` in your terminal and copy the results here.
|
||||
-->
|
|
@ -16,7 +16,7 @@ If you are making a new change then one of the following should be done:
|
|||
- [ ] I am making a fix / change for the macOS implementation of react-native
|
||||
- [ ] I am making a change required for Microsoft usage of react-native
|
||||
|
||||
#### Description of changes
|
||||
<!-- Help reviewers and the release process by writing your own changelog entry. See https://github.com/facebook/react-native/wiki/Changelog for an example. -->
|
||||
|
||||
(give an overview)
|
||||
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
Thanks for using React Native! If you need help with your React Native app, the right place to go depends on the type of help that you need.
|
||||
|
||||
|
||||
## 🤔 I have a question or need help with my React Native app.
|
||||
|
||||
If you have a coding question related to React Native, it might be better suited for Stack Overflow. It's a great place to browse through [frequent questions about using React Native](https://stackoverflow.com/questions/tagged/react-native?sort=frequent&pageSize=15), as well as [ask for help with specific questions](https://stackoverflow.com/questions/tagged/react-native).
|
||||
|
||||
[Reactiflux](https://www.reactiflux.com/) is an active community of React and React Native developers. If you are looking for immediate assistance or have a general question about React Native, the #react-native channel is a good place to start.
|
||||
|
||||
|
||||
## 📃 I found something that seems wrong in the documentation.
|
||||
|
||||
The React Native website is hosted on a [separate repository](https://github.com/facebook/react-native-website). If you want to report something that is wrong or missing from the documentation, [please open a new issue there](https://github.com/facebook/react-native-website/issues).
|
||||
|
||||
|
||||
## 🐛 I found a bug in React Native.
|
||||
|
||||
If you want to report a reproducible bug or regression in the React Native library, you can [create a new issue](https://github.com/facebook/react-native/issues/new?labels=Type%3A+Bug+Report&template=bug_report.md). It's a good idea to look through [open issues](https://github.com/facebook/react-native/issues) before doing so, as someone else may have reported a similar issue.
|
||||
|
||||
|
||||
## 🚀 I want to discuss the future of React Native.
|
||||
|
||||
If you'd like to discuss topics related to the future of React Native, please check out the [React Native Community Discussions and Proposals](https://github.com/react-native-community/discussions-and-proposals) repository.
|
||||
|
||||
|
||||
## 💬 I want to talk to other React Native developers.
|
||||
|
||||
If you want to participate in casual discussions about the use of React Native, consider participating in one of the following forums:
|
||||
|
||||
- [Reactiflux Discord Server](https://www.reactiflux)
|
||||
- [Spectrum Chat](https://spectrum.chat/react-native)
|
||||
- [React Native Community Facebook Group](https://www.facebook.com/groups/react.native.community)
|
||||
|
||||
|
||||
> For a full list of community resources, check out [React Native's Community page](https://facebook.github.io/react-native/help).
|
|
@ -12,12 +12,13 @@ exemptLabels:
|
|||
- "Help Wanted :octocat:"
|
||||
- "Impact: Regression"
|
||||
- "Resolution: PR Submitted"
|
||||
- "Resolution: Backlog"
|
||||
# Label to use when marking an issue as stale
|
||||
staleLabel: Stale
|
||||
# Comment to post when marking an issue as stale. Set to `false` to disable
|
||||
markComment: >
|
||||
Hey there, it looks like there has been no activity on this issue recently. Has the issue been fixed, or does it still require the community's attention? This issue may be closed if no further activity occurs.
|
||||
You may also label this issue as "For Discussion" or "Good first issue" and I will leave it open.
|
||||
You may also label this issue as a "Discussion" or add it to the "Backlog" and I will leave it open.
|
||||
Thank you for your contributions.
|
||||
# Comment to post when closing a stale issue. Set to `false` to disable
|
||||
closeComment: >
|
||||
|
|
|
@ -75,6 +75,7 @@ package-lock.json
|
|||
/ReactCommon/**/*.xcodeproj
|
||||
RNTester/build
|
||||
|
||||
<<<<<<< HEAD
|
||||
|
||||
*.nupkg
|
||||
|
||||
|
@ -90,3 +91,8 @@ ReactAndroid/bin/
|
|||
# binary files generated during ReactAndroid build.
|
||||
RNTester/android/app/bin/
|
||||
processor/bin/
|
||||
=======
|
||||
# CocoaPods
|
||||
/template/ios/Pods/
|
||||
/template/ios/Podfile.lock
|
||||
>>>>>>> v0.60.0
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"requirePragma": true,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "all",
|
||||
"bracketSpacing": false,
|
||||
"jsxBracketSameLine": true
|
||||
}
|
116
CONTRIBUTING.md
116
CONTRIBUTING.md
|
@ -1,55 +1,107 @@
|
|||
# Contributing to React Native
|
||||
|
||||
We want to make contributing to this project as easy and transparent as possible. Read on to learn more about our development process and how to propose bug fixes and improvements. The [How to Contribute](https://facebook.github.io/react-native/docs/contributing.html) guide on the website goes into more detail for each of these areas.
|
||||
Thank you for your interest in contributing to React Native! From commenting on and triaging issues, to reviewing and sending Pull Requests, all contributions are welcome. We aim to build a vibrant and inclusive [ecosystem of partners, core contributors, and community](ECOSYSTEM.md) that goes beyond the main React Native GitHub repository.
|
||||
|
||||
## Our Development Process
|
||||
The [Open Source Guides](https://opensource.guide/) website has a collection of resources for individuals, communities, and companies who want to learn how to run and contribute to an open source project. Contributors and people new to open source alike will find the following guides especially useful:
|
||||
|
||||
Most changes from engineers at Facebook will sync to [GitHub](https://github.com/facebook/react-native) through a bridge with Facebook's internal source control. Changes from the community are handled through GitHub pull requests. Once a change made on GitHub is approved, it will first be imported into Facebook's internal source control. The change will eventually sync back to GitHub as a single commit once it has passed Facebook's internal tests.
|
||||
* [How to Contribute to Open Source](https://opensource.guide/how-to-contribute/)
|
||||
* [Building Welcoming Communities](https://opensource.guide/building-community/)
|
||||
|
||||
## Pull Requests
|
||||
|
||||
Please make sure the following is done when submitting a pull request:
|
||||
### [Code of Conduct](https://code.fb.com/codeofconduct/)
|
||||
|
||||
1. Fork the repo and create your branch from `master`.
|
||||
2. If you've added code that should be tested, add tests.
|
||||
3. If you've changed APIs, update the documentation.
|
||||
4. Ensure the test suite passes.
|
||||
5. Make sure your code lints.
|
||||
6. If you haven't already, complete the Contributor License Agreement ("CLA").
|
||||
As a reminder, all contributors are expected to adhere to the [Code of Conduct](https://code.facebook.com/codeofconduct).
|
||||
|
||||
## Contributor License Agreement ("CLA")
|
||||
## Ways to Contribute
|
||||
|
||||
In order to accept your pull request, we need you to submit a CLA. You only need to do this once to work on any of Facebook's open source projects.
|
||||
If you are eager to start contributing code right away, we have a list of [good first issues](https://github.com/facebook/react-native/labels/good%20first%20issue) that contain bugs which have a relatively limited scope. As you gain more experience and demonstrate a commitment to evolving React Native, you may be granted issue management permissions in the repository.
|
||||
|
||||
Complete your CLA here: <https://code.facebook.com/cla>
|
||||
There are other ways you can contribute without writing a single line of code. Here are a few things you can do to help out:
|
||||
|
||||
## Issues
|
||||
1. **Replying and handling open issues.** We get a lot of issues every day, and some of them may lack necessary information. You can help out by guiding people through the process of filling out the issue template, asking for clarifying information, or pointing them to existing issues that match their description of the problem. We'll cover more about this process later, in [Handling Issues](http://github.com/facebook/react-native/wiki/Handling-Issues).
|
||||
2. **Reviewing pull requests for the docs.** Reviewing [documentation updates](https://github.com/facebook/react-native-website/pulls) can be as simple as checking for spelling and grammar. If you encounter situations that can be explained better in the docs, click **Edit** at the top of most docs pages to get started with your own contribution.
|
||||
3. **Help people write test plans.** Some pull requests sent to the main repository may lack a proper test plan. These help reviewers understand how the change was tested, and can speed up the time it takes for a contribution to be accepted.
|
||||
|
||||
We use GitHub issues to track public bugs. Please ensure your description is clear and has sufficient instructions to be able to reproduce the issue.
|
||||
Each of these tasks is highly impactful, and maintainers will greatly appreciate your help.
|
||||
|
||||
### Our Development Process
|
||||
|
||||
We use GitHub issues and pull requests to keep track of bug reports and contributions from the community. All changes from engineers at Facebook will sync to [GitHub](https://github.com/facebook/react-native) through a bridge with Facebook's internal source control. Changes from the community are handled through GitHub pull requests. Once a change made on GitHub is approved, it will first be imported into Facebook's internal source control and tested against Facebook's codebase. Once merged at Facebook, the change will eventually sync back to GitHub as a single commit once it has passed Facebook's internal tests.
|
||||
|
||||
You can learn more about the contribution process in the following documents:
|
||||
|
||||
* [Pull Requests](https://github.com/facebook/react-native/wiki/Pull-Requests)
|
||||
|
||||
We also have a thriving community of contributors who would be happy to help you get set up. You can reach out to us through [@ReactNative](http://twitter.com/reactnative) (the React Native team) and [@ReactNativeComm](http://twitter.com/reactnativecomm) (the React Native Community organization).
|
||||
|
||||
### Repositories
|
||||
|
||||
The main repository, <https://github.com/facebook/react-native>, contains the React Native framework itself and it is here where we keep track of bug reports and manage pull requests.
|
||||
|
||||
There are a few other repositories you might want to familiarize yourself with:
|
||||
|
||||
* **React Native website** which contains the source code for the website, including the documentation, located at <https://github.com/facebook/react-native-website>
|
||||
* **Releases** are coordinated through the <https://github.com/react-native-community/react-native-releases> repository. This includes important documents such as the Changelog.
|
||||
* **Discussions** about the future of React Native take place in the <https://github.com/react-native-community/discussions-and-proposals> repository.
|
||||
* **High-quality plugins** for React Native can be found throughout the [React Native Community GitHub Organization](http://github.com/react-native-community/).
|
||||
|
||||
Browsing through these repositories should provide some insight into how the React Native open source project is managed.
|
||||
|
||||
## Handling Issues
|
||||
|
||||
We use GitHub issues to track bugs exclusively. You can report an issue by filing a [Bug Report](https://github.com/facebook/react-native/issues/new/choose). Watch this space for more details on how to get involved and triage issues.
|
||||
|
||||
### Security Bugs
|
||||
|
||||
Facebook has a [bounty program](https://www.facebook.com/whitehat/) for the safe disclosure of security bugs. In those cases, please go through the process outlined on that page and do not file a public issue.
|
||||
|
||||
## Coding Style
|
||||
## Helping with Documentation
|
||||
|
||||
We use Prettier to format our JavaScript code. This saves you time and energy as you can let Prettier fix up any formatting issues automatically through its editor integrations, or by manually running `npm run prettier`. We also use a linter to catch styling issues that may exist in your code. You can check the status of your code styling by simply running `npm run lint`.
|
||||
The React Native documentation is hosted as part of the React Native website repository at https://github.com/facebook/react-native-website. The website itself is located at <https://facebook.github.io/react-native> and it is built using [Docusaurus](https://docusaurus.io/). If there's anything you'd like to change in the docs, you can get started by clicking on the "Edit" button located on the upper right of most pages in the website.
|
||||
|
||||
However, there are still some styles that the linter cannot pick up, notably in Java or Objective-C code.
|
||||
If you are adding new functionality or introducing a change in behavior, we will ask you to update the documentation to reflect your changes.
|
||||
|
||||
**Objective-C:**
|
||||
### Contributing to the Blog
|
||||
|
||||
* Space after `@property` declarations
|
||||
* Brackets on *every* `if`, on the *same* line
|
||||
* `- method`, `@interface`, and `@implementation` brackets on the following line
|
||||
* *Try* to keep it around 80 characters line length (sometimes it's just not possible...)
|
||||
* `*` operator goes with the variable name (e.g. `NSObject *variableName;`)
|
||||
The React Native blog is generated [from the Markdown sources for the blog](https://github.com/facebook/react-native-website/tree/master/website/blog).
|
||||
|
||||
**Java:**
|
||||
Please open an issue in the https://github.com/facebook/react-native-website repository or tag us on [@ReactNative on Twitter](http://twitter.com/reactnative) and get the go-ahead from a maintainer before writing an article intended for the React Native blog. In most cases, you might want to share your article on your own blog or writing medium instead. It's worth asking, though, in case we find your article is a good fit for the blog.
|
||||
|
||||
* If a method call spans multiple lines closing bracket is on the same line as the last argument.
|
||||
* If a method header doesn't fit on one line each argument goes on a separate line.
|
||||
* 100 character line length
|
||||
We recommend referring to the [CONTRIBUTING](https://github.com/facebook/react-native-website/blob/master/CONTRIBUTING.md) document for the `react-native-website` repository to learn more about contributing to the website in general.
|
||||
|
||||
## License
|
||||
## Contributing Code
|
||||
|
||||
By contributing to React Native, you agree that your contributions will be licensed
|
||||
under the LICENSE file in the root directory of this source tree.
|
||||
Code-level contributions to React Native generally come in the form of [pull requests](https://help.github.com/en/articles/about-pull-requests). The process of proposing a change to React Native can be summarized as follows:
|
||||
|
||||
1. Fork the React Native repository and create your branch from `master`.
|
||||
2. If you've added code that should be tested, add tests.
|
||||
3. If you've changed APIs, update the documentation.
|
||||
4. Ensure the test suite passes, either locally or on CI once you opened a pull request.
|
||||
5. Make sure your code lints (for example via `yarn lint --fix`).
|
||||
6. Push the changes to your fork.
|
||||
7. Create a pull request to the React Native repository.
|
||||
8. Review and address comments on your pull request.
|
||||
1. A bot may comment with suggestions. Generally we ask you to resolve these first before a maintainer will review your code.
|
||||
9. If you haven't already, complete the Contributor License Agreement ("CLA").
|
||||
|
||||
If all goes well, your pull request will be merged. If it is not merged, maintainers will do their best to explain the reason why.
|
||||
|
||||
### Step-by-step Guide
|
||||
|
||||
Whenever you are ready to contribute code, check out our [step-by-step guide to sending your first pull request](https://github.com/facebook/react-native/wiki/Pull-Requests#getting-ready-to-submit-your-first-pull-request), or read the [How to Contribute Code](https://github.com/facebook/react-native/wiki/How-to-Contribute) wiki for more details.
|
||||
|
||||
### Tests
|
||||
|
||||
Tests help us prevent regressions from being introduced to the codebase. The GitHub repository is continuously tested using Circle and Appveyor, the results of which are available through the Checks functionality on [commits](https://github.com/facebook/react-native/commits/master) and pull requests. You can learn more about running and writing tests in the [Tests wiki](http://github.com/facebook/react-native/wiki/Tests).
|
||||
|
||||
## Community Contributions
|
||||
|
||||
Contributions to React Native are not limited to GitHub. You can help others by sharing your experience using React Native, whether that is through blog posts, presenting talks at conferences, or simply sharing your thoughts on Twitter and tagging @ReactNative.
|
||||
|
||||
## Where to Get Help
|
||||
|
||||
As you work on React Native, it is natural that sooner or later you may require help. In addition to the resources listed in [SUPPORT](.github/SUPPORT.md), people interested in contributing may take advantage of the following:
|
||||
|
||||
* **Twitter**. The React Native team at Facebook has its own account at [@reactnative](https://twitter.com/reactnative), and the React Native Community uses [@reactnativecomm](https://twitter.com/reactnativecomm). If you feel stuck, or need help contributing, please do not hesitate to reach out.
|
||||
* **Proposals Repository**. If you are considering working on a feature large in scope, consider [creating a proposal first](https://github.com/react-native-community/discussions-and-proposals). The community can help you figure out the right approach, and we'd be happy to help.
|
||||
* **React Native Community Discord**. While we try to hold most discussions in public, sometimes it can be beneficial to have conversations in real time with other contributors. People who have demonstrated a commitment to moving React Native forward through sustained contributions to the project may eventually be invited to join the React Native Community Discord.
|
||||
|
|
|
@ -1,96 +0,0 @@
|
|||
# Dockerfile Tests
|
||||
|
||||
This is a high level overview of the test configuration using docker. It explains how to run the tests locally
|
||||
and how they integrate with the Jenkins Pipeline script to run the automated tests on ContainerShip <https://www.containership.io/>.
|
||||
|
||||
## Docker Installation
|
||||
|
||||
It is required to have Docker running on your machine in order to build and run the tests in the Dockerfiles.
|
||||
See <https://docs.docker.com/engine/installation/> for more information on how to install.
|
||||
|
||||
## Convenience NPM Run Scripts
|
||||
|
||||
We have added a number of default run scripts to the `package.json` file to simplify building and running your tests.
|
||||
|
||||
`npm run docker-setup-android` - Pulls down the base android docker image used for running the tests
|
||||
|
||||
`npm run docker-build-android` - Builds the docker image used to run the tests
|
||||
|
||||
`npm run test-android-run-unit` - Runs all the unit tests that have been built in the latest react/android docker image (note: you need to run test-android-build before executing this, if the image does not exist it will fail)
|
||||
|
||||
`npm run test-android-run-instrumentation` - Runs all the instrumentation tests that have been built in the latest react/android docker image (note: you need to run test-android-build before executing this, if the image does not exist it will fail). You can also pass additional flags to filter which tests instrumentation tests are run. Ex: `npm run test-android-run-instrumentation -- --filter=TestIdTestCase` to only run the TestIdTestCase instrumentation test. See below for more information
|
||||
on the instrumentation test flags.
|
||||
|
||||
`npm run test-android-run-e2e` - Runs all the end to end tests that have been built in the latest react/android docker image (note: you need to run test-android-build before executing this, if the image does not exist it will fail)
|
||||
|
||||
`npm run test-android-unit` - Builds and runs the android unit tests.
|
||||
|
||||
`npm run test-android-instrumentation` - Builds and runs the android instrumentation tests.
|
||||
|
||||
`npm run test-android-e2e` - Builds and runs the android end to end tests.
|
||||
|
||||
## Detailed Android Setup
|
||||
|
||||
There are two Dockerfiles for use with the Android codebase.
|
||||
|
||||
The `Dockerfile.android-base` contains all the necessary prerequisites required to run the React Android tests. It is
|
||||
separated out into a separate Dockerfile because these are dependencies that rarely change and also because it is quite
|
||||
a beastly image since it contains all the Android dependencies for running android and the emulators (~9GB).
|
||||
|
||||
The good news is you should rarely have to build or pull down the base image! All iterative code updates happen as
|
||||
part of the `Dockerfile.android` image build.
|
||||
|
||||
So step one...
|
||||
|
||||
`docker pull containership/android-base:latest`
|
||||
|
||||
This will take quite some time depending on your connection and you need to ensure you have ~10GB of free disk space.
|
||||
|
||||
Once this is done, you can run tests locally by executing two simple commands:
|
||||
|
||||
1. `docker build -t react/android -f ./ContainerShip/Dockerfile.android .`
|
||||
2. `docker run --cap-add=SYS_ADMIN -it react/android bash ContainerShip/scripts/run-android-docker-unit-tests.sh`
|
||||
|
||||
> Note: `--cap-add=SYS_ADMIN` flag is required for the `ContainerShip/scripts/run-android-docker-unit-tests.sh` and
|
||||
`ContainerShip/scripts/run-android-docker-instrumentation-tests.sh` in order to allow the remounting of `/dev/shm` as writeable
|
||||
so the `buck` build system may write temporary output to that location
|
||||
|
||||
Every time you make any modifications to the codebase, you should re-run the `docker build ...` command in order for your
|
||||
updates to be included in your local docker image.
|
||||
|
||||
The following shell scripts have been provided for android testing:
|
||||
|
||||
`ContainerShip/scripts/run-android-docker-unit-tests.sh` - Runs the standard android unit tests
|
||||
|
||||
`ContainerShip/scripts/run-android-docker-instrumentation-tests.sh` - Runs the android instrumentation tests on the emulator. *Note* that these
|
||||
tests take quite some time to run so there are various flags you can pass in order to filter which tests are run (see below)
|
||||
|
||||
`ContainerShip/scripts/run-ci-e2e-tests.sh` - Runs the android end to end tests
|
||||
|
||||
#### ContainerShip/scripts/run-android-docker-instrumentation-tests.sh
|
||||
|
||||
The instrumentation test script accepts the following flags in order to customize the execution of the tests:
|
||||
|
||||
`--filter` - A regex that filters which instrumentation tests will be run. (Defaults to .*)
|
||||
|
||||
`--package` - Name of the java package containing the instrumentation tests (Defaults to com.facebook.react.tests)
|
||||
|
||||
`--path` - Path to the directory containing the instrumentation tests. (Defaults to ./ReactAndroid/src/androidTest/java/com/facebook/react/tests)
|
||||
|
||||
`--retries` - Number of times to retry a failed test before declaring a failure (Defaults to 2)
|
||||
|
||||
For example, if locally you only wanted to run the InitialPropsTestCase, you could do the following:
|
||||
|
||||
`docker run --cap-add=SYS_ADMIN -it react/android bash ContainerShip/scripts/run-android-docker-instrumentation-tests.sh --filter="InitialPropsTestCase"`
|
||||
|
||||
# Javascript Setup
|
||||
|
||||
There is a single Dockerfile for use with the javascript codebase.
|
||||
|
||||
The `Dockerfile.javascript` base requires all the necessary dependencies for running Javascript tests.
|
||||
|
||||
Any time you make an update to the codebase, you can build and run the javascript tests with the following three commands:
|
||||
|
||||
1. `docker build -t react/js -f ./ContainerShip/Dockerfile.javascript .`
|
||||
2. `docker run -it react/js yarn test --maxWorkers=4`
|
||||
3. `docker run -it react/js yarn run flow -- check`
|
|
@ -0,0 +1,58 @@
|
|||
# The React Native Ecosystem
|
||||
|
||||
We aim to build a vibrant and inclusive ecosystem of partners, core contributors, and community that goes beyond the main React Native GitHub repository. This document explains the roles and responsibilities of various stakeholders and provides guidelines for the community organization. The structure outlined in this document has been in place for a while but hadn't been written down before.
|
||||
|
||||
There are three types of stakeholders:
|
||||
|
||||
* **Partners:** Companies that are significantly invested in React Native and have been for years.
|
||||
* **Core Contributors:** Individual people who contribute to the React Native project.
|
||||
* **Community Contributors:** Individuals who support projects in the [react-native-community](https://github.com/react-native-community) organization.
|
||||
|
||||
## Partners
|
||||
|
||||
Partners are companies that are significantly invested in React Native and have been for years. Informed by their use of React Native, they push for improvements of the core and/or the ecosystem around it. Facebook's partners think of React Native as a product: they understand the trade offs that the project makes as well as future plans and goals. Together we shape the vision for React Native to make it the best way to build applications.
|
||||
|
||||
Our current set of partners include Callstack, Expo, Infinite Red, Microsoft and Software Mansion. Many engineers from these companies are core contributors, and their partner responsibilities also include:
|
||||
|
||||
* **[Callstack](https://callstack.com/):** Manages releases, maintains the [React Native CLI](https://github.com/react-native-community/react-native-cli) and organizes [React Native EU](https://react-native.eu/)
|
||||
* **[Expo](https://expo.io/):** Builds [expo](https://github.com/expo/expo) on top of React Native to simplify app development
|
||||
* **[Infinite Red](https://infinite.red/):** Maintains the [ignite cli/boilerplate](https://github.com/infinitered/ignite), organizes [Chain React Conf](https://infinite.red/ChainReactConf)
|
||||
* **[Microsoft](https://www.microsoft.com/en-gb/):** Develops [React Native Windows](https://github.com/Microsoft/react-native-windows) for the Universal Windows Platform (UWP)
|
||||
* **[Software Mansion](https://swmansion.com/):** Maintain core infrastructure including JSC, Animated, and other popular third-party plugins.
|
||||
|
||||
In terms of open source work, pull requests from partners are commonly prioritized. When you are contributing to React Native, you'll most likely meet somebody who works at one of the partner companies and who is a core contributor:
|
||||
|
||||
## Core Contributors
|
||||
|
||||
Core contributors are individuals who contribute to the React Native project. A core contributor is somebody who displayed a lasting commitment to the evolution and maintenance of React Native. The work done by core contributors includes responsibilities mentioned in the “Partners” section above, and concretely means that they:
|
||||
|
||||
* Consistently contribute high quality changes, fixes and improvements
|
||||
* Actively review changes and provide quality feedback to contributors
|
||||
* Manage the release process of React Native by maintaining release branches, communicating changes to users and publishing releases
|
||||
* Love to help out other users with issues on GitHub
|
||||
* Mentor and encourage first time contributors
|
||||
* Identify React Native community members who could be effective core contributors
|
||||
* Help build an inclusive community with people from all backgrounds
|
||||
* Are great at communicating with other contributors and the community in general
|
||||
|
||||
These are behaviors we have observed in our existing core contributors. They aren't strict rules but rather outline their usual responsibilities. We do not expect every core contributor to do all of the above things all the time. Most importantly, we want to create a supportive and friendly environment that fosters collaboration. Above all else, **we are always polite and friendly.**
|
||||
|
||||
Core contributor status is attained after consistently contributing and taking on the responsibilities outlined above and granted by other core contributors. Similarly, after a long period of inactivity, a core contributor may be removed.
|
||||
|
||||
We aim to make contributing to React Native as easy and transparent as possible. All important topics are handled through a [discussion or RFC process on GitHub](https://github.com/react-native-community/discussions-and-proposals). We are always looking for active, enthusiastic members of the React Native community to become core contributors.
|
||||
|
||||
## Community Contributors
|
||||
|
||||
Community contributors are individuals who support projects in the [react-native-community](https://github.com/react-native-community) organization. This organization exists as an incubator for high quality components that extend the capabilities of React Native with functionality that many but not all applications require. Facebook engineers will provide guidance to help build a vibrant community of people and components that make React Native better.
|
||||
|
||||
This structure has multiple benefits:
|
||||
|
||||
* Keep the core of React Native small, which improves performance and reduces the surface area
|
||||
* Provide visibility to projects through shared representation, for example on the React Native website or on Twitter
|
||||
* Ensure a consistent and high standard for code, documentation, user experience, stability and contributions for third-party components
|
||||
* Upgrade the most important components right away when we make breaking changes and move the ecosystem forward at a fast pace
|
||||
* Find new maintainers for projects that are important but were abandoned by previous owners
|
||||
|
||||
Additionally, some companies may choose to sponsor the development of one or many of the packages that are part of the community organization. They will commit to maintain projects, triage issues, fix bugs and develop features. In turn, they will be able to gain visibility for their work, for example through a mention of active maintainers in the README of individual projects after a consistent period of contributions. Such a mention may be removed if maintainers abandon the project.
|
||||
|
||||
If you are working on a popular component and would like to move it to the React Native community, please create an issue on the [discussions-and-proposals repository](https://github.com/react-native-community/discussions-and-proposals).
|
|
@ -13,7 +13,7 @@
|
|||
const React = require('react');
|
||||
const ReactNative = require('react-native');
|
||||
const {View} = ReactNative;
|
||||
const RCTDeviceEventEmitter = require('RCTDeviceEventEmitter');
|
||||
const RCTDeviceEventEmitter = require('react-native/Libraries/EventEmitter/RCTDeviceEventEmitter');
|
||||
const {TestModule, AccessibilityManager} = ReactNative.NativeModules;
|
||||
|
||||
class AccessibilityManagerTest extends React.Component<{}> {
|
||||
|
|
|
@ -15,7 +15,7 @@ const ReactNative = require('react-native');
|
|||
const {NativeAppEventEmitter, StyleSheet, Text, View} = ReactNative;
|
||||
const {TestModule} = ReactNative.NativeModules;
|
||||
|
||||
const deepDiffer = require('deepDiffer');
|
||||
const deepDiffer = require('react-native/Libraries/Utilities/differ/deepDiffer');
|
||||
|
||||
const TEST_PAYLOAD = {foo: 'bar'};
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ const ReactNative = require('react-native');
|
|||
const {AsyncStorage, Text, View, StyleSheet} = ReactNative;
|
||||
const {TestModule} = ReactNative.NativeModules;
|
||||
|
||||
const deepDiffer = require('deepDiffer');
|
||||
const deepDiffer = require('react-native/Libraries/Utilities/differ/deepDiffer');
|
||||
|
||||
const DEBUG = false;
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
require('InitializeCore');
|
||||
require('react-native/Libraries/Core/InitializeCore');
|
||||
const React = require('react');
|
||||
const ReactNative = require('react-native');
|
||||
const {
|
||||
|
@ -33,7 +33,6 @@ const TESTS = [
|
|||
require('./ImageCachePolicyTest'),
|
||||
require('./ImageSnapshotTest'),
|
||||
require('./PromiseTest'),
|
||||
require('./WebViewTest'),
|
||||
require('./SyncMethodTest'),
|
||||
require('./WebSocketTest'),
|
||||
require('./AccessibilityManagerTest'),
|
||||
|
@ -47,7 +46,7 @@ TESTS.forEach(
|
|||
);
|
||||
|
||||
// Modules required for integration tests
|
||||
require('LoggingTestModule');
|
||||
require('./LoggingTestModule');
|
||||
|
||||
type Test = any;
|
||||
|
||||
|
|
|
@ -16,15 +16,18 @@ const ReactNative = require('react-native');
|
|||
const {Image, LayoutAnimation, StyleSheet, Text, View} = ReactNative;
|
||||
const {TestModule} = ReactNative.NativeModules;
|
||||
|
||||
import type {ViewStyleProp} from 'StyleSheet';
|
||||
import type {ViewStyleProp} from 'react-native/Libraries/StyleSheet/StyleSheet';
|
||||
|
||||
const deepDiffer = require('deepDiffer');
|
||||
const deepDiffer = require('react-native/Libraries/Utilities/differ/deepDiffer');
|
||||
|
||||
function debug(...args) {
|
||||
// console.log.apply(null, arguments);
|
||||
}
|
||||
|
||||
import type {Layout, LayoutEvent} from 'CoreEventTypes';
|
||||
import type {
|
||||
Layout,
|
||||
LayoutEvent,
|
||||
} from 'react-native/Libraries/Types/CoreEventTypes';
|
||||
|
||||
type Props = $ReadOnly<{||}>;
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
const BatchedBridge = require('BatchedBridge');
|
||||
const BatchedBridge = require('react-native/Libraries/BatchedBridge/BatchedBridge');
|
||||
|
||||
const warning = require('fbjs/lib/warning');
|
||||
const invariant = require('invariant');
|
||||
|
|
|
@ -12,12 +12,12 @@
|
|||
|
||||
const React = require('react');
|
||||
const ReactNative = require('react-native');
|
||||
const RCTNativeAppEventEmitter = require('RCTNativeAppEventEmitter');
|
||||
const RCTNativeAppEventEmitter = require('react-native/Libraries/EventEmitter/RCTNativeAppEventEmitter');
|
||||
|
||||
const {View} = ReactNative;
|
||||
|
||||
const {TestModule} = ReactNative.NativeModules;
|
||||
import type EmitterSubscription from 'EmitterSubscription';
|
||||
import type EmitterSubscription from 'react-native/Libraries/vendor/emitter/EmitterSubscription';
|
||||
|
||||
const reactViewWidth = 101;
|
||||
const reactViewHeight = 102;
|
||||
|
|
|
@ -12,9 +12,6 @@
|
|||
|
||||
const React = require('react');
|
||||
const ReactNative = require('react-native');
|
||||
/* $FlowFixMe(>=0.54.0 site=react_native_oss) This comment suppresses an error
|
||||
* found when Flow v0.54 was deployed. To see the error delete this comment and
|
||||
* run Flow. */
|
||||
const requestAnimationFrame = require('fbjs/lib/requestAnimationFrame');
|
||||
|
||||
const {StyleSheet, View} = ReactNative;
|
||||
|
|
|
@ -12,11 +12,11 @@
|
|||
|
||||
const React = require('react');
|
||||
const ReactNative = require('react-native');
|
||||
const RCTNativeAppEventEmitter = require('RCTNativeAppEventEmitter');
|
||||
const RCTNativeAppEventEmitter = require('react-native/Libraries/EventEmitter/RCTNativeAppEventEmitter');
|
||||
const {View} = ReactNative;
|
||||
|
||||
const {TestModule} = ReactNative.NativeModules;
|
||||
import type EmitterSubscription from 'EmitterSubscription';
|
||||
import type EmitterSubscription from 'react-native/Libraries/vendor/emitter/EmitterSubscription';
|
||||
|
||||
const reactViewWidth = 111;
|
||||
const reactViewHeight = 222;
|
||||
|
|
|
@ -21,12 +21,26 @@ class SyncMethodTest extends React.Component<{}> {
|
|||
if (
|
||||
RNTesterTestModule.echoString('test string value') !== 'test string value'
|
||||
) {
|
||||
throw new Error('Something wrong with sync method export');
|
||||
throw new Error('Something wrong with echoString sync method');
|
||||
}
|
||||
if (RNTesterTestModule.methodThatReturnsNil() != null) {
|
||||
throw new Error('Something wrong with sync method export');
|
||||
throw new Error('Something wrong with methodThatReturnsNil sync method');
|
||||
}
|
||||
let response;
|
||||
RNTesterTestModule.methodThatCallsCallbackWithString('test', echo => {
|
||||
response = echo;
|
||||
});
|
||||
requestAnimationFrame(() => {
|
||||
if (response === 'test') {
|
||||
TestModule.markTestCompleted();
|
||||
} else {
|
||||
throw new Error(
|
||||
'Something wrong with methodThatCallsCallbackWithString sync method, ' +
|
||||
'got response ' +
|
||||
JSON.stringify(response),
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
render(): React.Node {
|
||||
|
|
|
@ -1,75 +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';
|
||||
|
||||
const React = require('react');
|
||||
const ReactNative = require('react-native');
|
||||
const {WebView} = ReactNative;
|
||||
|
||||
const {TestModule} = ReactNative.NativeModules;
|
||||
|
||||
class WebViewTest extends React.Component {
|
||||
render() {
|
||||
let firstMessageReceived = false;
|
||||
let secondMessageReceived = false;
|
||||
function processMessage(e) {
|
||||
const message = e.nativeEvent.data;
|
||||
if (message === 'First') {
|
||||
firstMessageReceived = true;
|
||||
}
|
||||
if (message === 'Second') {
|
||||
secondMessageReceived = true;
|
||||
}
|
||||
|
||||
// got both messages
|
||||
if (firstMessageReceived && secondMessageReceived) {
|
||||
TestModule.markTestPassed(true);
|
||||
}
|
||||
// wait for next message
|
||||
else if (firstMessageReceived && !secondMessageReceived) {
|
||||
return;
|
||||
}
|
||||
// first message got lost
|
||||
else if (!firstMessageReceived && secondMessageReceived) {
|
||||
throw new Error('First message got lost');
|
||||
}
|
||||
}
|
||||
const html =
|
||||
'Hello world' +
|
||||
'<script>' +
|
||||
"window.setTimeout(function(){window.postMessage('First'); window.postMessage('Second')}, 0)" +
|
||||
'</script>';
|
||||
|
||||
// fail if messages didn't get through;
|
||||
window.setTimeout(function() {
|
||||
throw new Error(
|
||||
firstMessageReceived
|
||||
? 'Both messages got lost'
|
||||
: 'Second message got lost',
|
||||
);
|
||||
}, 10000);
|
||||
|
||||
const source = {
|
||||
html: html,
|
||||
};
|
||||
|
||||
return (
|
||||
<WebView
|
||||
source={source}
|
||||
onMessage={processMessage}
|
||||
originWhitelist={['about:blank']}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
WebViewTest.displayName = 'WebViewTest';
|
||||
|
||||
module.exports = WebViewTest;
|
|
@ -13,9 +13,6 @@
|
|||
|
||||
/* eslint-env node */
|
||||
|
||||
/* $FlowFixMe(>=0.54.0 site=react_native_oss) This comment suppresses an error
|
||||
* found when Flow v0.54 was deployed. To see the error delete this comment and
|
||||
* run Flow. */
|
||||
const WebSocket = require('ws');
|
||||
|
||||
console.log(`\
|
||||
|
@ -34,6 +31,7 @@ server.on('connection', ws => {
|
|||
console.log('WebSocket integration test server exit');
|
||||
process.exit(0);
|
||||
}
|
||||
<<<<<<< HEAD
|
||||
console.log('Cookie:', ws.upgradeReq.headers.cookie);
|
||||
|
||||
if (message instanceof Buffer) {
|
||||
|
@ -41,6 +39,9 @@ server.on('connection', ws => {
|
|||
} else {
|
||||
ws.send(message + '_response');
|
||||
}
|
||||
=======
|
||||
ws.send(message + '_response');
|
||||
>>>>>>> v0.60.0
|
||||
});
|
||||
|
||||
ws.send('hello');
|
||||
|
|
|
@ -1,206 +0,0 @@
|
|||
import groovy.json.JsonSlurperClassic
|
||||
|
||||
def runPipeline() {
|
||||
try {
|
||||
ansiColor('xterm') {
|
||||
runStages();
|
||||
}
|
||||
} catch(err) {
|
||||
echo "Error: ${err}"
|
||||
currentBuild.result = "FAILED"
|
||||
}
|
||||
}
|
||||
|
||||
def pullDockerImage(imageName) {
|
||||
def result = sh(script: "docker pull ${imageName}", returnStatus: true)
|
||||
|
||||
if (result != 0) {
|
||||
throw new Exception("Failed to pull image[${imageName}]")
|
||||
}
|
||||
}
|
||||
|
||||
def buildDockerfile(dockerfilePath = "Dockerfile", imageName) {
|
||||
def buildCmd = "docker build -f ${dockerfilePath} -t ${imageName} ."
|
||||
echo "${buildCmd}"
|
||||
|
||||
def result = sh(script: buildCmd, returnStatus: true)
|
||||
|
||||
if (result != 0) {
|
||||
throw new Exception("Failed to build image[${imageName}] from '${dockerfilePath}'")
|
||||
}
|
||||
}
|
||||
|
||||
def runCmdOnDockerImage(imageName, cmd, run_opts = '') {
|
||||
def result = sh(script: "docker run ${run_opts} -i ${imageName} sh -c '${cmd}'", returnStatus: true)
|
||||
|
||||
if(result != 0) {
|
||||
throw new Exception("Failed to run cmd[${cmd}] on image[${imageName}]")
|
||||
}
|
||||
}
|
||||
|
||||
def calculateGithubInfo() {
|
||||
return [
|
||||
branch: env.BRANCH_NAME,
|
||||
sha: sh(returnStdout: true, script: 'git rev-parse HEAD').trim(),
|
||||
tag: null,
|
||||
isPR: "${env.CHANGE_URL}".contains('/pull/')
|
||||
]
|
||||
}
|
||||
|
||||
def getParallelInstrumentationTests(testDir, parallelCount, imageName) {
|
||||
def integrationTests = [:]
|
||||
def testCount = sh(script: "ls ${testDir} | wc -l", returnStdout: true).trim().toInteger()
|
||||
def testPerParallel = testCount.intdiv(parallelCount) + 1
|
||||
|
||||
def ignoredTests = 'CatalystNativeJavaToJSReturnValuesTestCase|CatalystUIManagerTestCase|CatalystMeasureLayoutTest|CatalystNativeJavaToJSArgumentsTestCase|CatalystNativeJSToJavaParametersTestCase|ReactScrollViewTestCase|ReactHorizontalScrollViewTestCase|ViewRenderingTestCase';
|
||||
|
||||
for (def x = 0; (x*testPerParallel) < testCount; x++) {
|
||||
def offset = x
|
||||
integrationTests["android integration tests: ${offset}"] = {
|
||||
run: {
|
||||
runCmdOnDockerImage(imageName, "bash /app/ContainerShip/scripts/run-android-docker-instrumentation-tests.sh --offset=${offset} --count=${testPerParallel} --ignore=\"${ignoredTests}\"", '--privileged --rm')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return integrationTests
|
||||
}
|
||||
|
||||
def runStages() {
|
||||
def buildInfo = [
|
||||
image: [
|
||||
name: "facebook/react-native",
|
||||
tag: null
|
||||
],
|
||||
scm: [
|
||||
branch: null,
|
||||
sha: null,
|
||||
tag: null,
|
||||
isPR: false
|
||||
]
|
||||
]
|
||||
|
||||
node {
|
||||
def jsDockerBuild, androidDockerBuild
|
||||
def jsTag, androidTag, jsImageName, androidImageName, parallelInstrumentationTests
|
||||
|
||||
try {
|
||||
stage('Setup') {
|
||||
parallel(
|
||||
'pull images': {
|
||||
pullDockerImage('containership/android-base:latest')
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
stage('Build') {
|
||||
checkout scm
|
||||
|
||||
def githubInfo = calculateGithubInfo()
|
||||
buildInfo.scm.branch = githubInfo.branch
|
||||
buildInfo.scm.sha = githubInfo.sha
|
||||
buildInfo.scm.tag = githubInfo.tag
|
||||
buildInfo.scm.isPR = githubInfo.isPR
|
||||
buildInfo.image.tag = "${buildInfo.scm.sha}-${env.BUILD_TAG.replace(" ", "-").replace("/", "-").replace("%2F", "-")}"
|
||||
|
||||
jsTag = "${buildInfo.image.tag}"
|
||||
androidTag = "${buildInfo.image.tag}"
|
||||
jsImageName = "${buildInfo.image.name}-js:${jsTag}"
|
||||
androidImageName = "${buildInfo.image.name}-android:${androidTag}"
|
||||
|
||||
parallelInstrumentationTests = getParallelInstrumentationTests('./ReactAndroid/src/androidTest/java/com/facebook/react/tests', 3, androidImageName)
|
||||
|
||||
parallel(
|
||||
'javascript build': {
|
||||
jsDockerBuild = docker.build("${jsImageName}", "-f ContainerShip/Dockerfile.javascript .")
|
||||
},
|
||||
'android build': {
|
||||
androidDockerBuild = docker.build("${androidImageName}", "-f ContainerShip/Dockerfile.android .")
|
||||
}
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
stage('Tests JS') {
|
||||
try {
|
||||
parallel(
|
||||
'javascript flow': {
|
||||
runCmdOnDockerImage(jsImageName, 'yarn run flow -- check', '--rm')
|
||||
},
|
||||
'javascript tests': {
|
||||
runCmdOnDockerImage(jsImageName, 'yarn test --maxWorkers=4', '--rm')
|
||||
},
|
||||
'documentation tests': {
|
||||
runCmdOnDockerImage(jsImageName, 'cd website && yarn test', '--rm')
|
||||
},
|
||||
'documentation generation': {
|
||||
runCmdOnDockerImage(jsImageName, 'cd website && node ./server/generate.js', '--rm')
|
||||
}
|
||||
)
|
||||
} catch(e) {
|
||||
currentBuild.result = "FAILED"
|
||||
echo "Test JS Stage Error: ${e}"
|
||||
}
|
||||
}
|
||||
|
||||
stage('Tests Android') {
|
||||
try {
|
||||
parallel(
|
||||
'android unit tests': {
|
||||
runCmdOnDockerImage(androidImageName, 'bash /app/ContainerShip/scripts/run-android-docker-unit-tests.sh', '--privileged --rm')
|
||||
},
|
||||
'android e2e tests': {
|
||||
runCmdOnDockerImage(androidImageName, 'bash /app/ContainerShip/scripts/run-ci-e2e-tests.sh --android --js', '--privileged --rm')
|
||||
}
|
||||
)
|
||||
} catch(e) {
|
||||
currentBuild.result = "FAILED"
|
||||
echo "Tests Android Stage Error: ${e}"
|
||||
}
|
||||
}
|
||||
|
||||
stage('Tests Android Instrumentation') {
|
||||
// run all tests in parallel
|
||||
try {
|
||||
parallel(parallelInstrumentationTests)
|
||||
} catch(e) {
|
||||
currentBuild.result = "FAILED"
|
||||
echo "Tests Android Instrumentation Stage Error: ${e}"
|
||||
}
|
||||
}
|
||||
|
||||
stage('Cleanup') {
|
||||
cleanupImage(jsDockerBuild)
|
||||
cleanupImage(androidDockerBuild)
|
||||
}
|
||||
} catch(err) {
|
||||
cleanupImage(jsDockerBuild)
|
||||
cleanupImage(androidDockerBuild)
|
||||
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
def isMasterBranch() {
|
||||
return env.GIT_BRANCH == 'master'
|
||||
}
|
||||
|
||||
def gitCommit() {
|
||||
return sh(returnStdout: true, script: 'git rev-parse HEAD').trim()
|
||||
}
|
||||
|
||||
def cleanupImage(image) {
|
||||
if (image) {
|
||||
try {
|
||||
sh "docker ps -a | awk '{ print \$1,\$2 }' | grep ${image.id} | awk '{print \$1 }' | xargs -I {} docker rm {}"
|
||||
sh "docker rmi -f ${image.id}"
|
||||
} catch(e) {
|
||||
echo "Error cleaning up ${image.id}"
|
||||
echo "${e}"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
runPipeline()
|
|
@ -0,0 +1,34 @@
|
|||
# coding: utf-8
|
||||
# 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.
|
||||
|
||||
require "json"
|
||||
|
||||
package = JSON.parse(File.read(File.join(__dir__, "..", "..", "package.json")))
|
||||
version = package['version']
|
||||
|
||||
source = { :git => 'https://github.com/facebook/react-native.git' }
|
||||
if version == '1000.0.0'
|
||||
# This is an unpublished version, use the latest commit hash of the react-native repo, which we’re presumably in.
|
||||
source[:commit] = `git rev-parse HEAD`.strip
|
||||
else
|
||||
source[:tag] = "v#{version}"
|
||||
end
|
||||
|
||||
Pod::Spec.new do |s|
|
||||
s.name = "React-ART"
|
||||
s.version = version
|
||||
s.summary = "A library for drawing vector graphics."
|
||||
s.homepage = "http://facebook.github.io/react-native/"
|
||||
s.license = package["license"]
|
||||
s.author = "Facebook, Inc. and its affiliates"
|
||||
s.platforms = { :ios => "9.0", :tvos => "9.2" }
|
||||
s.source = source
|
||||
s.source_files = "**/*.{h,m}"
|
||||
s.preserve_paths = "package.json", "LICENSE", "LICENSE-docs"
|
||||
s.header_dir = "React"
|
||||
|
||||
s.dependency "React-Core", version
|
||||
end
|
|
@ -10,15 +10,15 @@
|
|||
'use strict';
|
||||
|
||||
const Color = require('art/core/color');
|
||||
const Path = require('ARTSerializablePath');
|
||||
const Path = require('./ARTSerializablePath');
|
||||
const Transform = require('art/core/transform');
|
||||
|
||||
const React = require('React');
|
||||
const React = require('react');
|
||||
const PropTypes = require('prop-types');
|
||||
const ReactNativeViewAttributes = require('ReactNativeViewAttributes');
|
||||
const ReactNativeViewAttributes = require('../Components/View/ReactNativeViewAttributes');
|
||||
|
||||
const createReactNativeComponentClass = require('createReactNativeComponentClass');
|
||||
const merge = require('merge');
|
||||
const createReactNativeComponentClass = require('../Renderer/shims/createReactNativeComponentClass');
|
||||
const merge = require('../vendor/core/merge');
|
||||
const invariant = require('invariant');
|
||||
|
||||
// Diff Helpers
|
||||
|
|
|
@ -9,10 +9,11 @@
|
|||
*/
|
||||
'use strict';
|
||||
|
||||
const RCTActionSheetManager = require('NativeModules').ActionSheetManager;
|
||||
const RCTActionSheetManager = require('../BatchedBridge/NativeModules')
|
||||
.ActionSheetManager;
|
||||
|
||||
const invariant = require('invariant');
|
||||
const processColor = require('processColor');
|
||||
const processColor = require('../StyleSheet/processColor');
|
||||
|
||||
/**
|
||||
* Display action sheets and share sheets on iOS.
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
# coding: utf-8
|
||||
# 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.
|
||||
|
||||
require "json"
|
||||
|
||||
package = JSON.parse(File.read(File.join(__dir__, "..", "..", "package.json")))
|
||||
version = package['version']
|
||||
|
||||
source = { :git => 'https://github.com/facebook/react-native.git' }
|
||||
if version == '1000.0.0'
|
||||
# This is an unpublished version, use the latest commit hash of the react-native repo, which we’re presumably in.
|
||||
source[:commit] = `git rev-parse HEAD`.strip
|
||||
else
|
||||
source[:tag] = "v#{version}"
|
||||
end
|
||||
|
||||
Pod::Spec.new do |s|
|
||||
s.name = "React-RCTActionSheet"
|
||||
s.version = version
|
||||
s.summary = "An API for displaying iOS action sheets and share sheets."
|
||||
s.homepage = "http://facebook.github.io/react-native/"
|
||||
s.documentation_url = "https://facebook.github.io/react-native/docs/actionsheetios"
|
||||
s.license = package["license"]
|
||||
s.author = "Facebook, Inc. and its affiliates"
|
||||
s.platforms = { :ios => "9.0", :tvos => "9.2" }
|
||||
s.source = source
|
||||
s.source_files = "*.{h,m}"
|
||||
s.preserve_paths = "package.json", "LICENSE", "LICENSE-docs"
|
||||
s.header_dir = "React"
|
||||
|
||||
s.dependency "React-Core", version
|
||||
end
|
|
@ -11,9 +11,9 @@
|
|||
'use strict';
|
||||
|
||||
const AlertMacOS = require('AlertMacOS'); // TODO(macOS ISS#2323203)
|
||||
const NativeModules = require('NativeModules');
|
||||
const NativeModules = require('../BatchedBridge/NativeModules');
|
||||
const RCTAlertManager = NativeModules.AlertManager;
|
||||
const Platform = require('Platform');
|
||||
const Platform = require('../Utilities/Platform');
|
||||
|
||||
export type Buttons = Array<{
|
||||
text?: string,
|
||||
|
@ -26,14 +26,14 @@ type Options = {
|
|||
onDismiss?: ?Function,
|
||||
};
|
||||
|
||||
export type AlertType = $Enum<{
|
||||
type AlertType = $Keys<{
|
||||
default: string,
|
||||
'plain-text': string,
|
||||
'secure-text': string,
|
||||
'login-password': string,
|
||||
}>;
|
||||
|
||||
export type AlertButtonStyle = $Enum<{
|
||||
export type AlertButtonStyle = $Keys<{
|
||||
default: string,
|
||||
cancel: string,
|
||||
destructive: string,
|
||||
|
@ -52,11 +52,59 @@ class Alert {
|
|||
options?: Options,
|
||||
): void {
|
||||
if (Platform.OS === 'ios') {
|
||||
AlertIOS.alert(title, message, buttons);
|
||||
Alert.prompt(title, message, buttons, 'default');
|
||||
} else if (Platform.OS === 'macos' /* TODO[(macOS ISS#2323203) */) {
|
||||
AlertMacOS.alert(title, message, buttons); // TODO](macOS ISS#2323203)
|
||||
AlertMacOS.prompt(title, message, buttons); // TODO](macOS ISS#2323203)
|
||||
} else if (Platform.OS === 'android') {
|
||||
AlertAndroid.alert(title, message, buttons, options);
|
||||
let config = {
|
||||
title: title || '',
|
||||
message: message || '',
|
||||
cancelable: false,
|
||||
};
|
||||
|
||||
if (options) {
|
||||
config = {...config, cancelable: options.cancelable};
|
||||
}
|
||||
// At most three buttons (neutral, negative, positive). Ignore rest.
|
||||
// The text 'OK' should be probably localized. iOS Alert does that in native.
|
||||
const validButtons: Buttons = buttons
|
||||
? buttons.slice(0, 3)
|
||||
: [{text: 'OK'}];
|
||||
const buttonPositive = validButtons.pop();
|
||||
const buttonNegative = validButtons.pop();
|
||||
const buttonNeutral = validButtons.pop();
|
||||
if (buttonNeutral) {
|
||||
config = {...config, buttonNeutral: buttonNeutral.text || ''};
|
||||
}
|
||||
if (buttonNegative) {
|
||||
config = {...config, buttonNegative: buttonNegative.text || ''};
|
||||
}
|
||||
if (buttonPositive) {
|
||||
config = {...config, buttonPositive: buttonPositive.text || ''};
|
||||
}
|
||||
NativeModules.DialogManagerAndroid.showAlert(
|
||||
config,
|
||||
errorMessage => console.warn(errorMessage),
|
||||
(action, buttonKey) => {
|
||||
if (action === NativeModules.DialogManagerAndroid.buttonClicked) {
|
||||
if (
|
||||
buttonKey === NativeModules.DialogManagerAndroid.buttonNeutral
|
||||
) {
|
||||
buttonNeutral.onPress && buttonNeutral.onPress();
|
||||
} else if (
|
||||
buttonKey === NativeModules.DialogManagerAndroid.buttonNegative
|
||||
) {
|
||||
buttonNegative.onPress && buttonNegative.onPress();
|
||||
} else if (
|
||||
buttonKey === NativeModules.DialogManagerAndroid.buttonPositive
|
||||
) {
|
||||
buttonPositive.onPress && buttonPositive.onPress();
|
||||
}
|
||||
} else if (action === NativeModules.DialogManagerAndroid.dismissed) {
|
||||
options && options.onDismiss && options.onDismiss();
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -69,38 +117,6 @@ class Alert {
|
|||
keyboardType?: string,
|
||||
): void {
|
||||
if (Platform.OS === 'ios') {
|
||||
AlertIOS.prompt(
|
||||
title,
|
||||
message,
|
||||
callbackOrButtons,
|
||||
type,
|
||||
defaultValue,
|
||||
keyboardType,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper around the iOS native module.
|
||||
*/
|
||||
class AlertIOS {
|
||||
static alert(
|
||||
title: ?string,
|
||||
message?: ?string,
|
||||
callbackOrButtons?: ?((() => void) | Buttons),
|
||||
): void {
|
||||
this.prompt(title, message, callbackOrButtons, 'default');
|
||||
}
|
||||
|
||||
static prompt(
|
||||
title: ?string,
|
||||
message?: ?string,
|
||||
callbackOrButtons?: ?(((text: string) => void) | Buttons),
|
||||
type?: ?AlertType = 'plain-text',
|
||||
defaultValue?: string,
|
||||
keyboardType?: string,
|
||||
): void {
|
||||
if (typeof type === 'function') {
|
||||
console.warn(
|
||||
'You passed a callback function as the "type" argument to Alert.prompt(). React Native is ' +
|
||||
|
@ -163,64 +179,6 @@ class AlertIOS {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper around the Android native module.
|
||||
*/
|
||||
class AlertAndroid {
|
||||
static alert(
|
||||
title: ?string,
|
||||
message?: ?string,
|
||||
buttons?: Buttons,
|
||||
options?: Options,
|
||||
): void {
|
||||
let config = {
|
||||
title: title || '',
|
||||
message: message || '',
|
||||
};
|
||||
|
||||
if (options) {
|
||||
config = {...config, cancelable: options.cancelable};
|
||||
}
|
||||
// At most three buttons (neutral, negative, positive). Ignore rest.
|
||||
// The text 'OK' should be probably localized. iOS Alert does that in native.
|
||||
const validButtons: Buttons = buttons
|
||||
? buttons.slice(0, 3)
|
||||
: [{text: 'OK'}];
|
||||
const buttonPositive = validButtons.pop();
|
||||
const buttonNegative = validButtons.pop();
|
||||
const buttonNeutral = validButtons.pop();
|
||||
if (buttonNeutral) {
|
||||
config = {...config, buttonNeutral: buttonNeutral.text || ''};
|
||||
}
|
||||
if (buttonNegative) {
|
||||
config = {...config, buttonNegative: buttonNegative.text || ''};
|
||||
}
|
||||
if (buttonPositive) {
|
||||
config = {...config, buttonPositive: buttonPositive.text || ''};
|
||||
}
|
||||
NativeModules.DialogManagerAndroid.showAlert(
|
||||
config,
|
||||
errorMessage => console.warn(errorMessage),
|
||||
(action, buttonKey) => {
|
||||
if (action === NativeModules.DialogManagerAndroid.buttonClicked) {
|
||||
if (buttonKey === NativeModules.DialogManagerAndroid.buttonNeutral) {
|
||||
buttonNeutral.onPress && buttonNeutral.onPress();
|
||||
} else if (
|
||||
buttonKey === NativeModules.DialogManagerAndroid.buttonNegative
|
||||
) {
|
||||
buttonNegative.onPress && buttonNegative.onPress();
|
||||
} else if (
|
||||
buttonKey === NativeModules.DialogManagerAndroid.buttonPositive
|
||||
) {
|
||||
buttonPositive.onPress && buttonPositive.onPress();
|
||||
}
|
||||
} else if (action === NativeModules.DialogManagerAndroid.dismissed) {
|
||||
options && options.onDismiss && options.onDismiss();
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Alert;
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
const NativeModules = require('NativeModules');
|
||||
const NativeModules = require('../BatchedBridge/NativeModules');
|
||||
|
||||
function emptyCallback() {}
|
||||
|
||||
|
|
|
@ -10,6 +10,6 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
const RCTAlertManager = require('NativeModules').AlertManager;
|
||||
const RCTAlertManager = require('../BatchedBridge/NativeModules').AlertManager;
|
||||
|
||||
module.exports = RCTAlertManager;
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
"babel-core": "^5.8.25",
|
||||
"babel-loader": "^5.3.2",
|
||||
"del": "^1.2.0",
|
||||
"fbjs-scripts": "^1.0.0",
|
||||
"fbjs-scripts": "^1.1.0",
|
||||
"gulp": "^3.9.0",
|
||||
"gulp-babel": "^5.1.0",
|
||||
"gulp-derequire": "^2.1.0",
|
||||
|
|
|
@ -10,30 +10,30 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
import Platform from 'Platform';
|
||||
import Platform from '../../Utilities/Platform';
|
||||
|
||||
const AnimatedImplementation = Platform.isTesting
|
||||
? require('AnimatedMock')
|
||||
: require('AnimatedImplementation');
|
||||
? require('./AnimatedMock')
|
||||
: require('./AnimatedImplementation');
|
||||
|
||||
module.exports = {
|
||||
get FlatList() {
|
||||
return require('AnimatedFlatList');
|
||||
return require('./components/AnimatedFlatList');
|
||||
},
|
||||
get Image() {
|
||||
return require('AnimatedImage');
|
||||
return require('./components/AnimatedImage');
|
||||
},
|
||||
get ScrollView() {
|
||||
return require('AnimatedScrollView');
|
||||
return require('./components/AnimatedScrollView');
|
||||
},
|
||||
get SectionList() {
|
||||
return require('AnimatedSectionList');
|
||||
return require('./components/AnimatedSectionList');
|
||||
},
|
||||
get Text() {
|
||||
return require('AnimatedText');
|
||||
return require('./components/AnimatedText');
|
||||
},
|
||||
get View() {
|
||||
return require('AnimatedView');
|
||||
return require('./components/AnimatedView');
|
||||
},
|
||||
...AnimatedImplementation,
|
||||
};
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
const AnimatedValue = require('./nodes/AnimatedValue');
|
||||
const NativeAnimatedHelper = require('./NativeAnimatedHelper');
|
||||
const ReactNative = require('ReactNative');
|
||||
const ReactNative = require('../../Renderer/shims/ReactNative');
|
||||
|
||||
const invariant = require('invariant');
|
||||
const {shouldUseNativeDriver} = require('./NativeAnimatedHelper');
|
||||
|
|
|
@ -417,11 +417,14 @@ const stagger = function(
|
|||
);
|
||||
};
|
||||
|
||||
type LoopAnimationConfig = {iterations: number};
|
||||
type LoopAnimationConfig = {
|
||||
iterations: number,
|
||||
resetBeforeIteration?: boolean,
|
||||
};
|
||||
|
||||
const loop = function(
|
||||
animation: CompositeAnimation,
|
||||
{iterations = -1}: LoopAnimationConfig = {},
|
||||
{iterations = -1, resetBeforeIteration = true}: LoopAnimationConfig = {},
|
||||
): CompositeAnimation {
|
||||
let isFinished = false;
|
||||
let iterationsSoFar = 0;
|
||||
|
@ -436,7 +439,7 @@ const loop = function(
|
|||
callback && callback(result);
|
||||
} else {
|
||||
iterationsSoFar++;
|
||||
animation.reset();
|
||||
resetBeforeIteration && animation.reset();
|
||||
animation.start(restart);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
'use strict';
|
||||
|
||||
const {AnimatedEvent, attachNativeEvent} = require('./AnimatedEvent');
|
||||
const AnimatedImplementation = require('AnimatedImplementation');
|
||||
const AnimatedImplementation = require('./AnimatedImplementation');
|
||||
const AnimatedInterpolation = require('./nodes/AnimatedInterpolation');
|
||||
const AnimatedNode = require('./nodes/AnimatedNode');
|
||||
const AnimatedProps = require('./nodes/AnimatedProps');
|
||||
|
@ -52,14 +52,28 @@ const spring = function(
|
|||
value: AnimatedValue | AnimatedValueXY,
|
||||
config: SpringAnimationConfig,
|
||||
): CompositeAnimation {
|
||||
return emptyAnimation;
|
||||
const anyValue: any = value;
|
||||
return {
|
||||
...emptyAnimation,
|
||||
start: (callback?: ?EndCallback): void => {
|
||||
anyValue.setValue(config.toValue);
|
||||
callback && callback({finished: true});
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const timing = function(
|
||||
value: AnimatedValue | AnimatedValueXY,
|
||||
config: TimingAnimationConfig,
|
||||
): CompositeAnimation {
|
||||
return emptyAnimation;
|
||||
const anyValue: any = value;
|
||||
return {
|
||||
...emptyAnimation,
|
||||
start: (callback?: ?EndCallback): void => {
|
||||
anyValue.setValue(config.toValue);
|
||||
callback && callback({finished: true});
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const decay = function(
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
const AnimatedImplementation = require('AnimatedImplementation');
|
||||
const AnimatedImplementation = require('./AnimatedImplementation');
|
||||
|
||||
module.exports = {
|
||||
...AnimatedImplementation,
|
||||
|
|
|
@ -216,7 +216,7 @@ class Easing {
|
|||
x2: number,
|
||||
y2: number,
|
||||
): (t: number) => number {
|
||||
const _bezier = require('bezier');
|
||||
const _bezier = require('./bezier');
|
||||
return _bezier(x1, y1, x2, y2);
|
||||
}
|
||||
|
||||
|
|
|
@ -9,8 +9,9 @@
|
|||
*/
|
||||
'use strict';
|
||||
|
||||
const NativeAnimatedModule = require('NativeModules').NativeAnimatedModule;
|
||||
const NativeEventEmitter = require('NativeEventEmitter');
|
||||
const NativeAnimatedModule = require('../../BatchedBridge/NativeModules')
|
||||
.NativeAnimatedModule;
|
||||
const NativeEventEmitter = require('../../EventEmitter/NativeEventEmitter');
|
||||
|
||||
const invariant = require('invariant');
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
let Animated = require('Animated');
|
||||
let Animated = require('../Animated');
|
||||
describe('Animated tests', () => {
|
||||
beforeEach(() => {
|
||||
jest.resetModules();
|
||||
|
@ -445,6 +445,37 @@ describe('Animated tests', () => {
|
|||
});
|
||||
});
|
||||
|
||||
it('does not reset animation in a loop if resetBeforeIteration is false', () => {
|
||||
const animation = {
|
||||
start: jest.fn(),
|
||||
reset: jest.fn(),
|
||||
_isUsingNativeDriver: () => false,
|
||||
};
|
||||
const cb = jest.fn();
|
||||
|
||||
const loop = Animated.loop(animation, {resetBeforeIteration: false});
|
||||
|
||||
expect(animation.start).not.toBeCalled();
|
||||
|
||||
loop.start(cb);
|
||||
|
||||
expect(animation.start).toBeCalled();
|
||||
expect(animation.reset).not.toBeCalled();
|
||||
expect(cb).not.toBeCalled();
|
||||
|
||||
animation.start.mock.calls[0][0]({finished: true}); // End of loop 1
|
||||
expect(animation.reset).not.toBeCalled();
|
||||
expect(cb).not.toBeCalled();
|
||||
|
||||
animation.start.mock.calls[0][0]({finished: true}); // End of loop 2
|
||||
expect(animation.reset).not.toBeCalled();
|
||||
expect(cb).not.toBeCalled();
|
||||
|
||||
animation.start.mock.calls[0][0]({finished: true}); // End of loop 3
|
||||
expect(animation.reset).not.toBeCalled();
|
||||
expect(cb).not.toBeCalled();
|
||||
});
|
||||
|
||||
describe('Animated Parallel', () => {
|
||||
it('works with an empty parallel', () => {
|
||||
const cb = jest.fn();
|
||||
|
@ -614,13 +645,13 @@ describe('Animated tests', () => {
|
|||
let InteractionManager;
|
||||
|
||||
beforeEach(() => {
|
||||
jest.mock('InteractionManager');
|
||||
Animated = require('Animated');
|
||||
InteractionManager = require('InteractionManager');
|
||||
jest.mock('../../../Interaction/InteractionManager');
|
||||
Animated = require('../Animated');
|
||||
InteractionManager = require('../../../Interaction/InteractionManager');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.unmock('InteractionManager');
|
||||
jest.unmock('../../../Interaction/InteractionManager');
|
||||
});
|
||||
|
||||
it('registers an interaction by default', () => {
|
||||
|
@ -803,6 +834,47 @@ describe('Animated tests', () => {
|
|||
expect(value1.__getValue()).toBe(1492);
|
||||
});
|
||||
|
||||
it('should get updates for derived animated nodes', () => {
|
||||
const value1 = new Animated.Value(40);
|
||||
const value2 = new Animated.Value(50);
|
||||
const value3 = new Animated.Value(0);
|
||||
const value4 = Animated.add(value3, Animated.multiply(value1, value2));
|
||||
const callback = jest.fn();
|
||||
const view = new Animated.__PropsOnlyForTests(
|
||||
{
|
||||
style: {
|
||||
transform: [
|
||||
{
|
||||
translateX: value4,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
callback,
|
||||
);
|
||||
const listener = jest.fn();
|
||||
const id = value4.addListener(listener);
|
||||
value3.setValue(137);
|
||||
expect(listener.mock.calls.length).toBe(1);
|
||||
expect(listener).toBeCalledWith({value: 2137});
|
||||
value1.setValue(0);
|
||||
expect(listener.mock.calls.length).toBe(2);
|
||||
expect(listener).toBeCalledWith({value: 137});
|
||||
expect(view.__getValue()).toEqual({
|
||||
style: {
|
||||
transform: [
|
||||
{
|
||||
translateX: 137,
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
value4.removeListener(id);
|
||||
value1.setValue(40);
|
||||
expect(listener.mock.calls.length).toBe(2);
|
||||
expect(value4.__getValue()).toBe(2137);
|
||||
});
|
||||
|
||||
it('should removeAll', () => {
|
||||
const value1 = new Animated.Value(0);
|
||||
const listener = jest.fn();
|
||||
|
|
|
@ -10,8 +10,8 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
const AnimatedMock = require('AnimatedMock');
|
||||
const AnimatedImplementation = require('AnimatedImplementation');
|
||||
const AnimatedMock = require('../AnimatedMock');
|
||||
const AnimatedImplementation = require('../AnimatedImplementation');
|
||||
|
||||
describe('Animated Mock', () => {
|
||||
it('matches implementation keys', () => {
|
||||
|
@ -19,11 +19,34 @@ describe('Animated Mock', () => {
|
|||
Object.keys(AnimatedImplementation),
|
||||
);
|
||||
});
|
||||
it('matches implementation params', () => {
|
||||
Object.keys(AnimatedImplementation).forEach(key =>
|
||||
expect(AnimatedImplementation[key].length).toEqual(
|
||||
AnimatedMock[key].length,
|
||||
it('matches implementation params', done => {
|
||||
Object.keys(AnimatedImplementation).forEach(key => {
|
||||
if (AnimatedImplementation[key].length !== AnimatedMock[key].length) {
|
||||
done(
|
||||
new Error(
|
||||
'key ' +
|
||||
key +
|
||||
' had different lengths: ' +
|
||||
JSON.stringify(
|
||||
{
|
||||
impl: {
|
||||
len: AnimatedImplementation[key].length,
|
||||
type: typeof AnimatedImplementation[key],
|
||||
val: AnimatedImplementation[key].toString(),
|
||||
},
|
||||
mock: {
|
||||
len: AnimatedMock[key].length,
|
||||
type: typeof AnimatedMock[key],
|
||||
val: AnimatedMock[key].toString(),
|
||||
},
|
||||
},
|
||||
null,
|
||||
2,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
});
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -15,22 +15,22 @@ ClassComponentMock.prototype.isReactComponent = true;
|
|||
|
||||
jest
|
||||
.clearAllMocks()
|
||||
.setMock('Text', ClassComponentMock)
|
||||
.setMock('View', ClassComponentMock)
|
||||
.setMock('Image', ClassComponentMock)
|
||||
.setMock('ScrollView', ClassComponentMock)
|
||||
.setMock('FlatList', ClassComponentMock)
|
||||
.setMock('SectionList', ClassComponentMock)
|
||||
.setMock('React', {Component: class {}})
|
||||
.setMock('NativeModules', {
|
||||
.setMock('../../../Text/Text', ClassComponentMock)
|
||||
.setMock('../../../Components/View/View', ClassComponentMock)
|
||||
.setMock('../../../Image/Image', ClassComponentMock)
|
||||
.setMock('../../../Components/ScrollView/ScrollView', ClassComponentMock)
|
||||
.setMock('../../../Lists/FlatList', ClassComponentMock)
|
||||
.setMock('../../../Lists/SectionList', ClassComponentMock)
|
||||
.setMock('react', {Component: class {}})
|
||||
.setMock('../../../BatchedBridge/NativeModules', {
|
||||
NativeAnimatedModule: {},
|
||||
})
|
||||
.mock('NativeEventEmitter')
|
||||
.mock('../../../EventEmitter/NativeEventEmitter')
|
||||
// findNodeHandle is imported from ReactNative so mock that whole module.
|
||||
.setMock('ReactNative', {findNodeHandle: () => 1});
|
||||
.setMock('../../../Renderer/shims/ReactNative', {findNodeHandle: () => 1});
|
||||
|
||||
const Animated = require('Animated');
|
||||
const NativeAnimatedHelper = require('NativeAnimatedHelper');
|
||||
const Animated = require('../Animated');
|
||||
const NativeAnimatedHelper = require('../NativeAnimatedHelper');
|
||||
|
||||
function createAndMountComponent(ComponentClass, props) {
|
||||
const component = new ComponentClass();
|
||||
|
@ -43,7 +43,8 @@ function createAndMountComponent(ComponentClass, props) {
|
|||
}
|
||||
|
||||
describe('Native Animated', () => {
|
||||
const nativeAnimatedModule = require('NativeModules').NativeAnimatedModule;
|
||||
const nativeAnimatedModule = require('../../../BatchedBridge/NativeModules')
|
||||
.NativeAnimatedModule;
|
||||
|
||||
beforeEach(() => {
|
||||
nativeAnimatedModule.addAnimatedEventToView = jest.fn();
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
const Easing = require('Easing');
|
||||
const Easing = require('../Easing');
|
||||
describe('Easing', () => {
|
||||
it('should work with linear', () => {
|
||||
const easing = Easing.linear;
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
'use strict';
|
||||
|
||||
const AnimatedInterpolation = require('../nodes/AnimatedInterpolation');
|
||||
const Easing = require('Easing');
|
||||
const Easing = require('../Easing');
|
||||
|
||||
describe('Interpolation', () => {
|
||||
it('should work with defaults', () => {
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
const bezier = require('bezier');
|
||||
const bezier = require('../bezier');
|
||||
|
||||
const identity = function(x) {
|
||||
return x;
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
*/
|
||||
'use strict';
|
||||
|
||||
const NativeAnimatedHelper = require('NativeAnimatedHelper');
|
||||
const NativeAnimatedHelper = require('../NativeAnimatedHelper');
|
||||
|
||||
import type AnimatedValue from '../nodes/AnimatedValue';
|
||||
|
||||
|
|
|
@ -38,13 +38,11 @@ class DecayAnimation extends Animation {
|
|||
|
||||
constructor(config: DecayAnimationConfigSingle) {
|
||||
super();
|
||||
this._deceleration =
|
||||
config.deceleration !== undefined ? config.deceleration : 0.998;
|
||||
this._deceleration = config.deceleration ?? 0.998;
|
||||
this._velocity = config.velocity;
|
||||
this._useNativeDriver = shouldUseNativeDriver(config);
|
||||
this.__isInteraction =
|
||||
config.isInteraction !== undefined ? config.isInteraction : true;
|
||||
this.__iterations = config.iterations !== undefined ? config.iterations : 1;
|
||||
this.__isInteraction = config.isInteraction ?? !this._useNativeDriver;
|
||||
this.__iterations = config.iterations ?? 1;
|
||||
}
|
||||
|
||||
__getNativeAnimationConfig() {
|
||||
|
|
|
@ -51,13 +51,6 @@ export type SpringAnimationConfigSingle = AnimationConfig & {
|
|||
delay?: number,
|
||||
};
|
||||
|
||||
function withDefault<T>(value: ?T, defaultValue: T): T {
|
||||
if (value === undefined || value === null) {
|
||||
return defaultValue;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
class SpringAnimation extends Animation {
|
||||
_overshootClamping: boolean;
|
||||
_restDisplacementThreshold: number;
|
||||
|
@ -83,20 +76,16 @@ class SpringAnimation extends Animation {
|
|||
constructor(config: SpringAnimationConfigSingle) {
|
||||
super();
|
||||
|
||||
this._overshootClamping = withDefault(config.overshootClamping, false);
|
||||
this._restDisplacementThreshold = withDefault(
|
||||
config.restDisplacementThreshold,
|
||||
0.001,
|
||||
);
|
||||
this._restSpeedThreshold = withDefault(config.restSpeedThreshold, 0.001);
|
||||
this._initialVelocity = withDefault(config.velocity, 0);
|
||||
this._lastVelocity = withDefault(config.velocity, 0);
|
||||
this._overshootClamping = config.overshootClamping ?? false;
|
||||
this._restDisplacementThreshold = config.restDisplacementThreshold ?? 0.001;
|
||||
this._restSpeedThreshold = config.restSpeedThreshold ?? 0.001;
|
||||
this._initialVelocity = config.velocity ?? 0;
|
||||
this._lastVelocity = config.velocity ?? 0;
|
||||
this._toValue = config.toValue;
|
||||
this._delay = withDefault(config.delay, 0);
|
||||
this._delay = config.delay ?? 0;
|
||||
this._useNativeDriver = shouldUseNativeDriver(config);
|
||||
this.__isInteraction =
|
||||
config.isInteraction !== undefined ? config.isInteraction : true;
|
||||
this.__iterations = config.iterations !== undefined ? config.iterations : 1;
|
||||
this.__isInteraction = config.isInteraction ?? !this._useNativeDriver;
|
||||
this.__iterations = config.iterations ?? 1;
|
||||
|
||||
if (
|
||||
config.stiffness !== undefined ||
|
||||
|
@ -110,9 +99,9 @@ class SpringAnimation extends Animation {
|
|||
config.friction === undefined,
|
||||
'You can define one of bounciness/speed, tension/friction, or stiffness/damping/mass, but not more than one',
|
||||
);
|
||||
this._stiffness = withDefault(config.stiffness, 100);
|
||||
this._damping = withDefault(config.damping, 10);
|
||||
this._mass = withDefault(config.mass, 1);
|
||||
this._stiffness = config.stiffness ?? 100;
|
||||
this._damping = config.damping ?? 10;
|
||||
this._mass = config.mass ?? 1;
|
||||
} else if (config.bounciness !== undefined || config.speed !== undefined) {
|
||||
// Convert the origami bounciness/speed values to stiffness/damping
|
||||
// We assume mass is 1.
|
||||
|
@ -125,8 +114,8 @@ class SpringAnimation extends Animation {
|
|||
'You can define one of bounciness/speed, tension/friction, or stiffness/damping/mass, but not more than one',
|
||||
);
|
||||
const springConfig = SpringConfig.fromBouncinessAndSpeed(
|
||||
withDefault(config.bounciness, 8),
|
||||
withDefault(config.speed, 12),
|
||||
config.bounciness ?? 8,
|
||||
config.speed ?? 12,
|
||||
);
|
||||
this._stiffness = springConfig.stiffness;
|
||||
this._damping = springConfig.damping;
|
||||
|
@ -135,8 +124,8 @@ class SpringAnimation extends Animation {
|
|||
// Convert the origami tension/friction values to stiffness/damping
|
||||
// We assume mass is 1.
|
||||
const springConfig = SpringConfig.fromOrigamiTensionAndFriction(
|
||||
withDefault(config.tension, 40),
|
||||
withDefault(config.friction, 7),
|
||||
config.tension ?? 40,
|
||||
config.friction ?? 7,
|
||||
);
|
||||
this._stiffness = springConfig.stiffness;
|
||||
this._damping = springConfig.damping;
|
||||
|
@ -157,7 +146,7 @@ class SpringAnimation extends Animation {
|
|||
stiffness: this._stiffness,
|
||||
damping: this._damping,
|
||||
mass: this._mass,
|
||||
initialVelocity: withDefault(this._initialVelocity, this._lastVelocity),
|
||||
initialVelocity: this._initialVelocity ?? this._lastVelocity,
|
||||
toValue: this._toValue,
|
||||
iterations: this.__iterations,
|
||||
};
|
||||
|
|
|
@ -34,7 +34,7 @@ export type TimingAnimationConfigSingle = AnimationConfig & {
|
|||
let _easeInOut;
|
||||
function easeInOut() {
|
||||
if (!_easeInOut) {
|
||||
const Easing = require('Easing');
|
||||
const Easing = require('../Easing');
|
||||
_easeInOut = Easing.inOut(Easing.ease);
|
||||
}
|
||||
return _easeInOut;
|
||||
|
@ -55,13 +55,12 @@ class TimingAnimation extends Animation {
|
|||
constructor(config: TimingAnimationConfigSingle) {
|
||||
super();
|
||||
this._toValue = config.toValue;
|
||||
this._easing = config.easing !== undefined ? config.easing : easeInOut();
|
||||
this._duration = config.duration !== undefined ? config.duration : 500;
|
||||
this._delay = config.delay !== undefined ? config.delay : 0;
|
||||
this.__iterations = config.iterations !== undefined ? config.iterations : 1;
|
||||
this.__isInteraction =
|
||||
config.isInteraction !== undefined ? config.isInteraction : true;
|
||||
this._easing = config.easing ?? easeInOut();
|
||||
this._duration = config.duration ?? 500;
|
||||
this._delay = config.delay ?? 0;
|
||||
this.__iterations = config.iterations ?? 1;
|
||||
this._useNativeDriver = shouldUseNativeDriver(config);
|
||||
this.__isInteraction = config.isInteraction ?? !this._useNativeDriver;
|
||||
}
|
||||
|
||||
__getNativeAnimationConfig(): any {
|
||||
|
|
|
@ -10,8 +10,10 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
const FlatList = require('FlatList');
|
||||
const FlatList = require('../../../Lists/FlatList');
|
||||
|
||||
const createAnimatedComponent = require('createAnimatedComponent');
|
||||
const createAnimatedComponent = require('../createAnimatedComponent');
|
||||
|
||||
module.exports = createAnimatedComponent(FlatList);
|
||||
module.exports = createAnimatedComponent(FlatList, {
|
||||
scrollEventThrottle: 0.0001,
|
||||
});
|
||||
|
|
|
@ -10,8 +10,8 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
const Image = require('Image');
|
||||
const Image = require('../../../Image/Image');
|
||||
|
||||
const createAnimatedComponent = require('createAnimatedComponent');
|
||||
const createAnimatedComponent = require('../createAnimatedComponent');
|
||||
|
||||
module.exports = createAnimatedComponent(Image);
|
||||
|
|
|
@ -10,8 +10,10 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
const ScrollView = require('ScrollView');
|
||||
const ScrollView = require('../../../Components/ScrollView/ScrollView');
|
||||
|
||||
const createAnimatedComponent = require('createAnimatedComponent');
|
||||
const createAnimatedComponent = require('../createAnimatedComponent');
|
||||
|
||||
module.exports = createAnimatedComponent(ScrollView);
|
||||
module.exports = createAnimatedComponent(ScrollView, {
|
||||
scrollEventThrottle: 0.0001,
|
||||
});
|
||||
|
|
|
@ -10,8 +10,10 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
const SectionList = require('SectionList');
|
||||
const SectionList = require('../../../Lists/SectionList');
|
||||
|
||||
const createAnimatedComponent = require('createAnimatedComponent');
|
||||
const createAnimatedComponent = require('../createAnimatedComponent');
|
||||
|
||||
module.exports = createAnimatedComponent(SectionList);
|
||||
module.exports = createAnimatedComponent(SectionList, {
|
||||
scrollEventThrottle: 0.0001,
|
||||
});
|
||||
|
|
|
@ -10,8 +10,8 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
const Text = require('Text');
|
||||
const Text = require('../../../Text/Text');
|
||||
|
||||
const createAnimatedComponent = require('createAnimatedComponent');
|
||||
const createAnimatedComponent = require('../createAnimatedComponent');
|
||||
|
||||
module.exports = createAnimatedComponent(Text);
|
||||
|
|
|
@ -10,8 +10,8 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
const View = require('View');
|
||||
const View = require('../../../Components/View/View');
|
||||
|
||||
const createAnimatedComponent = require('createAnimatedComponent');
|
||||
const createAnimatedComponent = require('../createAnimatedComponent');
|
||||
|
||||
module.exports = createAnimatedComponent(View);
|
||||
|
|
|
@ -11,12 +11,12 @@
|
|||
|
||||
const {AnimatedEvent} = require('./AnimatedEvent');
|
||||
const AnimatedProps = require('./nodes/AnimatedProps');
|
||||
const React = require('React');
|
||||
const DeprecatedViewStylePropTypes = require('DeprecatedViewStylePropTypes');
|
||||
const React = require('react');
|
||||
const DeprecatedViewStylePropTypes = require('../../DeprecatedPropTypes/DeprecatedViewStylePropTypes');
|
||||
|
||||
const invariant = require('invariant');
|
||||
|
||||
function createAnimatedComponent(Component: any): any {
|
||||
function createAnimatedComponent(Component: any, defaultProps: any): any {
|
||||
invariant(
|
||||
typeof Component !== 'function' ||
|
||||
(Component.prototype && Component.prototype.isReactComponent),
|
||||
|
@ -149,6 +149,7 @@ function createAnimatedComponent(Component: any): any {
|
|||
const props = this._propsAnimated.__getValue();
|
||||
return (
|
||||
<Component
|
||||
{...defaultProps}
|
||||
{...props}
|
||||
ref={this._setComponentRef}
|
||||
// The native driver updates views directly through the UI thread so we
|
||||
|
|
|
@ -15,7 +15,7 @@ const AnimatedWithChildren = require('./AnimatedWithChildren');
|
|||
const NativeAnimatedHelper = require('../NativeAnimatedHelper');
|
||||
|
||||
const invariant = require('invariant');
|
||||
const normalizeColor = require('normalizeColor');
|
||||
const normalizeColor = require('../../../Color/normalizeColor');
|
||||
|
||||
type ExtrapolateType = 'extend' | 'identity' | 'clamp';
|
||||
|
||||
|
|
|
@ -11,11 +11,18 @@
|
|||
|
||||
const NativeAnimatedHelper = require('../NativeAnimatedHelper');
|
||||
|
||||
const NativeAnimatedAPI = NativeAnimatedHelper.API;
|
||||
const invariant = require('invariant');
|
||||
|
||||
type ValueListenerCallback = (state: {value: number}) => mixed;
|
||||
|
||||
let _uniqueId = 1;
|
||||
|
||||
// Note(vjeux): this would be better as an interface but flow doesn't
|
||||
// support them yet
|
||||
class AnimatedNode {
|
||||
_listeners: {[key: string]: ValueListenerCallback};
|
||||
__nativeAnimatedValueListener: ?any;
|
||||
__attach(): void {}
|
||||
__detach(): void {
|
||||
if (this.__isNative && this.__nativeTag != null) {
|
||||
|
@ -36,11 +43,112 @@ class AnimatedNode {
|
|||
/* Methods and props used by native Animated impl */
|
||||
__isNative: boolean;
|
||||
__nativeTag: ?number;
|
||||
__shouldUpdateListenersForNewNativeTag: boolean;
|
||||
|
||||
constructor() {
|
||||
this._listeners = {};
|
||||
}
|
||||
|
||||
__makeNative() {
|
||||
if (!this.__isNative) {
|
||||
throw new Error('This node cannot be made a "native" animated node');
|
||||
}
|
||||
|
||||
if (this.hasListeners()) {
|
||||
this._startListeningToNativeValueUpdates();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an asynchronous listener to the value so you can observe updates from
|
||||
* animations. This is useful because there is no way to
|
||||
* synchronously read the value because it might be driven natively.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animatedvalue.html#addlistener
|
||||
*/
|
||||
addListener(callback: (value: any) => mixed): string {
|
||||
const id = String(_uniqueId++);
|
||||
this._listeners[id] = callback;
|
||||
if (this.__isNative) {
|
||||
this._startListeningToNativeValueUpdates();
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister a listener. The `id` param shall match the identifier
|
||||
* previously returned by `addListener()`.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animatedvalue.html#removelistener
|
||||
*/
|
||||
removeListener(id: string): void {
|
||||
delete this._listeners[id];
|
||||
if (this.__isNative && !this.hasListeners()) {
|
||||
this._stopListeningForNativeValueUpdates();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all registered listeners.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animatedvalue.html#removealllisteners
|
||||
*/
|
||||
removeAllListeners(): void {
|
||||
this._listeners = {};
|
||||
if (this.__isNative) {
|
||||
this._stopListeningForNativeValueUpdates();
|
||||
}
|
||||
}
|
||||
|
||||
hasListeners(): boolean {
|
||||
return !!Object.keys(this._listeners).length;
|
||||
}
|
||||
|
||||
_startListeningToNativeValueUpdates() {
|
||||
if (
|
||||
this.__nativeAnimatedValueListener &&
|
||||
!this.__shouldUpdateListenersForNewNativeTag
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.__shouldUpdateListenersForNewNativeTag) {
|
||||
this.__shouldUpdateListenersForNewNativeTag = false;
|
||||
this._stopListeningForNativeValueUpdates();
|
||||
}
|
||||
|
||||
NativeAnimatedAPI.startListeningToAnimatedNodeValue(this.__getNativeTag());
|
||||
this.__nativeAnimatedValueListener = NativeAnimatedHelper.nativeEventEmitter.addListener(
|
||||
'onAnimatedValueUpdate',
|
||||
data => {
|
||||
if (data.tag !== this.__getNativeTag()) {
|
||||
return;
|
||||
}
|
||||
this._onAnimatedValueUpdateReceived(data.value);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
_onAnimatedValueUpdateReceived(value: number) {
|
||||
this.__callListeners(value);
|
||||
}
|
||||
|
||||
__callListeners(value: number): void {
|
||||
for (const key in this._listeners) {
|
||||
this._listeners[key]({value});
|
||||
}
|
||||
}
|
||||
|
||||
_stopListeningForNativeValueUpdates() {
|
||||
if (!this.__nativeAnimatedValueListener) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.__nativeAnimatedValueListener.remove();
|
||||
this.__nativeAnimatedValueListener = null;
|
||||
NativeAnimatedAPI.stopListeningToAnimatedNodeValue(this.__getNativeTag());
|
||||
}
|
||||
|
||||
__getNativeTag(): ?number {
|
||||
NativeAnimatedHelper.assertNativeAnimatedModule();
|
||||
invariant(
|
||||
|
@ -54,6 +162,7 @@ class AnimatedNode {
|
|||
this.__getNativeConfig(),
|
||||
);
|
||||
this.__nativeTag = nativeTag;
|
||||
this.__shouldUpdateListenersForNewNativeTag = true;
|
||||
}
|
||||
return this.__nativeTag;
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ const {AnimatedEvent} = require('../AnimatedEvent');
|
|||
const AnimatedNode = require('./AnimatedNode');
|
||||
const AnimatedStyle = require('./AnimatedStyle');
|
||||
const NativeAnimatedHelper = require('../NativeAnimatedHelper');
|
||||
const ReactNative = require('ReactNative');
|
||||
const ReactNative = require('../../../Renderer/shims/ReactNative');
|
||||
|
||||
const invariant = require('invariant');
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ const AnimatedTransform = require('./AnimatedTransform');
|
|||
const AnimatedWithChildren = require('./AnimatedWithChildren');
|
||||
const NativeAnimatedHelper = require('../NativeAnimatedHelper');
|
||||
|
||||
const flattenStyle = require('flattenStyle');
|
||||
const flattenStyle = require('../../../StyleSheet/flattenStyle');
|
||||
|
||||
class AnimatedStyle extends AnimatedWithChildren {
|
||||
_style: Object;
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
const AnimatedInterpolation = require('./AnimatedInterpolation');
|
||||
const AnimatedWithChildren = require('./AnimatedWithChildren');
|
||||
const InteractionManager = require('InteractionManager');
|
||||
const InteractionManager = require('../../../Interaction/InteractionManager');
|
||||
const NativeAnimatedHelper = require('../NativeAnimatedHelper');
|
||||
|
||||
import type Animation, {EndCallback} from '../animations/Animation';
|
||||
|
@ -20,10 +20,6 @@ import type AnimatedTracking from './AnimatedTracking';
|
|||
|
||||
const NativeAnimatedAPI = NativeAnimatedHelper.API;
|
||||
|
||||
type ValueListenerCallback = (state: {value: number}) => void;
|
||||
|
||||
let _uniqueId = 1;
|
||||
|
||||
/**
|
||||
* Animated works by building a directed acyclic graph of dependencies
|
||||
* transparently when you render your Animated components.
|
||||
|
@ -77,15 +73,12 @@ class AnimatedValue extends AnimatedWithChildren {
|
|||
_offset: number;
|
||||
_animation: ?Animation;
|
||||
_tracking: ?AnimatedTracking;
|
||||
_listeners: {[key: string]: ValueListenerCallback};
|
||||
__nativeAnimatedValueListener: ?any;
|
||||
|
||||
constructor(value: number) {
|
||||
super();
|
||||
this._startingValue = this._value = value;
|
||||
this._offset = 0;
|
||||
this._animation = null;
|
||||
this._listeners = {};
|
||||
}
|
||||
|
||||
__detach() {
|
||||
|
@ -97,14 +90,6 @@ class AnimatedValue extends AnimatedWithChildren {
|
|||
return this._value + this._offset;
|
||||
}
|
||||
|
||||
__makeNative() {
|
||||
super.__makeNative();
|
||||
|
||||
if (Object.keys(this._listeners).length) {
|
||||
this._startListeningToNativeValueUpdates();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Directly set the value. This will stop any animations running on the value
|
||||
* and update all the bound properties.
|
||||
|
@ -167,74 +152,6 @@ class AnimatedValue extends AnimatedWithChildren {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an asynchronous listener to the value so you can observe updates from
|
||||
* animations. This is useful because there is no way to
|
||||
* synchronously read the value because it might be driven natively.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animatedvalue.html#addlistener
|
||||
*/
|
||||
addListener(callback: ValueListenerCallback): string {
|
||||
const id = String(_uniqueId++);
|
||||
this._listeners[id] = callback;
|
||||
if (this.__isNative) {
|
||||
this._startListeningToNativeValueUpdates();
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister a listener. The `id` param shall match the identifier
|
||||
* previously returned by `addListener()`.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animatedvalue.html#removelistener
|
||||
*/
|
||||
removeListener(id: string): void {
|
||||
delete this._listeners[id];
|
||||
if (this.__isNative && Object.keys(this._listeners).length === 0) {
|
||||
this._stopListeningForNativeValueUpdates();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all registered listeners.
|
||||
*
|
||||
* See http://facebook.github.io/react-native/docs/animatedvalue.html#removealllisteners
|
||||
*/
|
||||
removeAllListeners(): void {
|
||||
this._listeners = {};
|
||||
if (this.__isNative) {
|
||||
this._stopListeningForNativeValueUpdates();
|
||||
}
|
||||
}
|
||||
|
||||
_startListeningToNativeValueUpdates() {
|
||||
if (this.__nativeAnimatedValueListener) {
|
||||
return;
|
||||
}
|
||||
|
||||
NativeAnimatedAPI.startListeningToAnimatedNodeValue(this.__getNativeTag());
|
||||
this.__nativeAnimatedValueListener = NativeAnimatedHelper.nativeEventEmitter.addListener(
|
||||
'onAnimatedValueUpdate',
|
||||
data => {
|
||||
if (data.tag !== this.__getNativeTag()) {
|
||||
return;
|
||||
}
|
||||
this._updateValue(data.value, false /* flush */);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
_stopListeningForNativeValueUpdates() {
|
||||
if (!this.__nativeAnimatedValueListener) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.__nativeAnimatedValueListener.remove();
|
||||
this.__nativeAnimatedValueListener = null;
|
||||
NativeAnimatedAPI.stopListeningToAnimatedNodeValue(this.__getNativeTag());
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops any running animation or tracking. `callback` is invoked with the
|
||||
* final value after stopping the animation, which is useful for updating
|
||||
|
@ -259,6 +176,10 @@ class AnimatedValue extends AnimatedWithChildren {
|
|||
this._value = this._startingValue;
|
||||
}
|
||||
|
||||
_onAnimatedValueUpdateReceived(value: number): void {
|
||||
this._updateValue(value, false /*flush*/);
|
||||
}
|
||||
|
||||
/**
|
||||
* Interpolates the value before updating the property, e.g. mapping 0-1 to
|
||||
* 0-10.
|
||||
|
@ -321,9 +242,7 @@ class AnimatedValue extends AnimatedWithChildren {
|
|||
if (flush) {
|
||||
_flush(this);
|
||||
}
|
||||
for (const key in this._listeners) {
|
||||
this._listeners[key]({value: this.__getValue()});
|
||||
}
|
||||
super.__callListeners(this.__getValue());
|
||||
}
|
||||
|
||||
__getNativeConfig(): Object {
|
||||
|
|
|
@ -14,7 +14,7 @@ const AnimatedWithChildren = require('./AnimatedWithChildren');
|
|||
|
||||
const invariant = require('invariant');
|
||||
|
||||
type ValueXYListenerCallback = (value: {x: number, y: number}) => void;
|
||||
type ValueXYListenerCallback = (value: {x: number, y: number}) => mixed;
|
||||
|
||||
let _uniqueId = 1;
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@ class AnimatedWithChildren extends AnimatedNode {
|
|||
);
|
||||
}
|
||||
}
|
||||
super.__makeNative();
|
||||
}
|
||||
|
||||
__addChild(child: AnimatedNode): void {
|
||||
|
@ -69,6 +70,17 @@ class AnimatedWithChildren extends AnimatedNode {
|
|||
__getChildren(): Array<AnimatedNode> {
|
||||
return this._children;
|
||||
}
|
||||
|
||||
__callListeners(value: number): void {
|
||||
super.__callListeners(value);
|
||||
if (!this.__isNative) {
|
||||
for (const child of this._children) {
|
||||
if (child.__getValue) {
|
||||
child.__callListeners(child.__getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = AnimatedWithChildren;
|
||||
|
|
|
@ -10,12 +10,11 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
const MissingNativeEventEmitterShim = require('MissingNativeEventEmitterShim');
|
||||
const NativeEventEmitter = require('NativeEventEmitter');
|
||||
const NativeModules = require('NativeModules');
|
||||
const RCTAppState = NativeModules.AppState;
|
||||
const EventEmitter = require('../vendor/emitter/EventEmitter');
|
||||
const NativeEventEmitter = require('../EventEmitter/NativeEventEmitter');
|
||||
import NativeAppState from './NativeAppState';
|
||||
|
||||
const logError = require('logError');
|
||||
const logError = require('../Utilities/logError');
|
||||
const invariant = require('invariant');
|
||||
|
||||
/**
|
||||
|
@ -27,10 +26,10 @@ const invariant = require('invariant');
|
|||
class AppState extends NativeEventEmitter {
|
||||
_eventHandlers: Object;
|
||||
currentState: ?string;
|
||||
isAvailable: boolean = true;
|
||||
isAvailable: boolean;
|
||||
|
||||
constructor() {
|
||||
super(RCTAppState);
|
||||
super(NativeAppState);
|
||||
|
||||
this.isAvailable = true;
|
||||
this._eventHandlers = {
|
||||
|
@ -38,9 +37,7 @@ class AppState extends NativeEventEmitter {
|
|||
memoryWarning: new Map(),
|
||||
};
|
||||
|
||||
// TODO: Remove the 'active' fallback after `initialAppState` is exported by
|
||||
// the Android implementation.
|
||||
this.currentState = RCTAppState.initialAppState || 'active';
|
||||
this.currentState = NativeAppState.getConstants().initialAppState;
|
||||
|
||||
let eventUpdated = false;
|
||||
|
||||
|
@ -56,7 +53,7 @@ class AppState extends NativeEventEmitter {
|
|||
// TODO: see above - this request just populates the value of `currentState`
|
||||
// when the module is first initialized. Would be better to get rid of the
|
||||
// prop and expose `getCurrentAppState` method directly.
|
||||
RCTAppState.getCurrentAppState(appStateData => {
|
||||
NativeAppState.getCurrentAppState(appStateData => {
|
||||
// It's possible that the state will have changed here & listeners need to be notified
|
||||
if (!eventUpdated && this.currentState !== appStateData.app_state) {
|
||||
this.currentState = appStateData.app_state;
|
||||
|
@ -116,32 +113,48 @@ class AppState extends NativeEventEmitter {
|
|||
}
|
||||
}
|
||||
|
||||
if (__DEV__ && !RCTAppState) {
|
||||
class MissingNativeAppStateShim extends MissingNativeEventEmitterShim {
|
||||
constructor() {
|
||||
super('RCTAppState', 'AppState');
|
||||
function throwMissingNativeModule() {
|
||||
invariant(
|
||||
false,
|
||||
'Cannot use AppState module when native RCTAppState is not included in the build.\n' +
|
||||
'Either include it, or check AppState.isAvailable before calling any methods.',
|
||||
);
|
||||
}
|
||||
|
||||
get currentState(): ?string {
|
||||
this.throwMissingNativeModule();
|
||||
class MissingNativeAppStateShim extends EventEmitter {
|
||||
// AppState
|
||||
isAvailable: boolean = false;
|
||||
currentState: ?string = null;
|
||||
|
||||
addEventListener() {
|
||||
throwMissingNativeModule();
|
||||
}
|
||||
|
||||
addEventListener(...args: Array<any>) {
|
||||
this.throwMissingNativeModule();
|
||||
removeEventListener() {
|
||||
throwMissingNativeModule();
|
||||
}
|
||||
|
||||
removeEventListener(...args: Array<any>) {
|
||||
this.throwMissingNativeModule();
|
||||
// EventEmitter
|
||||
addListener() {
|
||||
throwMissingNativeModule();
|
||||
}
|
||||
|
||||
removeAllListeners() {
|
||||
throwMissingNativeModule();
|
||||
}
|
||||
|
||||
removeSubscription() {
|
||||
throwMissingNativeModule();
|
||||
}
|
||||
}
|
||||
|
||||
// This module depends on the native `RCTAppState` module. If you don't
|
||||
// include it, `AppState.isAvailable` will return `false`, and any method
|
||||
// calls will throw. We reassign the class variable to keep the autodoc
|
||||
// generator happy.
|
||||
AppState = new MissingNativeAppStateShim();
|
||||
} else {
|
||||
// This module depends on the native `RCTAppState` module. If you don't include it,
|
||||
// `AppState.isAvailable` will return `false`, and any method calls will throw.
|
||||
// We reassign the class variable to keep the autodoc generator happy.
|
||||
if (NativeAppState) {
|
||||
AppState = new AppState();
|
||||
} else {
|
||||
AppState = new MissingNativeAppStateShim();
|
||||
}
|
||||
|
||||
module.exports = AppState;
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
* @flow
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import type {TurboModule} from 'RCTExport';
|
||||
import * as TurboModuleRegistry from 'TurboModuleRegistry';
|
||||
|
||||
export interface Spec extends TurboModule {
|
||||
+getConstants: () => {|
|
||||
initialAppState: string,
|
||||
|};
|
||||
+getCurrentAppState: (
|
||||
success: (appState: {|app_state: string|}) => void,
|
||||
failure: (error: Object) => void,
|
||||
) => void;
|
||||
|
||||
// Events
|
||||
+addListener: (eventName: string) => void;
|
||||
+removeListeners: (count: number) => void;
|
||||
}
|
||||
|
||||
export default TurboModuleRegistry.getEnforcing<Spec>('AppState');
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
const MessageQueue = require('MessageQueue');
|
||||
const MessageQueue = require('./MessageQueue');
|
||||
|
||||
const BatchedBridge = new MessageQueue();
|
||||
|
||||
|
|
|
@ -10,12 +10,12 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
const ErrorUtils = require('ErrorUtils');
|
||||
const Systrace = require('Systrace');
|
||||
const ErrorUtils = require('../vendor/core/ErrorUtils');
|
||||
const Systrace = require('../Performance/Systrace');
|
||||
|
||||
const deepFreezeAndThrowOnMutationInDev = require('deepFreezeAndThrowOnMutationInDev');
|
||||
const deepFreezeAndThrowOnMutationInDev = require('../Utilities/deepFreezeAndThrowOnMutationInDev');
|
||||
const invariant = require('invariant');
|
||||
const stringifySafe = require('stringifySafe');
|
||||
const stringifySafe = require('../Utilities/stringifySafe');
|
||||
|
||||
export type SpyData = {
|
||||
type: number,
|
||||
|
@ -165,7 +165,27 @@ class MessageQueue {
|
|||
return getValue ? getValue() : null;
|
||||
}
|
||||
|
||||
enqueueNativeCall(
|
||||
callNativeSyncHook(
|
||||
moduleID: number,
|
||||
methodID: number,
|
||||
params: any[],
|
||||
onFail: ?Function,
|
||||
onSucc: ?Function,
|
||||
) {
|
||||
if (__DEV__) {
|
||||
invariant(
|
||||
global.nativeCallSyncHook,
|
||||
'Calling synchronous methods on native ' +
|
||||
'modules is not supported in Chrome.\n\n Consider providing alternative ' +
|
||||
'methods to expose this method in debug mode, e.g. by exposing constants ' +
|
||||
'ahead-of-time.',
|
||||
);
|
||||
}
|
||||
this.processCallbacks(moduleID, methodID, params, onFail, onSucc);
|
||||
return global.nativeCallSyncHook(moduleID, methodID, params);
|
||||
}
|
||||
|
||||
processCallbacks(
|
||||
moduleID: number,
|
||||
methodID: number,
|
||||
params: any[],
|
||||
|
@ -188,7 +208,6 @@ class MessageQueue {
|
|||
this._successCallbacks[this._callID] = onSucc;
|
||||
this._failureCallbacks[this._callID] = onFail;
|
||||
}
|
||||
|
||||
if (__DEV__) {
|
||||
global.nativeTraceBeginAsyncFlow &&
|
||||
global.nativeTraceBeginAsyncFlow(
|
||||
|
@ -198,6 +217,16 @@ class MessageQueue {
|
|||
);
|
||||
}
|
||||
this._callID++;
|
||||
}
|
||||
|
||||
enqueueNativeCall(
|
||||
moduleID: number,
|
||||
methodID: number,
|
||||
params: any[],
|
||||
onFail: ?Function,
|
||||
onSucc: ?Function,
|
||||
) {
|
||||
this.processCallbacks(moduleID, methodID, params, onFail, onSucc);
|
||||
|
||||
this._queue[MODULE_IDS].push(moduleID);
|
||||
this._queue[METHOD_IDS].push(methodID);
|
||||
|
@ -385,15 +414,14 @@ class MessageQueue {
|
|||
const debug = this._debugInfo[callID];
|
||||
const module = debug && this._remoteModuleTable[debug[0]];
|
||||
const method = debug && this._remoteMethodTable[debug[0]][debug[1]];
|
||||
if (!callback) {
|
||||
let errorMessage = `Callback with id ${cbID}: ${module}.${method}() not found`;
|
||||
if (method) {
|
||||
errorMessage =
|
||||
`The callback ${method}() exists in module ${module}, ` +
|
||||
'but only one callback may be registered to a function in a native module.';
|
||||
}
|
||||
invariant(callback, errorMessage);
|
||||
}
|
||||
invariant(
|
||||
callback,
|
||||
`No callback found with cbID ${cbID} and callID ${callID} for ` +
|
||||
(method
|
||||
? ` ${module}.${method} - most likely the callback was already invoked`
|
||||
: `module ${module || '<unknown>'}`) +
|
||||
`. Args: '${stringifySafe(args)}'`,
|
||||
);
|
||||
const profileName = debug
|
||||
? '<callback for ' + module + '.' + method + '>'
|
||||
: cbID;
|
||||
|
|
|
@ -10,11 +10,11 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
const BatchedBridge = require('BatchedBridge');
|
||||
const BatchedBridge = require('./BatchedBridge');
|
||||
|
||||
const invariant = require('invariant');
|
||||
|
||||
import type {ExtendedError} from 'parseErrorStack';
|
||||
import type {ExtendedError} from '../Core/Devtools/parseErrorStack';
|
||||
|
||||
type ModuleConfig = [
|
||||
string /* name */,
|
||||
|
@ -64,7 +64,7 @@ function genModule(
|
|||
Object.assign(module, constants);
|
||||
|
||||
if (module.getConstants == null) {
|
||||
module.getConstants = () => constants;
|
||||
module.getConstants = () => constants || Object.freeze({});
|
||||
} else {
|
||||
console.warn(
|
||||
`Unable to define method 'getConstants()' on NativeModule '${moduleName}'. NativeModule '${moduleName}' already has a constant or method called 'getConstants'. Please remove it.`,
|
||||
|
@ -105,19 +105,6 @@ function genMethod(moduleID: number, methodID: number, type: MethodType) {
|
|||
);
|
||||
});
|
||||
};
|
||||
} else if (type === 'sync') {
|
||||
fn = function(...args: Array<any>) {
|
||||
if (__DEV__) {
|
||||
invariant(
|
||||
global.nativeCallSyncHook,
|
||||
'Calling synchronous methods on native ' +
|
||||
'modules is not supported in Chrome.\n\n Consider providing alternative ' +
|
||||
'methods to expose this method in debug mode, e.g. by exposing constants ' +
|
||||
'ahead-of-time.',
|
||||
);
|
||||
}
|
||||
return global.nativeCallSyncHook(moduleID, methodID, args);
|
||||
};
|
||||
} else {
|
||||
fn = function(...args: Array<any>) {
|
||||
const lastArg = args.length > 0 ? args[args.length - 1] : null;
|
||||
|
@ -133,6 +120,15 @@ function genMethod(moduleID: number, methodID: number, type: MethodType) {
|
|||
const onFail = hasErrorCallback ? secondLastArg : null;
|
||||
const callbackCount = hasSuccessCallback + hasErrorCallback;
|
||||
args = args.slice(0, args.length - callbackCount);
|
||||
if (type === 'sync') {
|
||||
return BatchedBridge.callNativeSyncHook(
|
||||
moduleID,
|
||||
methodID,
|
||||
args,
|
||||
onFail,
|
||||
onSuccess,
|
||||
);
|
||||
} else {
|
||||
BatchedBridge.enqueueNativeCall(
|
||||
moduleID,
|
||||
methodID,
|
||||
|
@ -140,6 +136,7 @@ function genMethod(moduleID: number, methodID: number, type: MethodType) {
|
|||
onFail,
|
||||
onSuccess,
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
fn.type = type;
|
||||
|
@ -167,7 +164,7 @@ if (global.nativeModuleProxy) {
|
|||
'__fbBatchedBridgeConfig is not set, cannot invoke native modules',
|
||||
);
|
||||
|
||||
const defineLazyObjectProperty = require('defineLazyObjectProperty');
|
||||
const defineLazyObjectProperty = require('../Utilities/defineLazyObjectProperty');
|
||||
(bridgeConfig.remoteModuleConfig || []).forEach(
|
||||
(config: ModuleConfig, moduleID: number) => {
|
||||
// Initially this config will only contain the module name when running in JSC. The actual
|
||||
|
|
|
@ -32,7 +32,7 @@ const assertQueue = (flushedQueue, index, moduleID, methodID, params) => {
|
|||
describe('MessageQueue', function() {
|
||||
beforeEach(function() {
|
||||
jest.resetModules();
|
||||
MessageQueue = require('MessageQueue');
|
||||
MessageQueue = require('../MessageQueue');
|
||||
MessageQueueTestModule = require('MessageQueueTestModule');
|
||||
queue = new MessageQueue();
|
||||
queue.registerCallableModule(
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
jest.unmock('NativeModules');
|
||||
jest.unmock('../NativeModules');
|
||||
|
||||
let BatchedBridge;
|
||||
let NativeModules;
|
||||
|
@ -41,8 +41,8 @@ describe('MessageQueue', function() {
|
|||
jest.resetModules();
|
||||
|
||||
global.__fbBatchedBridgeConfig = require('MessageQueueTestConfig');
|
||||
BatchedBridge = require('BatchedBridge');
|
||||
NativeModules = require('NativeModules');
|
||||
BatchedBridge = require('../BatchedBridge');
|
||||
NativeModules = require('../NativeModules');
|
||||
});
|
||||
|
||||
it('should generate native modules', () => {
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
import type {BlobData, BlobOptions} from 'BlobTypes';
|
||||
import type {BlobData, BlobOptions} from './BlobTypes';
|
||||
|
||||
/**
|
||||
* Opaque JS representation of some binary data in native.
|
||||
|
@ -58,7 +58,7 @@ class Blob {
|
|||
* Reference: https://developer.mozilla.org/en-US/docs/Web/API/Blob/Blob
|
||||
*/
|
||||
constructor(parts: Array<Blob | string> = [], options?: BlobOptions) {
|
||||
const BlobManager = require('BlobManager');
|
||||
const BlobManager = require('./BlobManager');
|
||||
this.data = BlobManager.createFromParts(parts, options).data;
|
||||
}
|
||||
|
||||
|
@ -80,7 +80,7 @@ class Blob {
|
|||
}
|
||||
|
||||
slice(start?: number, end?: number): Blob {
|
||||
const BlobManager = require('BlobManager');
|
||||
const BlobManager = require('./BlobManager');
|
||||
let {offset, size} = this.data;
|
||||
|
||||
if (typeof start === 'number') {
|
||||
|
@ -117,7 +117,7 @@ class Blob {
|
|||
* `new Blob([blob, ...])` actually copies the data in memory.
|
||||
*/
|
||||
close() {
|
||||
const BlobManager = require('BlobManager');
|
||||
const BlobManager = require('./BlobManager');
|
||||
BlobManager.release(this.data.blobId);
|
||||
this.data = null;
|
||||
}
|
||||
|
|
|
@ -10,11 +10,11 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
const Blob = require('Blob');
|
||||
const BlobRegistry = require('BlobRegistry');
|
||||
const {BlobModule} = require('NativeModules');
|
||||
const Blob = require('./Blob');
|
||||
const BlobRegistry = require('./BlobRegistry');
|
||||
const {BlobModule} = require('../BatchedBridge/NativeModules');
|
||||
|
||||
import type {BlobData, BlobOptions} from 'BlobTypes';
|
||||
import type {BlobData, BlobOptions, BlobCollector} from './BlobTypes';
|
||||
|
||||
/*eslint-disable no-bitwise */
|
||||
/*eslint-disable eqeqeq */
|
||||
|
@ -31,6 +31,21 @@ function uuidv4(): string {
|
|||
});
|
||||
}
|
||||
|
||||
// **Temporary workaround**
|
||||
// TODO(#24654): Use turbomodules for the Blob module.
|
||||
// Blob collector is a jsi::HostObject that is used by native to know
|
||||
// when the a Blob instance is deallocated. This allows to free the
|
||||
// underlying native resources. This is a hack to workaround the fact
|
||||
// that the current bridge infra doesn't allow to track js objects
|
||||
// deallocation. Ideally the whole Blob object should be a jsi::HostObject.
|
||||
function createBlobCollector(blobId: string): BlobCollector | null {
|
||||
if (global.__blobCollectorProvider == null) {
|
||||
return null;
|
||||
} else {
|
||||
return global.__blobCollectorProvider(blobId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Module to manage blobs. Wrapper around the native blob module.
|
||||
*/
|
||||
|
@ -94,7 +109,18 @@ class BlobManager {
|
|||
*/
|
||||
static createFromOptions(options: BlobData): Blob {
|
||||
BlobRegistry.register(options.blobId);
|
||||
return Object.assign(Object.create(Blob.prototype), {data: options});
|
||||
return Object.assign(Object.create(Blob.prototype), {
|
||||
data:
|
||||
// Reuse the collector instance when creating from an existing blob.
|
||||
// This will make sure that the underlying resource is only deallocated
|
||||
// when all blobs that refer to it are deallocated.
|
||||
options.__collector == null
|
||||
? {
|
||||
...options,
|
||||
__collector: createBlobCollector(options.blobId),
|
||||
}
|
||||
: options,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
export opaque type BlobCollector = {};
|
||||
|
||||
export type BlobData = {
|
||||
blobId: string,
|
||||
offset: number,
|
||||
|
@ -17,6 +19,7 @@ export type BlobData = {
|
|||
name?: string,
|
||||
type?: string,
|
||||
lastModified?: number,
|
||||
__collector?: ?BlobCollector,
|
||||
};
|
||||
|
||||
export type BlobOptions = {
|
||||
|
|
|
@ -9,11 +9,11 @@
|
|||
*/
|
||||
'use strict';
|
||||
|
||||
const Blob = require('Blob');
|
||||
const Blob = require('./Blob');
|
||||
|
||||
const invariant = require('invariant');
|
||||
|
||||
import type {BlobOptions} from 'BlobTypes';
|
||||
import type {BlobOptions} from './BlobTypes';
|
||||
|
||||
/**
|
||||
* The File interface provides information about files.
|
||||
|
|
|
@ -11,8 +11,8 @@
|
|||
'use strict';
|
||||
|
||||
const EventTarget = require('event-target-shim');
|
||||
const Blob = require('Blob');
|
||||
const {FileReaderModule} = require('NativeModules');
|
||||
const Blob = require('./Blob');
|
||||
const {FileReaderModule} = require('../BatchedBridge/NativeModules');
|
||||
|
||||
type ReadyState =
|
||||
| 0 // EMPTY
|
||||
|
|
|
@ -7,14 +7,22 @@
|
|||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
<<<<<<< HEAD
|
||||
18B8F9E32143371700CE911A /* RCTFileReaderModule.m in Sources */ = {isa = PBXBuildFile; fileRef = ADDFBA6B1F33455F0064C998 /* RCTFileReaderModule.m */; };
|
||||
18F3B9AD2142F00100AD247D /* RCTFileReaderModule.h in Headers */ = {isa = PBXBuildFile; fileRef = ADDFBA6A1F33455F0064C998 /* RCTFileReaderModule.h */; };
|
||||
18F3B9AE2142F00400AD247D /* RCTBlobManager.h in Headers */ = {isa = PBXBuildFile; fileRef = AD9A43C11DFC7126008DC588 /* RCTBlobManager.h */; };
|
||||
18F3BA222142F91100AD247D /* RCTBlobManager.mm in Sources */ = {isa = PBXBuildFile; fileRef = AD9A43C21DFC7126008DC588 /* RCTBlobManager.mm */; };
|
||||
=======
|
||||
1946172A225F085900E4E008 /* RCTBlobCollector.h in Headers */ = {isa = PBXBuildFile; fileRef = 19461728225F085900E4E008 /* RCTBlobCollector.h */; };
|
||||
1946172B225F085900E4E008 /* RCTBlobCollector.h in Headers */ = {isa = PBXBuildFile; fileRef = 19461728225F085900E4E008 /* RCTBlobCollector.h */; };
|
||||
1946172C225F085900E4E008 /* RCTBlobCollector.mm in Sources */ = {isa = PBXBuildFile; fileRef = 19461729225F085900E4E008 /* RCTBlobCollector.mm */; };
|
||||
1946172D225F085900E4E008 /* RCTBlobCollector.mm in Sources */ = {isa = PBXBuildFile; fileRef = 19461729225F085900E4E008 /* RCTBlobCollector.mm */; };
|
||||
>>>>>>> v0.60.0
|
||||
19BA88FE1F84391700741C5A /* RCTFileReaderModule.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = ADDFBA6A1F33455F0064C998 /* RCTFileReaderModule.h */; };
|
||||
19BA88FF1F84392900741C5A /* RCTFileReaderModule.h in Headers */ = {isa = PBXBuildFile; fileRef = ADDFBA6A1F33455F0064C998 /* RCTFileReaderModule.h */; };
|
||||
19BA89001F84392F00741C5A /* RCTFileReaderModule.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = ADDFBA6A1F33455F0064C998 /* RCTFileReaderModule.h */; };
|
||||
19BA89011F84393D00741C5A /* RCTFileReaderModule.m in Sources */ = {isa = PBXBuildFile; fileRef = ADDFBA6B1F33455F0064C998 /* RCTFileReaderModule.m */; };
|
||||
19D9CA2622820DA40021BD26 /* RCTBlobCollector.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 19461728225F085900E4E008 /* RCTBlobCollector.h */; };
|
||||
AD0871131E215B28007D136D /* RCTBlobManager.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = AD9A43C11DFC7126008DC588 /* RCTBlobManager.h */; };
|
||||
AD0871161E215EC9007D136D /* RCTBlobManager.h in Headers */ = {isa = PBXBuildFile; fileRef = AD9A43C11DFC7126008DC588 /* RCTBlobManager.h */; };
|
||||
AD0871181E215ED1007D136D /* RCTBlobManager.h in Headers */ = {isa = PBXBuildFile; fileRef = AD9A43C11DFC7126008DC588 /* RCTBlobManager.h */; };
|
||||
|
@ -32,6 +40,7 @@
|
|||
dstPath = include/RCTBlob;
|
||||
dstSubfolderSpec = 16;
|
||||
files = (
|
||||
19D9CA2622820DA40021BD26 /* RCTBlobCollector.h in Copy Headers */,
|
||||
19BA88FE1F84391700741C5A /* RCTFileReaderModule.h in Copy Headers */,
|
||||
AD08711A1E2162C8007D136D /* RCTBlobManager.h in Copy Headers */,
|
||||
);
|
||||
|
@ -63,6 +72,8 @@
|
|||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
19461728225F085900E4E008 /* RCTBlobCollector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTBlobCollector.h; sourceTree = "<group>"; };
|
||||
19461729225F085900E4E008 /* RCTBlobCollector.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = RCTBlobCollector.mm; sourceTree = "<group>"; };
|
||||
358F4ED71D1E81A9004DF814 /* libRCTBlob.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRCTBlob.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
6484CE57201A74FA004275A4 /* libRCTBlob-macOS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libRCTBlob-macOS.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
AD9A43C11DFC7126008DC588 /* RCTBlobManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = RCTBlobManager.h; sourceTree = "<group>"; };
|
||||
|
@ -76,6 +87,8 @@
|
|||
358F4ECE1D1E81A9004DF814 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
19461728225F085900E4E008 /* RCTBlobCollector.h */,
|
||||
19461729225F085900E4E008 /* RCTBlobCollector.mm */,
|
||||
ADDFBA6A1F33455F0064C998 /* RCTFileReaderModule.h */,
|
||||
ADDFBA6B1F33455F0064C998 /* RCTFileReaderModule.m */,
|
||||
AD9A43C11DFC7126008DC588 /* RCTBlobManager.h */,
|
||||
|
@ -114,6 +127,7 @@
|
|||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
AD0871161E215EC9007D136D /* RCTBlobManager.h in Headers */,
|
||||
1946172A225F085900E4E008 /* RCTBlobCollector.h in Headers */,
|
||||
ADDFBA6C1F33455F0064C998 /* RCTFileReaderModule.h in Headers */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
@ -123,6 +137,7 @@
|
|||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
19BA88FF1F84392900741C5A /* RCTFileReaderModule.h in Headers */,
|
||||
1946172B225F085900E4E008 /* RCTBlobCollector.h in Headers */,
|
||||
AD0871181E215ED1007D136D /* RCTBlobManager.h in Headers */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
@ -204,6 +219,7 @@
|
|||
developmentRegion = English;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
English,
|
||||
en,
|
||||
);
|
||||
mainGroup = 358F4ECE1D1E81A9004DF814;
|
||||
|
@ -223,6 +239,7 @@
|
|||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
1946172C225F085900E4E008 /* RCTBlobCollector.mm in Sources */,
|
||||
ADDFBA6D1F33455F0064C998 /* RCTFileReaderModule.m in Sources */,
|
||||
AD9A43C31DFC7126008DC588 /* RCTBlobManager.mm in Sources */,
|
||||
);
|
||||
|
@ -241,6 +258,7 @@
|
|||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
1946172D225F085900E4E008 /* RCTBlobCollector.mm in Sources */,
|
||||
19BA89011F84393D00741C5A /* RCTFileReaderModule.m in Sources */,
|
||||
ADD01A711E09404A00F6D226 /* RCTBlobManager.mm in Sources */,
|
||||
);
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
||||
#import <jsi/jsi.h>
|
||||
|
||||
using namespace facebook;
|
||||
|
||||
@class RCTBlobManager;
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
class JSI_EXPORT RCTBlobCollector : public jsi::HostObject {
|
||||
public:
|
||||
RCTBlobCollector(RCTBlobManager *blobManager, const std::string &blobId);
|
||||
~RCTBlobCollector();
|
||||
|
||||
static void install(RCTBlobManager *blobManager);
|
||||
|
||||
private:
|
||||
const std::string blobId_;
|
||||
RCTBlobManager *blobManager_;
|
||||
};
|
||||
|
||||
} // namespace react
|
||||
} // namespace facebook
|
|
@ -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.
|
||||
*/
|
||||
|
||||
#import "RCTBlobCollector.h"
|
||||
|
||||
#import <React/RCTBridge+Private.h>
|
||||
#import "RCTBlobManager.h"
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
RCTBlobCollector::RCTBlobCollector(RCTBlobManager *blobManager, const std::string &blobId)
|
||||
: blobId_(blobId), blobManager_(blobManager) {}
|
||||
|
||||
RCTBlobCollector::~RCTBlobCollector() {
|
||||
RCTBlobManager *blobManager = blobManager_;
|
||||
NSString *blobId = [NSString stringWithUTF8String:blobId_.c_str()];
|
||||
dispatch_async([blobManager_ methodQueue], ^{
|
||||
[blobManager remove:blobId];
|
||||
});
|
||||
}
|
||||
|
||||
void RCTBlobCollector::install(RCTBlobManager *blobManager) {
|
||||
__weak RCTCxxBridge *cxxBridge = (RCTCxxBridge *)blobManager.bridge;
|
||||
[cxxBridge dispatchBlock:^{
|
||||
if (!cxxBridge || cxxBridge.runtime == nullptr) {
|
||||
return;
|
||||
}
|
||||
jsi::Runtime &runtime = *(jsi::Runtime *)cxxBridge.runtime;
|
||||
runtime.global().setProperty(
|
||||
runtime,
|
||||
"__blobCollectorProvider",
|
||||
jsi::Function::createFromHostFunction(
|
||||
runtime,
|
||||
jsi::PropNameID::forAscii(runtime, "__blobCollectorProvider"),
|
||||
1,
|
||||
[blobManager](jsi::Runtime& rt, const jsi::Value& thisVal, const jsi::Value* args, size_t count) {
|
||||
auto blobId = args[0].asString(rt).utf8(rt);
|
||||
auto blobCollector = std::make_shared<RCTBlobCollector>(blobManager, blobId);
|
||||
return jsi::Object::createFromHostObject(rt, blobCollector);
|
||||
}
|
||||
)
|
||||
);
|
||||
} queue:RCTJSThread];
|
||||
}
|
||||
|
||||
} // namespace react
|
||||
} // namespace facebook
|
|
@ -13,6 +13,7 @@
|
|||
#import <React/RCTNetworking.h>
|
||||
#import <React/RCTUtils.h>
|
||||
#import <React/RCTWebSocketModule.h>
|
||||
#import "RCTBlobCollector.h"
|
||||
|
||||
static NSString *const kBlobURIScheme = @"blob";
|
||||
|
||||
|
@ -33,6 +34,7 @@ static NSString *const kBlobURIScheme = @"blob";
|
|||
RCT_EXPORT_MODULE(BlobModule)
|
||||
|
||||
@synthesize bridge = _bridge;
|
||||
@synthesize methodQueue = _methodQueue;
|
||||
|
||||
- (void)setBridge:(RCTBridge *)bridge
|
||||
{
|
||||
|
@ -40,6 +42,8 @@ RCT_EXPORT_MODULE(BlobModule)
|
|||
|
||||
std::lock_guard<std::mutex> lock(_blobsMutex);
|
||||
_blobs = [NSMutableDictionary new];
|
||||
|
||||
facebook::react::RCTBlobCollector::install(self);
|
||||
}
|
||||
|
||||
+ (BOOL)requiresMainQueueSetup
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
# coding: utf-8
|
||||
# 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.
|
||||
|
||||
require "json"
|
||||
|
||||
package = JSON.parse(File.read(File.join(__dir__, "..", "..", "package.json")))
|
||||
version = package['version']
|
||||
|
||||
source = { :git => 'https://github.com/facebook/react-native.git' }
|
||||
if version == '1000.0.0'
|
||||
# This is an unpublished version, use the latest commit hash of the react-native repo, which we’re presumably in.
|
||||
source[:commit] = `git rev-parse HEAD`.strip
|
||||
else
|
||||
source[:tag] = "v#{version}"
|
||||
end
|
||||
|
||||
Pod::Spec.new do |s|
|
||||
s.name = "React-RCTBlob"
|
||||
s.version = version
|
||||
s.summary = "An API for displaying iOS action sheets and share sheets."
|
||||
s.homepage = "http://facebook.github.io/react-native/"
|
||||
s.license = package["license"]
|
||||
s.author = "Facebook, Inc. and its affiliates"
|
||||
s.platforms = { :ios => "9.0", :tvos => "9.2" }
|
||||
s.source = source
|
||||
s.source_files = "*.{h,m,mm}"
|
||||
s.preserve_paths = "package.json", "LICENSE", "LICENSE-docs"
|
||||
s.header_dir = "React"
|
||||
|
||||
s.dependency "React-Core", version
|
||||
s.dependency "React-RCTNetwork", version
|
||||
s.dependency "React-RCTWebSocket", version
|
||||
end
|
|
@ -9,9 +9,9 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
const Blob = require('Blob');
|
||||
const Blob = require('./Blob');
|
||||
|
||||
const {BlobModule} = require('NativeModules');
|
||||
const {BlobModule} = require('../BatchedBridge/NativeModules');
|
||||
|
||||
let BLOB_URL_PREFIX = null;
|
||||
|
||||
|
|
|
@ -9,11 +9,11 @@
|
|||
*/
|
||||
'use strict';
|
||||
|
||||
jest.setMock('NativeModules', {
|
||||
jest.setMock('../../BatchedBridge/NativeModules', {
|
||||
BlobModule: require('../__mocks__/BlobModule'),
|
||||
});
|
||||
|
||||
const Blob = require('Blob');
|
||||
const Blob = require('../Blob');
|
||||
|
||||
describe('Blob', function() {
|
||||
it('should create empty blob', () => {
|
||||
|
|
|
@ -9,12 +9,12 @@
|
|||
*/
|
||||
'use strict';
|
||||
|
||||
jest.setMock('NativeModules', {
|
||||
jest.setMock('../../BatchedBridge/NativeModules', {
|
||||
BlobModule: require('../__mocks__/BlobModule'),
|
||||
});
|
||||
|
||||
const Blob = require('Blob');
|
||||
const BlobManager = require('BlobManager');
|
||||
const Blob = require('../Blob');
|
||||
const BlobManager = require('../BlobManager');
|
||||
|
||||
describe('BlobManager', function() {
|
||||
it('should create blob from parts', () => {
|
||||
|
|
|
@ -9,12 +9,12 @@
|
|||
*/
|
||||
'use strict';
|
||||
|
||||
jest.setMock('NativeModules', {
|
||||
jest.setMock('../../BatchedBridge/NativeModules', {
|
||||
BlobModule: require('../__mocks__/BlobModule'),
|
||||
});
|
||||
|
||||
const Blob = require('Blob');
|
||||
const File = require('File');
|
||||
const Blob = require('../Blob');
|
||||
const File = require('../File');
|
||||
|
||||
describe('babel 7 smoke test', function() {
|
||||
it('should be able to extend a class with native name', function() {
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче