mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Compare commits
19
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
984cbb3524 | ||
|
|
3a5572e0e0 | ||
|
|
62695a1351 | ||
|
|
5f3f3d463a | ||
|
|
ec2f97ac1a | ||
|
|
43d1cf8fd1 | ||
|
|
9faf324d30 | ||
|
|
8e0d54d38b | ||
|
|
2d88b63747 | ||
|
|
d93de22ad9 | ||
|
|
f3cbd4f159 | ||
|
|
a7fdca038f | ||
|
|
42879d21e8 | ||
|
|
d0bb66fbf7 | ||
|
|
c85aa82cd0 | ||
|
|
91509751ef | ||
|
|
87e524b4a4 | ||
|
|
6817f05f63 | ||
|
|
7f4fe158a2 |
+156
-148
@@ -52,6 +52,10 @@ aliases:
|
||||
keys:
|
||||
- v1-android-ndk-{{ arch }}-r10e-32-64
|
||||
|
||||
- &install-ndk
|
||||
|
|
||||
source scripts/circle-ci-android-setup.sh && getAndroidNDK
|
||||
|
||||
- &save-cache-ndk
|
||||
paths:
|
||||
- /opt/ndk
|
||||
@@ -87,6 +91,19 @@ aliases:
|
||||
|
|
||||
npm install --no-package-lock --no-spin --no-progress
|
||||
|
||||
- &install-buck
|
||||
|
|
||||
if [[ ! -e ~/buck ]]; then
|
||||
git clone https://github.com/facebook/buck.git ~/buck --branch v2017.09.04.02 --depth=1
|
||||
fi
|
||||
cd ~/buck && ant
|
||||
buck --version
|
||||
|
||||
- &install-node
|
||||
|
|
||||
curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash -
|
||||
sudo apt-get install -y nodejs
|
||||
|
||||
- &run-node-tests
|
||||
|
|
||||
npm test -- --maxWorkers=2
|
||||
@@ -99,6 +116,11 @@ aliases:
|
||||
- /.*-stable/
|
||||
- master
|
||||
|
||||
- &filter-only-stable
|
||||
branches:
|
||||
only:
|
||||
- /.*-stable/
|
||||
|
||||
- &filter-ignore-gh-pages
|
||||
branches:
|
||||
ignore: gh-pages
|
||||
@@ -110,9 +132,54 @@ aliases:
|
||||
- /.*-stable/
|
||||
- gh-pages
|
||||
|
||||
- &create-ndk-directory
|
||||
|
|
||||
if [[ ! -e /opt/ndk ]]; then
|
||||
sudo mkdir /opt/ndk
|
||||
fi
|
||||
sudo chown ${USER:=$(/usr/bin/id -run)}:$USER /opt/ndk
|
||||
|
||||
# CircleCI does not support interpolating env variables in the environment
|
||||
# https://circleci.com/docs/2.0/env-vars/#interpolating-environment-variables-to-set-other-environment-variables
|
||||
- &configure-android-path
|
||||
|
|
||||
echo 'export PATH=${ANDROID_NDK}:~/react-native/gradle-2.9/bin:~/buck/bin:$PATH' >> $BASH_ENV
|
||||
source $BASH_ENV
|
||||
|
||||
- &install-android-packages
|
||||
|
|
||||
source scripts/circle-ci-android-setup.sh && getAndroidSDK
|
||||
|
||||
- &install-build-dependencies
|
||||
|
|
||||
sudo apt-get update -y
|
||||
sudo apt-get install ant autoconf automake g++ gcc libqt5widgets5 lib32z1 lib32stdc++6 make maven python-dev python3-dev qml-module-qtquick-controls qtdeclarative5-dev file -y
|
||||
|
||||
- &install-android-app-dependencies
|
||||
|
|
||||
buck fetch ReactAndroid/src/test/java/com/facebook/react/modules
|
||||
buck fetch ReactAndroid/src/main/java/com/facebook/react
|
||||
buck fetch ReactAndroid/src/main/java/com/facebook/react/shell
|
||||
buck fetch ReactAndroid/src/test/...
|
||||
buck fetch ReactAndroid/src/androidTest/...
|
||||
./gradlew :ReactAndroid:downloadBoost :ReactAndroid:downloadDoubleConversion :ReactAndroid:downloadFolly :ReactAndroid:downloadGlog :ReactAndroid:downloadJSCHeaders
|
||||
|
||||
defaults: &defaults
|
||||
working_directory: ~/react-native
|
||||
|
||||
android_defaults: &android_defaults
|
||||
<<: *defaults
|
||||
docker:
|
||||
- image: circleci/android:api-26-alpha
|
||||
resource_class: "large"
|
||||
environment:
|
||||
- TERM: "dumb"
|
||||
- ADB_INSTALL_TIMEOUT: 10
|
||||
- _JAVA_OPTIONS: "-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap"
|
||||
- GRADLE_OPTS: '-Dorg.gradle.daemon=false -Dorg.gradle.jvmargs="-XX:+HeapDumpOnOutOfMemoryError"'
|
||||
- ANDROID_NDK: '/opt/ndk/android-ndk-r10e'
|
||||
- BUILD_THREADS: 2
|
||||
|
||||
version: 2
|
||||
jobs:
|
||||
# Runs JavaScript tests on Node 8
|
||||
@@ -208,6 +275,7 @@ jobs:
|
||||
- save-cache: *save-node-cache
|
||||
- run: ./scripts/process-podspecs.sh
|
||||
|
||||
# Tests website
|
||||
test-website:
|
||||
<<: *defaults
|
||||
docker:
|
||||
@@ -228,6 +296,7 @@ jobs:
|
||||
name: Test Build Static Website
|
||||
command: cd website && node ./server/generate.js
|
||||
|
||||
# Deploys website
|
||||
deploy-website:
|
||||
<<: *defaults
|
||||
docker:
|
||||
@@ -252,6 +321,46 @@ jobs:
|
||||
echo "Skipping deploy."
|
||||
fi
|
||||
|
||||
# Publishes new version onto npm
|
||||
deploy:
|
||||
<<: *android_defaults
|
||||
steps:
|
||||
- checkout
|
||||
|
||||
# Configure Android dependencies
|
||||
- run: *configure-android-path
|
||||
- run: *install-build-dependencies
|
||||
- restore-cache: *restore-cache-android-packages
|
||||
- run: *install-android-packages
|
||||
- save-cache: *save-cache-android-packages
|
||||
- run: *create-ndk-directory
|
||||
- restore-cache: *restore-cache-ndk
|
||||
- run: *install-ndk
|
||||
- save-cache: *save-cache-ndk
|
||||
- restore-cache: *restore-cache-buck
|
||||
- run: *install-buck
|
||||
- save-cache: *save-cache-buck
|
||||
- run: *install-node
|
||||
- restore-cache: *restore-node-cache
|
||||
- run: *install-node-dependencies
|
||||
- save-cache: *save-node-cache
|
||||
- restore-cache: *restore-cache-buck-downloads
|
||||
- run: *install-android-app-dependencies
|
||||
- save-cache: *save-cache-buck-downloads
|
||||
|
||||
- run:
|
||||
name: Publish React Native Package
|
||||
command: |
|
||||
if [ -z "$CIRCLE_PULL_REQUEST" ]; then
|
||||
echo "//registry.npmjs.org/:_authToken=${CIRCLE_NPM_TOKEN}" > ~/.npmrc
|
||||
git config --global user.email "reactjs-bot@users.noreply.github.com"
|
||||
git config --global user.name "Website Deployment Script"
|
||||
echo "machine github.com login reactjs-bot password $GITHUB_TOKEN" > ~/.netrc
|
||||
node ./scripts/publish-npm.js
|
||||
else
|
||||
echo "Skipping deploy."
|
||||
fi
|
||||
|
||||
# Build JavaScript bundle for Android tests
|
||||
build-js-bundle:
|
||||
<<: *defaults
|
||||
@@ -274,116 +383,55 @@ jobs:
|
||||
|
||||
# Runs unit tests tests on Android
|
||||
test-android:
|
||||
<<: *defaults
|
||||
docker:
|
||||
- image: circleci/android:api-26-alpha
|
||||
environment:
|
||||
- TERM: "dumb"
|
||||
- ADB_INSTALL_TIMEOUT: 10
|
||||
- GRADLE_OPTS: '-Dorg.gradle.jvmargs="-Xmx512m -XX:+HeapDumpOnOutOfMemoryError"'
|
||||
- ANDROID_NDK: '/opt/ndk/android-ndk-r10e'
|
||||
- BUILD_THREADS: 2
|
||||
<<: *android_defaults
|
||||
steps:
|
||||
- checkout
|
||||
# CircleCI does not support interpolating env variables in the environment: step above.
|
||||
# https://circleci.com/docs/2.0/env-vars/#interpolating-environment-variables-to-set-other-environment-variables
|
||||
- run:
|
||||
name: Configure PATH
|
||||
command: |
|
||||
echo 'export PATH=${ANDROID_NDK}:~/react-native/gradle-2.9/bin:~/buck/bin:$PATH' >> $BASH_ENV
|
||||
source $BASH_ENV
|
||||
# Configure dependencies
|
||||
- run:
|
||||
name: Install Build Dependencies
|
||||
command: |
|
||||
sudo apt-get update -y
|
||||
sudo apt-get install ant autoconf automake g++ gcc libqt5widgets5 lib32z1 lib32stdc++6 make maven python-dev python3-dev qml-module-qtquick-controls qtdeclarative5-dev -y
|
||||
|
||||
# Configure Android dependencies
|
||||
- run: *configure-android-path
|
||||
- run: *install-build-dependencies
|
||||
- restore-cache: *restore-cache-android-packages
|
||||
- run:
|
||||
name: Install Android Packages
|
||||
command: source scripts/circle-ci-android-setup.sh && getAndroidSDK
|
||||
- run: *install-android-packages
|
||||
- save-cache: *save-cache-android-packages
|
||||
|
||||
# Starting emulator in advance as it takes some time to boot.
|
||||
- run:
|
||||
name: Create Android Virtual Device
|
||||
command: source scripts/circle-ci-android-setup.sh && createAVD
|
||||
# Starting emulator in advance as it takes some time to boot.
|
||||
- run:
|
||||
name: Launch Android Virtual Device in Background
|
||||
command: source scripts/circle-ci-android-setup.sh && launchAVD
|
||||
background: true
|
||||
# Continue configuring dependencies while AVD boots.
|
||||
- run:
|
||||
name: Create Android NDK Directory
|
||||
command: |
|
||||
if [[ ! -e /opt/ndk ]]; then
|
||||
sudo mkdir /opt/ndk
|
||||
fi
|
||||
sudo chown ${USER:=$(/usr/bin/id -run)}:$USER /opt/ndk
|
||||
|
||||
# Keep configuring Android dependencies while AVD boots up
|
||||
- run: *create-ndk-directory
|
||||
- restore-cache: *restore-cache-ndk
|
||||
- run:
|
||||
name: Install Android NDK
|
||||
command: source scripts/circle-ci-android-setup.sh && getAndroidNDK
|
||||
- run: *install-ndk
|
||||
- save-cache: *save-cache-ndk
|
||||
- restore-cache: *restore-cache-buck
|
||||
- run:
|
||||
name: Install Buck
|
||||
command: |
|
||||
if [[ ! -e ~/buck ]]; then
|
||||
git clone https://github.com/facebook/buck.git ~/buck --branch v2017.09.04.02 --depth=1
|
||||
fi
|
||||
cd ~/buck && ant
|
||||
buck --version
|
||||
- run: *install-buck
|
||||
- save-cache: *save-cache-buck
|
||||
- run:
|
||||
name: Install Node
|
||||
command: |
|
||||
curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash -
|
||||
sudo apt-get install -y nodejs
|
||||
- run: *install-node
|
||||
- restore-cache: *restore-node-cache
|
||||
- run: *install-node-dependencies
|
||||
- save-cache: *save-node-cache
|
||||
# TODO: Install and use watchman to speed up builds
|
||||
# - restore-cache: *restore-cache-watchman
|
||||
# - run:
|
||||
# name: Install Watchman Dependencies
|
||||
# command: |
|
||||
# sudo apt-get update -y
|
||||
# sudo apt-get install libtool pkg-config -y
|
||||
# - run:
|
||||
# name: Install Watchman
|
||||
# command: |
|
||||
# if [[ ! -e ~/watchman ]]; then
|
||||
# mkdir ~/watchman
|
||||
# git clone https://github.com/facebook/watchman.git ~/watchman --branch v4.9.0 --depth=1
|
||||
# cd ~/watchman
|
||||
# ./autogen.sh
|
||||
# ./configure
|
||||
# make
|
||||
# fi
|
||||
# cd ~/watchman
|
||||
# sudo make install
|
||||
# - save-cache: *save-cache-watchman
|
||||
- restore-cache: *restore-cache-buck-downloads
|
||||
- run:
|
||||
name: Download Android App Dependencies
|
||||
command: |
|
||||
buck fetch ReactAndroid/src/test/java/com/facebook/react/modules
|
||||
buck fetch ReactAndroid/src/main/java/com/facebook/react
|
||||
buck fetch ReactAndroid/src/main/java/com/facebook/react/shell
|
||||
buck fetch ReactAndroid/src/test/...
|
||||
buck fetch ReactAndroid/src/androidTest/...
|
||||
./gradlew :ReactAndroid:downloadBoost :ReactAndroid:downloadDoubleConversion :ReactAndroid:downloadFolly :ReactAndroid:downloadGlog :ReactAndroid:downloadJSCHeaders
|
||||
- run: *install-android-app-dependencies
|
||||
- save-cache: *save-cache-buck-downloads
|
||||
|
||||
- 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
|
||||
# Wait for AVD to finish booting before running tests
|
||||
|
||||
# Wait for AVD to finish booting before running tests
|
||||
- run:
|
||||
name: Wait for Android Virtual Device
|
||||
command: source scripts/circle-ci-android-setup.sh && waitForAVD
|
||||
# The JavaScript Bundle is built as part of the build-js-bundle workflow, and is required for instrumentation tests.
|
||||
|
||||
# The JavaScript Bundle is built as part of the build-js-bundle workflow,
|
||||
# and is required for instrumentation tests.
|
||||
- attach_workspace:
|
||||
at: ReactAndroid/src/androidTest/assets/
|
||||
- run:
|
||||
@@ -394,7 +442,8 @@ jobs:
|
||||
else
|
||||
echo "JavaScript bundle found.";
|
||||
fi
|
||||
# Tests
|
||||
|
||||
# Tests
|
||||
- run:
|
||||
name: Compile Native Libs for Unit and Integration Tests
|
||||
command: ./gradlew :ReactAndroid:packageReactNdkLibsForBuck -Pjobs=$BUILD_THREADS -Pcom.android.build.threadPoolSize=1
|
||||
@@ -402,28 +451,19 @@ jobs:
|
||||
- run:
|
||||
name: Unit Tests
|
||||
command: buck test ReactAndroid/src/test/... --config build.threads=$BUILD_THREADS
|
||||
# Integration Tests
|
||||
|
||||
# Integration Tests
|
||||
- run:
|
||||
name: Build and Install Test APK
|
||||
command: source scripts/circle-ci-android-setup.sh && NO_BUCKD=1 retry3 buck install ReactAndroid/src/androidTest/buck-runner:instrumentation-tests --config build.threads=$BUILD_THREADS
|
||||
# TODO: Uncomment, test was already failing on Circle 1.0
|
||||
# - run:
|
||||
# name: Run Installed APK with Tests
|
||||
# command: node ./scripts/run-android-ci-instrumentation-tests.js --retries 3 --path ./ReactAndroid/src/androidTest/java/com/facebook/react/tests --package com.facebook.react.tests
|
||||
# TODO: Should be disabled, pending on https://our.intern.facebook.com/intern/tasks?t=16912142
|
||||
# - run:
|
||||
# name: Run Android End to End Tests
|
||||
# command: source scripts/circle-ci-android-setup.sh && retry3 node ./scripts/run-ci-e2e-tests.js --android --js --retries 2
|
||||
|
||||
# post (always runs)
|
||||
|
||||
# post (always runs)
|
||||
- run:
|
||||
name: Collect Test Results
|
||||
command: |
|
||||
mkdir -p ~/junit/
|
||||
find . -type f -regex ".*/build/test-results/debug/.*xml" -exec cp {} ~/junit/ \;
|
||||
find . -type f -regex ".*/outputs/androidTest-results/connected/.*xml" -exec cp {} ~/junit/ \;
|
||||
# TODO: Circle does not understand Buck's report, maybe need to transform xml slightly
|
||||
# find . -type f -regex ".*/buck-out/gen/ReactAndroid/src/test/.*/.*xml" -exec cp {} ~/junit/ \;
|
||||
when: always
|
||||
- store_test_results:
|
||||
path: ~/junit
|
||||
@@ -449,7 +489,6 @@ jobs:
|
||||
echo "Skipping dependency installation."
|
||||
fi
|
||||
- save-cache: *save-cache-analysis
|
||||
# Run Danger
|
||||
- run:
|
||||
name: Analyze Pull Request
|
||||
command: |
|
||||
@@ -459,7 +498,6 @@ jobs:
|
||||
echo "Skipping pull request analysis."
|
||||
fi
|
||||
when: always
|
||||
# Run eslint
|
||||
- run:
|
||||
name: Analyze Code
|
||||
command: |
|
||||
@@ -469,81 +507,51 @@ jobs:
|
||||
echo "Skipping code analysis."
|
||||
fi
|
||||
|
||||
publish-npm:
|
||||
<<: *defaults
|
||||
docker:
|
||||
- image: circleci/node:8
|
||||
steps:
|
||||
- checkout
|
||||
- run: *install-node-dependencies
|
||||
- run:
|
||||
name: Publish React Native Package
|
||||
command: |
|
||||
if [ -z "$CIRCLE_PULL_REQUEST" ]; then
|
||||
echo "//registry.npmjs.org/:_authToken=${CIRCLE_NPM_TOKEN}" > ~/.npmrc
|
||||
git config --global user.email "reactjs-bot@users.noreply.github.com"
|
||||
git config --global user.name "Website Deployment Script"
|
||||
echo "machine github.com login reactjs-bot password $GITHUB_TOKEN" > ~/.netrc
|
||||
node ./scripts/publish-npm.js
|
||||
else
|
||||
echo "Skipping publication."
|
||||
fi
|
||||
|
||||
# Workflows enables us to run multiple jobs in parallel
|
||||
workflows:
|
||||
version: 2
|
||||
|
||||
test_node:
|
||||
|
||||
build:
|
||||
jobs:
|
||||
|
||||
# Test Javascript on Node 8 and 6
|
||||
- test-js-node-8:
|
||||
filters: *filter-ignore-gh-pages
|
||||
- test-js-node-6:
|
||||
filters: *filter-ignore-gh-pages
|
||||
|
||||
# TODO: Re-enable. Node 4 tests are already failing on Circle 1.0
|
||||
# - test-js-node-4:
|
||||
# filters: *filter-ignore-gh-pages
|
||||
|
||||
|
||||
test_android:
|
||||
jobs:
|
||||
# Test Android
|
||||
- build-js-bundle:
|
||||
filters: *filter-ignore-gh-pages
|
||||
- test-android:
|
||||
requires:
|
||||
- build-js-bundle
|
||||
|
||||
test_ios:
|
||||
jobs:
|
||||
# Test iOS & tvOS
|
||||
- test-objc-ios:
|
||||
filters: *filter-ignore-gh-pages
|
||||
- test-objc-tvos:
|
||||
filters: *filter-ignore-gh-pages
|
||||
- test-objc-e2e:
|
||||
filters: *filter-ignore-gh-pages
|
||||
# TODO: Re-enable. Podspec tests are already failing on Travis
|
||||
# - test-podspec:
|
||||
# filters: *filter-ignore-gh-pages
|
||||
|
||||
website:
|
||||
jobs:
|
||||
# Test website
|
||||
- test-website:
|
||||
filters: *filter-ignore-gh-pages
|
||||
- deploy-website:
|
||||
requires:
|
||||
- test-website
|
||||
filters: *filter-only-master-stable
|
||||
|
||||
analyze:
|
||||
jobs:
|
||||
- analyze-pull-request:
|
||||
filters: *filter-ignore-master-stable
|
||||
|
||||
deploy:
|
||||
jobs:
|
||||
|
||||
# If we are on a stable branch, deploy to `npm`
|
||||
- hold:
|
||||
type: approval
|
||||
- publish-npm:
|
||||
requires:
|
||||
- deploy:
|
||||
filters: *filter-only-stable
|
||||
requires:
|
||||
- hold
|
||||
|
||||
# If we are on a master / stable branch, deploy docs
|
||||
- deploy-website:
|
||||
filters: *filter-only-master-stable
|
||||
requires:
|
||||
- test-website
|
||||
|
||||
- analyze-pull-request:
|
||||
filters: *filter-ignore-master-stable
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
exports.version = {
|
||||
major: 0,
|
||||
minor: 0,
|
||||
patch: 0,
|
||||
minor: 51,
|
||||
patch: 1,
|
||||
prerelease: null,
|
||||
};
|
||||
|
||||
@@ -427,6 +427,20 @@
|
||||
remoteGlobalIDString = 134814201AA4EA6300B7C361;
|
||||
remoteInfo = RCTSettings;
|
||||
};
|
||||
AD9FBECB1FD7597F00CADA08 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 14AADEFF1AC3DB95002390C9 /* React.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 9936F3131F5F2E4B0010BF04;
|
||||
remoteInfo = privatedata;
|
||||
};
|
||||
AD9FBECD1FD7597F00CADA08 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 14AADEFF1AC3DB95002390C9 /* React.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 9936F32F1F5F2E5B0010BF04;
|
||||
remoteInfo = "privatedata-tvOS";
|
||||
};
|
||||
D85B829B1AB6D5CE003F4FE2 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = D85B82911AB6D5CE003F4FE2 /* RCTVibration.xcodeproj */;
|
||||
@@ -806,6 +820,8 @@
|
||||
2D66FF8C1ECA405900F0A767 /* libthird-party.a */,
|
||||
3D507F441EBC88B700B56834 /* libdouble-conversion.a */,
|
||||
2D66FF8E1ECA405900F0A767 /* libdouble-conversion.a */,
|
||||
AD9FBECC1FD7597F00CADA08 /* libprivatedata.a */,
|
||||
AD9FBECE1FD7597F00CADA08 /* libprivatedata-tvOS.a */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
@@ -1478,6 +1494,20 @@
|
||||
remoteRef = 834C36D11AF8DA610019C93C /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
AD9FBECC1FD7597F00CADA08 /* libprivatedata.a */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = archive.ar;
|
||||
path = libprivatedata.a;
|
||||
remoteRef = AD9FBECB1FD7597F00CADA08 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
AD9FBECE1FD7597F00CADA08 /* libprivatedata-tvOS.a */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = archive.ar;
|
||||
path = "libprivatedata-tvOS.a";
|
||||
remoteRef = AD9FBECD1FD7597F00CADA08 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
D85B829C1AB6D5CE003F4FE2 /* libRCTVibration.a */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = archive.ar;
|
||||
|
||||
@@ -44,13 +44,6 @@ RCT_TEST(LayoutExample)
|
||||
RCT_TEST(ARTExample)
|
||||
RCT_TEST(ScrollViewExample)
|
||||
RCT_TEST(TextExample)
|
||||
#if !TARGET_OS_TV
|
||||
// No switch or slider available on tvOS
|
||||
RCT_TEST(SwitchExample)
|
||||
RCT_TEST(SliderExample)
|
||||
// TabBarExample on tvOS passes locally but not on Travis
|
||||
RCT_TEST(TabBarExample)
|
||||
#endif
|
||||
|
||||
- (void)testZZZNotInRecordMode
|
||||
{
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
require('MessageQueue').spy(true);
|
||||
|
||||
const AsyncStorage = require('AsyncStorage');
|
||||
const BackHandler = require('BackHandler');
|
||||
const Linking = require('Linking');
|
||||
|
||||
@@ -320,10 +320,14 @@ class AutogrowingTextInputExample extends React.Component<{}> {
|
||||
width: 100,
|
||||
multiline: true,
|
||||
text: '',
|
||||
contentSize: {
|
||||
width: 0,
|
||||
height: 0,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
componentDidReceiveProps(props) {
|
||||
componentWillReceiveProps(props) {
|
||||
this.setState({
|
||||
multiline: props.multiline,
|
||||
});
|
||||
@@ -351,10 +355,12 @@ class AutogrowingTextInputExample extends React.Component<{}> {
|
||||
multiline={this.state.multiline}
|
||||
style={[style, {width: this.state.width + '%'}]}
|
||||
onChangeText={(value) => this.setState({text: value})}
|
||||
onContentSizeChange={(event) => this.setState({contentSize: event.nativeEvent.contentSize})}
|
||||
{...props}
|
||||
/>
|
||||
<Text>Plain text value representation:</Text>
|
||||
<Text>{this.state.text}</Text>
|
||||
<Text>Content Size: {JSON.stringify(this.state.contentSize)}</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -109,6 +109,7 @@ Pod::Spec.new do |s|
|
||||
|
||||
s.subspec "jschelpers" do |ss|
|
||||
ss.dependency "Folly", "2016.09.26.00"
|
||||
ss.dependency "React/PrivateDatabase"
|
||||
ss.compiler_flags = folly_compiler_flags
|
||||
ss.source_files = "ReactCommon/jschelpers/*.{cpp,h}"
|
||||
ss.private_header_files = "ReactCommon/jschelpers/*.h"
|
||||
@@ -116,6 +117,12 @@ Pod::Spec.new do |s|
|
||||
ss.framework = "JavaScriptCore"
|
||||
end
|
||||
|
||||
s.subspec "PrivateDatabase" do |ss|
|
||||
ss.source_files = "ReactCommon/privatedata/*.{cpp,h}"
|
||||
ss.private_header_files = "ReactCommon/privatedata/*.h"
|
||||
ss.pod_target_xcconfig = { "HEADER_SEARCH_PATHS" => "\"$(PODS_TARGET_SRCROOT)/ReactCommon\"" }
|
||||
end
|
||||
|
||||
s.subspec "cxxreact" do |ss|
|
||||
ss.dependency "React/jschelpers"
|
||||
ss.dependency "boost"
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
methodName = "init";
|
||||
}
|
||||
RCTLogWarn(@"Module %@ requires main queue setup since it overrides `%s` but doesn't implement "
|
||||
"`requiresMainQueueSetup. In a future release React Native will default to initializing all native modules "
|
||||
"`requiresMainQueueSetup`. In a future release React Native will default to initializing all native modules "
|
||||
"on a background thread unless explicitly opted-out of.", _moduleClass, methodName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
#define RCT_REACT_NATIVE_VERSION @{ \
|
||||
@"major": @(0), \
|
||||
@"minor": @(0), \
|
||||
@"patch": @(0), \
|
||||
@"minor": @(51), \
|
||||
@"patch": @(1), \
|
||||
@"prerelease": [NSNull null], \
|
||||
}
|
||||
|
||||
@@ -17,6 +17,11 @@ static NSString *const TVNavigationEventName = @"onTVNavEvent";
|
||||
|
||||
RCT_EXPORT_MODULE()
|
||||
|
||||
+ (BOOL)requiresMainQueueSetup
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
if (self = [super init]) {
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
#import "RCTSafeAreaViewLocalData.h"
|
||||
|
||||
@implementation RCTSafeAreaView {
|
||||
RCTBridge *_bridge;
|
||||
__weak RCTBridge *_bridge;
|
||||
UIEdgeInsets _currentSafeAreaInsets;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
VERSION_NAME=1000.0.0-master
|
||||
VERSION_NAME=0.51.1
|
||||
GROUP=com.facebook.react
|
||||
|
||||
POM_NAME=ReactNative
|
||||
|
||||
@@ -12,7 +12,6 @@ android_library(
|
||||
provided_deps = [
|
||||
react_native_dep("third-party/android/support/v4:lib-support-v4"),
|
||||
],
|
||||
required_for_source_only_abi = True,
|
||||
visibility = [
|
||||
"PUBLIC",
|
||||
],
|
||||
|
||||
@@ -16,7 +16,6 @@ android_library(
|
||||
provided_deps = [
|
||||
react_native_dep("third-party/android/support/v4:lib-support-v4"),
|
||||
],
|
||||
required_for_source_only_abi = True,
|
||||
visibility = [
|
||||
"PUBLIC",
|
||||
],
|
||||
|
||||
+11
-7
@@ -9,14 +9,17 @@
|
||||
|
||||
package com.facebook.react.devsupport;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import com.facebook.infer.annotation.Assertions;
|
||||
import com.facebook.react.bridge.JavaJSExecutor;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.concurrent.Semaphore;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
|
||||
import com.facebook.infer.annotation.Assertions;
|
||||
import com.facebook.react.bridge.JavaJSExecutor;
|
||||
|
||||
/**
|
||||
* Executes JS remotely via the react nodejs server as a proxy to a browser on the host machine.
|
||||
@@ -157,7 +160,8 @@ public class WebsocketJavaScriptExecutor implements JavaJSExecutor {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadApplicationScript(String sourceURL) throws JavaJSExecutor.ProxyExecutorException {
|
||||
public void loadApplicationScript(String sourceURL)
|
||||
throws ProxyExecutorException {
|
||||
JSExecutorCallbackFuture callback = new JSExecutorCallbackFuture();
|
||||
Assertions.assertNotNull(mWebSocketClient).loadApplicationScript(
|
||||
sourceURL,
|
||||
@@ -172,7 +176,7 @@ public class WebsocketJavaScriptExecutor implements JavaJSExecutor {
|
||||
|
||||
@Override
|
||||
public @Nullable String executeJSCall(String methodName, String jsonArgsArray)
|
||||
throws JavaJSExecutor.ProxyExecutorException {
|
||||
throws ProxyExecutorException {
|
||||
JSExecutorCallbackFuture callback = new JSExecutorCallbackFuture();
|
||||
Assertions.assertNotNull(mWebSocketClient).executeJSCall(
|
||||
methodName,
|
||||
|
||||
@@ -3,7 +3,6 @@ include_defs("//ReactAndroid/DEFS")
|
||||
android_library(
|
||||
name = "annotations",
|
||||
srcs = glob(["**/*.java"]),
|
||||
required_for_source_only_abi = True,
|
||||
visibility = [
|
||||
"PUBLIC",
|
||||
],
|
||||
|
||||
+2
-2
@@ -18,7 +18,7 @@ import java.util.Map;
|
||||
public class ReactNativeVersion {
|
||||
public static final Map<String, Object> VERSION = MapBuilder.<String, Object>of(
|
||||
"major", 0,
|
||||
"minor", 0,
|
||||
"patch", 0,
|
||||
"minor", 51,
|
||||
"patch", 1,
|
||||
"prerelease", null);
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@ android_library(
|
||||
provided_deps = [
|
||||
react_native_dep("third-party/android/support/v4:lib-support-v4"),
|
||||
],
|
||||
required_for_source_only_abi = True,
|
||||
visibility = [
|
||||
"PUBLIC",
|
||||
],
|
||||
|
||||
@@ -3,7 +3,6 @@ include_defs("//ReactAndroid/DEFS")
|
||||
android_library(
|
||||
name = "annotations",
|
||||
srcs = glob(["*.java"]),
|
||||
required_for_source_only_abi = True,
|
||||
visibility = [
|
||||
"PUBLIC",
|
||||
],
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@ import android.view.animation.Transformation;
|
||||
*/
|
||||
/* package */ class OpacityAnimation extends Animation {
|
||||
|
||||
static class OpacityAnimationListener implements Animation.AnimationListener {
|
||||
static class OpacityAnimationListener implements AnimationListener {
|
||||
|
||||
private final View mView;
|
||||
private boolean mLayerTypeChanged = false;
|
||||
|
||||
@@ -11,7 +11,6 @@ android_library(
|
||||
react_native_dep("third-party/android/support-annotations:android-support-annotations"),
|
||||
react_native_dep("third-party/android/support/v4:lib-support-v4"),
|
||||
],
|
||||
required_for_source_only_abi = True,
|
||||
visibility = ["PUBLIC"],
|
||||
deps = [
|
||||
react_native_dep("third-party/java/jsr-305:jsr-305"),
|
||||
|
||||
@@ -229,11 +229,11 @@ public class ReactImageView extends GenericDraweeView {
|
||||
}
|
||||
|
||||
public void setBlurRadius(float blurRadius) {
|
||||
if (blurRadius == 0) {
|
||||
int pixelBlurRadius = (int) PixelUtil.toPixelFromDIP(blurRadius);
|
||||
if (pixelBlurRadius == 0) {
|
||||
mIterativeBoxBlurPostProcessor = null;
|
||||
} else {
|
||||
mIterativeBoxBlurPostProcessor =
|
||||
new IterativeBoxBlurPostProcessor((int) PixelUtil.toPixelFromDIP(blurRadius));
|
||||
mIterativeBoxBlurPostProcessor = new IterativeBoxBlurPostProcessor(pixelBlurRadius);
|
||||
}
|
||||
mIsDirty = true;
|
||||
}
|
||||
|
||||
@@ -117,16 +117,7 @@ public class ReactEditText extends EditText {
|
||||
// TODO: t6408636 verify if we should schedule a layout after a View does a requestLayout()
|
||||
@Override
|
||||
public boolean isLayoutRequested() {
|
||||
// If we are watching and updating container height based on content size
|
||||
// then we don't want to scroll right away. This isn't perfect -- you might
|
||||
// want to limit the height the text input can grow to. Possible solution
|
||||
// is to add another prop that determines whether we should scroll to end
|
||||
// of text.
|
||||
if (mContentSizeWatcher != null) {
|
||||
return isMultiline();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -54,13 +54,13 @@ public class ReactViewGroup extends ViewGroup implements
|
||||
|
||||
/**
|
||||
* This listener will be set for child views when removeClippedSubview property is enabled. When
|
||||
* children layout is updated, it will call {@link #updateSubviewClipStatus} to notify parent view
|
||||
* about that fact so that view can be attached/detached if necessary.
|
||||
* children layout is updated, it will call {@link #updateSubviewClipStatus} to notify parent
|
||||
* view about that fact so that view can be attached/detached if necessary.
|
||||
*
|
||||
* <p>TODO(7728005): Attach/detach views in batch - once per frame in case when multiple children
|
||||
* TODO(7728005): Attach/detach views in batch - once per frame in case when multiple children
|
||||
* update their layout.
|
||||
*/
|
||||
private static final class ChildrenLayoutChangeListener implements View.OnLayoutChangeListener {
|
||||
private static final class ChildrenLayoutChangeListener implements OnLayoutChangeListener {
|
||||
|
||||
private final ReactViewGroup mParent;
|
||||
|
||||
@@ -396,7 +396,7 @@ public class ReactViewGroup extends ViewGroup implements
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addView(View child, int index, ViewGroup.LayoutParams params) {
|
||||
public void addView(View child, int index, LayoutParams params) {
|
||||
// This will get called for every overload of addView so there is not need to override every method.
|
||||
mDrawingOrderHelper.handleAddView(child);
|
||||
setChildrenDrawingOrderEnabled(mDrawingOrderHelper.shouldEnableCustomDrawingOrder());
|
||||
@@ -468,8 +468,7 @@ public class ReactViewGroup extends ViewGroup implements
|
||||
addViewWithSubviewClippingEnabled(child, index, sDefaultLayoutParam);
|
||||
}
|
||||
|
||||
/*package*/ void addViewWithSubviewClippingEnabled(
|
||||
View child, int index, ViewGroup.LayoutParams params) {
|
||||
/*package*/ void addViewWithSubviewClippingEnabled(View child, int index, LayoutParams params) {
|
||||
Assertions.assertCondition(mRemoveClippedSubviews);
|
||||
Assertions.assertNotNull(mClippingRect);
|
||||
Assertions.assertNotNull(mAllChildren);
|
||||
|
||||
@@ -9,17 +9,19 @@
|
||||
|
||||
package com.facebook.react.views.viewpager;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import android.support.v4.view.PagerAdapter;
|
||||
import android.support.v4.view.ViewPager;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.facebook.react.bridge.ReactContext;
|
||||
import com.facebook.react.uimanager.UIManagerModule;
|
||||
import com.facebook.react.uimanager.events.EventDispatcher;
|
||||
import com.facebook.react.uimanager.events.NativeGestureUtil;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Wrapper view for {@link ViewPager}. It's forwarding calls to {@link ViewGroup#addView} to add
|
||||
@@ -116,7 +118,7 @@ public class ReactViewPager extends ViewPager {
|
||||
}
|
||||
}
|
||||
|
||||
private class PageChangeListener implements ViewPager.OnPageChangeListener {
|
||||
private class PageChangeListener implements OnPageChangeListener {
|
||||
|
||||
@Override
|
||||
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
|
||||
|
||||
@@ -26,18 +26,27 @@ describe('findPlugins', () => {
|
||||
jest.mock(pjsonPath, () => ({
|
||||
dependencies: {'rnpm-plugin-test': '*'},
|
||||
}));
|
||||
expect(findPlugins([ROOT])).toHaveLength(1);
|
||||
expect(findPlugins([ROOT])[0]).toBe('rnpm-plugin-test');
|
||||
|
||||
expect(findPlugins([ROOT])).toHaveProperty('commands');
|
||||
expect(findPlugins([ROOT])).toHaveProperty('platforms');
|
||||
expect(findPlugins([ROOT]).commands).toHaveLength(1);
|
||||
expect(findPlugins([ROOT]).commands[0]).toBe('rnpm-plugin-test');
|
||||
expect(findPlugins([ROOT]).platforms).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('returns an empty array if there are no plugins in this folder', () => {
|
||||
jest.mock(pjsonPath, () => ({}));
|
||||
expect(findPlugins([ROOT])).toHaveLength(0);
|
||||
expect(findPlugins([ROOT])).toHaveProperty('commands');
|
||||
expect(findPlugins([ROOT])).toHaveProperty('platforms');
|
||||
expect(findPlugins([ROOT]).commands).toHaveLength(0);
|
||||
expect(findPlugins([ROOT]).platforms).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('returns an empty array if there is no package.json in the supplied folder', () => {
|
||||
expect(Array.isArray(findPlugins(['fake-path']))).toBeTruthy();
|
||||
expect(findPlugins(['fake-path'])).toHaveLength(0);
|
||||
it('returns an object with empty arrays if there is no package.json in the supplied folder', () => {
|
||||
expect(findPlugins(['fake-path'])).toHaveProperty('commands');
|
||||
expect(findPlugins(['fake-path'])).toHaveProperty('platforms');
|
||||
expect(findPlugins(['fake-path']).commands).toHaveLength(0);
|
||||
expect(findPlugins(['fake-path']).platforms).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('returns plugins from both dependencies and dev dependencies', () => {
|
||||
@@ -45,7 +54,10 @@ describe('findPlugins', () => {
|
||||
dependencies: {'rnpm-plugin-test': '*'},
|
||||
devDependencies: {'rnpm-plugin-test-2': '*'},
|
||||
}));
|
||||
expect(findPlugins([ROOT])).toHaveLength(2);
|
||||
expect(findPlugins([ROOT])).toHaveProperty('commands');
|
||||
expect(findPlugins([ROOT])).toHaveProperty('platforms');
|
||||
expect(findPlugins([ROOT]).commands).toHaveLength(2);
|
||||
expect(findPlugins([ROOT]).platforms).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('returns unique list of plugins', () => {
|
||||
@@ -53,6 +65,6 @@ describe('findPlugins', () => {
|
||||
dependencies: {'rnpm-plugin-test': '*'},
|
||||
devDependencies: {'rnpm-plugin-test': '*'},
|
||||
}));
|
||||
expect(findPlugins([ROOT])).toHaveLength(1);
|
||||
expect(findPlugins([ROOT]).commands).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -126,3 +126,5 @@ exports.dependencyConfig = function dependencyConfigAndroid(folder, userConfig)
|
||||
|
||||
return { sourceDir, folder, manifest, packageImportPath, packageInstance };
|
||||
};
|
||||
|
||||
exports.linkConfig = require('../../link/android');
|
||||
|
||||
@@ -37,11 +37,19 @@ const findPluginsInReactNativePackage = (pjson) => {
|
||||
return path.join(pjson.name, pjson.rnpm.plugin);
|
||||
};
|
||||
|
||||
const findPlatformsInPackage = (pjson) => {
|
||||
if (!pjson.rnpm || !pjson.rnpm.platform) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return path.join(pjson.name, pjson.rnpm.platform);
|
||||
};
|
||||
|
||||
const findPluginInFolder = (folder) => {
|
||||
const pjson = readPackage(folder);
|
||||
|
||||
if (!pjson) {
|
||||
return [];
|
||||
return {commands: [], platforms: []};
|
||||
}
|
||||
|
||||
const deps = union(
|
||||
@@ -51,27 +59,33 @@ const findPluginInFolder = (folder) => {
|
||||
|
||||
return deps.reduce(
|
||||
(acc, pkg) => {
|
||||
let commands = acc.commands;
|
||||
let platforms = acc.platforms;
|
||||
if (isRNPMPlugin(pkg)) {
|
||||
return acc.concat(pkg);
|
||||
commands = commands.concat(pkg);
|
||||
}
|
||||
if (isReactNativePlugin(pkg)) {
|
||||
const pkgJson = readPackage(path.join(folder, 'node_modules', pkg));
|
||||
if (!pkgJson) {
|
||||
return acc;
|
||||
if (pkgJson) {
|
||||
commands = commands.concat(findPluginsInReactNativePackage(pkgJson));
|
||||
platforms = platforms.concat(findPlatformsInPackage(pkgJson));
|
||||
}
|
||||
return acc.concat(findPluginsInReactNativePackage(pkgJson));
|
||||
}
|
||||
return acc;
|
||||
return {commands: commands, platforms: platforms};
|
||||
},
|
||||
[]
|
||||
{commands: [], platforms: []}
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Find plugins in package.json of the given folder
|
||||
* @param {String} folder Path to the folder to get the package.json from
|
||||
* @type {Array} Array of plugins or an empty array if no package.json found
|
||||
* @type {Object} Object of commands and platform plugins
|
||||
*/
|
||||
module.exports = function findPlugins(folders) {
|
||||
return uniq(flatten(folders.map(findPluginInFolder)));
|
||||
const plugins = folders.map(findPluginInFolder);
|
||||
return {
|
||||
commands: uniq(flatten(plugins.map(p => p.commands))),
|
||||
platforms: uniq(flatten(plugins.map(p => p.platforms)))
|
||||
};
|
||||
};
|
||||
|
||||
+42
-12
@@ -15,7 +15,6 @@ const Config = require('../util/Config');
|
||||
const findPlugins = require('./findPlugins');
|
||||
const findAssets = require('./findAssets');
|
||||
const ios = require('./ios');
|
||||
const windows = require('./windows');
|
||||
const wrapCommands = require('./wrapCommands');
|
||||
|
||||
/* $FlowFixMe(>=0.54.0 site=react_native_oss) This comment suppresses an error
|
||||
@@ -33,6 +32,10 @@ import type {ConfigT} from 'metro-bundler';
|
||||
|
||||
export type RNConfig = {
|
||||
...ConfigT,
|
||||
/**
|
||||
* Returns an object with all platform configurations.
|
||||
*/
|
||||
getPlatformConfig(): Object,
|
||||
/**
|
||||
* Returns an array of project commands used by the CLI to load
|
||||
*/
|
||||
@@ -55,10 +58,21 @@ const attachPackage = (command, pkg) => Array.isArray(command)
|
||||
? command.map(cmd => attachPackage(cmd, pkg))
|
||||
: { ...command, pkg };
|
||||
|
||||
const appRoot = process.cwd();
|
||||
const plugins = findPlugins([appRoot]);
|
||||
const pluginPlatforms = plugins
|
||||
.platforms
|
||||
.reduce((acc, pathToPlatforms) => {
|
||||
// $FlowFixMe non-literal require
|
||||
return Object.assign(acc, require(path.join(appRoot, 'node_modules', pathToPlatforms)));
|
||||
},
|
||||
{});
|
||||
|
||||
const defaultRNConfig = {
|
||||
|
||||
getProjectCommands(): Array<CommandT> {
|
||||
const appRoot = process.cwd();
|
||||
const plugins = findPlugins([appRoot])
|
||||
const commands = plugins
|
||||
.commands
|
||||
.map(pathToCommands => {
|
||||
const name = pathToCommands.split(path.sep)[0];
|
||||
|
||||
@@ -70,35 +84,51 @@ const defaultRNConfig = {
|
||||
);
|
||||
});
|
||||
|
||||
return flatten(plugins);
|
||||
return flatten(commands);
|
||||
},
|
||||
|
||||
getPlatformConfig(): Object {
|
||||
return {
|
||||
ios,
|
||||
android,
|
||||
...pluginPlatforms
|
||||
};
|
||||
},
|
||||
|
||||
getProjectConfig(): Object {
|
||||
const platforms = this.getPlatformConfig();
|
||||
const folder = process.cwd();
|
||||
const rnpm = getRNPMConfig(folder);
|
||||
|
||||
return Object.assign({}, rnpm, {
|
||||
ios: ios.projectConfig(folder, rnpm.ios || {}),
|
||||
android: android.projectConfig(folder, rnpm.android || {}),
|
||||
windows: windows.projectConfig(folder, rnpm.windows || {}),
|
||||
let config = Object.assign({}, rnpm, {
|
||||
assets: findAssets(folder, rnpm.assets),
|
||||
});
|
||||
|
||||
Object.keys(platforms).forEach(key => {
|
||||
config[key] = platforms[key].projectConfig(folder, rnpm[key] || {});
|
||||
});
|
||||
|
||||
return config;
|
||||
},
|
||||
|
||||
getDependencyConfig(packageName: string) {
|
||||
const platforms = this.getPlatformConfig();
|
||||
const folder = path.join(process.cwd(), 'node_modules', packageName);
|
||||
const rnpm = getRNPMConfig(
|
||||
path.join(process.cwd(), 'node_modules', packageName)
|
||||
);
|
||||
|
||||
return Object.assign({}, rnpm, {
|
||||
ios: ios.dependencyConfig(folder, rnpm.ios || {}),
|
||||
android: android.dependencyConfig(folder, rnpm.android || {}),
|
||||
windows: windows.dependencyConfig(folder, rnpm.windows || {}),
|
||||
let config = Object.assign({}, rnpm, {
|
||||
assets: findAssets(folder, rnpm.assets),
|
||||
commands: wrapCommands(rnpm.commands),
|
||||
params: rnpm.params || [],
|
||||
});
|
||||
|
||||
Object.keys(platforms).forEach(key => {
|
||||
config[key] = platforms[key].dependencyConfig(folder, rnpm[key] || {});
|
||||
});
|
||||
|
||||
return config;
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -57,3 +57,5 @@ exports.projectConfig = function projectConfigIOS(folder, userConfig) {
|
||||
};
|
||||
|
||||
exports.dependencyConfig = exports.projectConfig;
|
||||
|
||||
exports.linkConfig = require('../../link/ios');
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
const fs = require('fs');
|
||||
const glob = require('glob');
|
||||
const path = require('path');
|
||||
|
||||
/**
|
||||
* Gets package's namespace
|
||||
* by searching for its declaration in all C# files present in the folder
|
||||
*
|
||||
* @param {String} folder Folder to find C# files
|
||||
*/
|
||||
module.exports = function getNamespace(folder) {
|
||||
const files = glob.sync('**/*.cs', { cwd: folder });
|
||||
|
||||
const packages = files
|
||||
.map(filePath => fs.readFileSync(path.join(folder, filePath), 'utf8'))
|
||||
.map(file => file.match(/namespace (.*)[\s\S]+IReactPackage/))
|
||||
.filter(match => match);
|
||||
|
||||
return packages.length ? packages[0][1] : null;
|
||||
};
|
||||
@@ -1,30 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
const fs = require('fs');
|
||||
const glob = require('glob');
|
||||
const path = require('path');
|
||||
|
||||
/**
|
||||
* Gets package's class name (class that implements IReactPackage)
|
||||
* by searching for its declaration in all C# files present in the folder
|
||||
*
|
||||
* @param {String} folder Folder to find C# files
|
||||
*/
|
||||
module.exports = function getPackageClassName(folder) {
|
||||
const files = glob.sync('**/*.cs', { cwd: folder });
|
||||
|
||||
const packages = files
|
||||
.map(filePath => fs.readFileSync(path.join(folder, filePath), 'utf8'))
|
||||
.map(file => file.match(/class (.*) : IReactPackage/))
|
||||
.filter(match => match);
|
||||
|
||||
return packages.length ? packages[0][1] : null;
|
||||
};
|
||||
@@ -1,27 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
const glob = require('glob');
|
||||
const path = require('path');
|
||||
|
||||
/**
|
||||
* Find an C# project file
|
||||
*
|
||||
* @param {String} folder Name of the folder where to seek
|
||||
* @return {String}
|
||||
*/
|
||||
module.exports = function findManifest(folder) {
|
||||
const csprojPath = glob.sync(path.join('**', '*.csproj'), {
|
||||
cwd: folder,
|
||||
ignore: ['node_modules/**', '**/build/**', 'Examples/**', 'examples/**'],
|
||||
})[0];
|
||||
|
||||
return csprojPath ? path.join(folder, csprojPath) : null;
|
||||
};
|
||||
@@ -1,60 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
const glob = require('glob');
|
||||
const path = require('path');
|
||||
|
||||
/**
|
||||
* Glob pattern to look for solution file
|
||||
*/
|
||||
const GLOB_PATTERN = '**/*.sln';
|
||||
|
||||
/**
|
||||
* Regexp matching all test projects
|
||||
*/
|
||||
const TEST_PROJECTS = /test|example|sample/i;
|
||||
|
||||
/**
|
||||
* Base windows folder
|
||||
*/
|
||||
const WINDOWS_BASE = 'windows';
|
||||
|
||||
/**
|
||||
* These folders will be excluded from search to speed it up
|
||||
*/
|
||||
const GLOB_EXCLUDE_PATTERN = ['**/@(node_modules)/**'];
|
||||
|
||||
/**
|
||||
* Finds windows project by looking for all .sln files
|
||||
* in given folder.
|
||||
*
|
||||
* Returns first match if files are found or null
|
||||
*
|
||||
* Note: `./windows/*.sln` are returned regardless of the name
|
||||
*/
|
||||
module.exports = function findSolution(folder) {
|
||||
const projects = glob
|
||||
.sync(GLOB_PATTERN, {
|
||||
cwd: folder,
|
||||
ignore: GLOB_EXCLUDE_PATTERN,
|
||||
})
|
||||
.filter(project => {
|
||||
return path.dirname(project) === WINDOWS_BASE || !TEST_PROJECTS.test(project);
|
||||
})
|
||||
.sort((projectA, projectB) => {
|
||||
return path.dirname(projectA) === WINDOWS_BASE ? -1 : 1;
|
||||
});
|
||||
|
||||
if (projects.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return projects[0];
|
||||
};
|
||||
@@ -1,10 +0,0 @@
|
||||
const s4 = () => {
|
||||
return Math.floor((1 + Math.random()) * 0x10000)
|
||||
.toString(16)
|
||||
.substring(1);
|
||||
};
|
||||
|
||||
module.exports = function generateGUID() {
|
||||
return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
|
||||
s4() + '-' + s4() + s4() + s4();
|
||||
};
|
||||
@@ -1,114 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
const findWindowsSolution = require('./findWindowsSolution');
|
||||
const findNamespace = require('./findNamespace');
|
||||
const findProject = require('./findProject');
|
||||
const findPackageClassName = require('./findPackageClassName');
|
||||
const path = require('path');
|
||||
const generateGUID = require('./generateGUID');
|
||||
|
||||
const relativeProjectPath = (fullProjPath) => {
|
||||
const windowsPath = fullProjPath
|
||||
.substring(fullProjPath.lastIndexOf('node_modules') - 1, fullProjPath.length)
|
||||
.replace(/\//g, '\\');
|
||||
|
||||
return '..' + windowsPath;
|
||||
};
|
||||
|
||||
const getProjectName = (fullProjPath) => {
|
||||
return fullProjPath.split('/').slice(-1)[0].replace(/\.csproj/i, '');
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets windows project config by analyzing given folder and taking some
|
||||
* defaults specified by user into consideration
|
||||
*/
|
||||
exports.projectConfig = function projectConfigWindows(folder, userConfig) {
|
||||
|
||||
const csSolution = userConfig.csSolution || findWindowsSolution(folder);
|
||||
|
||||
if (!csSolution) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// expects solutions to be named the same as project folders
|
||||
const solutionPath = path.join(folder, csSolution);
|
||||
const windowsAppFolder = csSolution.substring(0, csSolution.lastIndexOf('.sln'));
|
||||
const src = userConfig.sourceDir || windowsAppFolder;
|
||||
const sourceDir = path.join(folder, src);
|
||||
const mainPage = path.join(sourceDir, 'MainPage.cs');
|
||||
const projectPath = userConfig.projectPath || findProject(folder);
|
||||
|
||||
return {
|
||||
sourceDir,
|
||||
solutionPath,
|
||||
projectPath,
|
||||
mainPage,
|
||||
folder,
|
||||
userConfig,
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Same as projectConfigWindows except it returns
|
||||
* different config that applies to packages only
|
||||
*/
|
||||
exports.dependencyConfig = function dependencyConfigWindows(folder, userConfig) {
|
||||
|
||||
const csSolution = userConfig.csSolution || findWindowsSolution(folder);
|
||||
|
||||
if (!csSolution) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// expects solutions to be named the same as project folders
|
||||
const windowsAppFolder = csSolution.substring(0, csSolution.lastIndexOf('.sln'));
|
||||
const src = userConfig.sourceDir || windowsAppFolder;
|
||||
|
||||
if (!src) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const sourceDir = path.join(folder, src);
|
||||
const packageClassName = findPackageClassName(sourceDir);
|
||||
const namespace = userConfig.namespace || findNamespace(sourceDir);
|
||||
const csProj = userConfig.csProj || findProject(folder);
|
||||
|
||||
/**
|
||||
* This module has no package to export or no namespace
|
||||
*/
|
||||
if (!packageClassName || !namespace) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const packageUsingPath = userConfig.packageUsingPath ||
|
||||
`using ${namespace};`;
|
||||
|
||||
const packageInstance = userConfig.packageInstance ||
|
||||
`new ${packageClassName}()`;
|
||||
|
||||
const projectGUID = generateGUID();
|
||||
const pathGUID = generateGUID();
|
||||
const projectName = getProjectName(csProj);
|
||||
const relativeProjPath = relativeProjectPath(csProj);
|
||||
|
||||
return {
|
||||
sourceDir,
|
||||
packageUsingPath,
|
||||
packageInstance,
|
||||
projectName,
|
||||
csProj,
|
||||
folder,
|
||||
projectGUID,
|
||||
pathGUID,
|
||||
relativeProjPath,
|
||||
};
|
||||
};
|
||||
@@ -37,6 +37,7 @@ describe('link', () => {
|
||||
|
||||
it('should accept a name of a dependency to link', (done) => {
|
||||
const config = {
|
||||
getPlatformConfig: () => ({ios: {}, android: {}}),
|
||||
getProjectConfig: () => ({ assets: [] }),
|
||||
getDependencyConfig: sinon.stub().returns({ assets: [], commands: {} }),
|
||||
};
|
||||
@@ -52,6 +53,7 @@ describe('link', () => {
|
||||
|
||||
it('should read dependencies from package.json when name not provided', (done) => {
|
||||
const config = {
|
||||
getPlatformConfig: () => ({ios: {}, android: {}}),
|
||||
getProjectConfig: () => ({ assets: [] }),
|
||||
getDependencyConfig: sinon.stub().returns({ assets: [], commands: {} }),
|
||||
};
|
||||
@@ -77,7 +79,10 @@ describe('link', () => {
|
||||
it('should register native module when android/ios projects are present', (done) => {
|
||||
const registerNativeModule = sinon.stub();
|
||||
const dependencyConfig = {android: {}, ios: {}, assets: [], commands: {}};
|
||||
const androidLinkConfig = require('../android');
|
||||
const iosLinkConfig = require('../ios');
|
||||
const config = {
|
||||
getPlatformConfig: () => ({ios: { linkConfig: iosLinkConfig }, android: { linkConfig: androidLinkConfig }}),
|
||||
getProjectConfig: () => ({android: {}, ios: {}, assets: []}),
|
||||
getDependencyConfig: sinon.stub().returns(dependencyConfig),
|
||||
};
|
||||
@@ -114,6 +119,7 @@ describe('link', () => {
|
||||
const registerNativeModule = sinon.stub();
|
||||
const dependencyConfig = {ios: {}, android: {}, assets: [], commands: {}};
|
||||
const config = {
|
||||
getPlatformConfig: () => ({ios: {}, android: {}}),
|
||||
getProjectConfig: () => ({ ios: {}, android: {}, assets: [] }),
|
||||
getDependencyConfig: sinon.stub().returns(dependencyConfig),
|
||||
};
|
||||
@@ -146,6 +152,62 @@ describe('link', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('should register native modules for plugins', (done) => {
|
||||
const registerNativeModule = sinon.stub();
|
||||
const dependencyConfig = {ios: {}, android: {}, test: {}, assets: [], commands: {}};
|
||||
const linkPluginConfig = { isInstalled: () => false, register: registerNativeModule };
|
||||
const config = {
|
||||
getPlatformConfig: () => ({ ios: {}, android: {}, test: { linkConfig: () => linkPluginConfig }}),
|
||||
getProjectConfig: () => ({ ios: {}, android: {}, test: {}, assets: [] }),
|
||||
getDependencyConfig: sinon.stub().returns(dependencyConfig),
|
||||
};
|
||||
|
||||
jest.setMock(
|
||||
'../ios/isInstalled.js',
|
||||
sinon.stub().returns(true)
|
||||
);
|
||||
|
||||
jest.setMock(
|
||||
'../android/isInstalled.js',
|
||||
sinon.stub().returns(true)
|
||||
);
|
||||
|
||||
const link = require('../link').func;
|
||||
|
||||
link(['react-native-blur'], config).then(() => {
|
||||
expect(registerNativeModule.calledOnce).toBeTruthy();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should not register native modules for plugins when already installed', (done) => {
|
||||
const registerNativeModule = sinon.stub();
|
||||
const dependencyConfig = {ios: {}, android: {}, test: {}, assets: [], commands: {}};
|
||||
const linkPluginConfig = { isInstalled: () => true, register: registerNativeModule};
|
||||
const config = {
|
||||
getPlatformConfig: () => ({ ios: {}, android: {}, test: { linkConfig: () => linkPluginConfig }}),
|
||||
getProjectConfig: () => ({ ios: {}, android: {}, test: {}, assets: [] }),
|
||||
getDependencyConfig: sinon.stub().returns(dependencyConfig),
|
||||
};
|
||||
|
||||
jest.setMock(
|
||||
'../ios/isInstalled.js',
|
||||
sinon.stub().returns(true)
|
||||
);
|
||||
|
||||
jest.setMock(
|
||||
'../android/isInstalled.js',
|
||||
sinon.stub().returns(true)
|
||||
);
|
||||
|
||||
const link = require('../link').func;
|
||||
|
||||
link(['react-native-blur'], config).then(() => {
|
||||
expect(registerNativeModule.callCount).toEqual(0);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should run prelink and postlink commands at the appropriate times', (done) => {
|
||||
const registerNativeModule = sinon.stub();
|
||||
const prelink = sinon.stub().yieldsAsync();
|
||||
@@ -161,7 +223,9 @@ describe('link', () => {
|
||||
sinon.stub().returns(false)
|
||||
);
|
||||
|
||||
const linkConfig = require('../ios');
|
||||
const config = {
|
||||
getPlatformConfig: () => ({ ios: { linkConfig: linkConfig }}),
|
||||
getProjectConfig: () => ({ ios: {}, assets: [] }),
|
||||
getDependencyConfig: sinon.stub().returns({
|
||||
ios: {}, assets: [], commands: { prelink, postlink },
|
||||
@@ -179,7 +243,7 @@ describe('link', () => {
|
||||
|
||||
it('should copy assets from both project and dependencies projects', (done) => {
|
||||
const dependencyAssets = ['Fonts/Font.ttf'];
|
||||
const dependencyConfig = {assets: dependencyAssets, commands: {}};
|
||||
const dependencyConfig = {assets: dependencyAssets, ios: {}, commands: {}};
|
||||
const projectAssets = ['Fonts/FontC.ttf'];
|
||||
const copyAssets = sinon.stub();
|
||||
|
||||
@@ -188,7 +252,9 @@ describe('link', () => {
|
||||
copyAssets
|
||||
);
|
||||
|
||||
const linkConfig = require('../ios');
|
||||
const config = {
|
||||
getPlatformConfig: () => ({ ios: { linkConfig: linkConfig } }),
|
||||
getProjectConfig: () => ({ ios: {}, assets: projectAssets }),
|
||||
getDependencyConfig: sinon.stub().returns(dependencyConfig),
|
||||
};
|
||||
|
||||
@@ -8,10 +8,10 @@ const groupFilesByType = require('../groupFilesByType');
|
||||
* For now, the only types of files that are handled are:
|
||||
* - Fonts (otf, ttf) - copied to targetPath/fonts under original name
|
||||
*/
|
||||
module.exports = function copyAssetsAndroid(files, targetPath) {
|
||||
module.exports = function copyAssetsAndroid(files, project) {
|
||||
const assets = groupFilesByType(files);
|
||||
|
||||
(assets.font || []).forEach(asset =>
|
||||
fs.copySync(asset, path.join(targetPath, 'fonts', path.basename(asset)))
|
||||
fs.copySync(asset, path.join(project.assetsPath, 'fonts', path.basename(asset)))
|
||||
);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
module.exports = function() {
|
||||
return {
|
||||
isInstalled: require('./isInstalled'),
|
||||
register: require('./registerNativeModule'),
|
||||
unregister: require('./unregisterNativeModule'),
|
||||
copyAssets: require('./copyAssets'),
|
||||
unlinkAssets: require('./unlinkAssets')
|
||||
};
|
||||
};
|
||||
@@ -8,11 +8,11 @@ const groupFilesByType = require('../groupFilesByType');
|
||||
* For now, the only types of files that are handled are:
|
||||
* - Fonts (otf, ttf) - copied to targetPath/fonts under original name
|
||||
*/
|
||||
module.exports = function unlinkAssetsAndroid(files, targetPath) {
|
||||
module.exports = function unlinkAssetsAndroid(files, project) {
|
||||
const assets = groupFilesByType(files);
|
||||
|
||||
(assets.font || []).forEach((file) => {
|
||||
const filePath = path.join(targetPath, 'fonts', path.basename(file));
|
||||
const filePath = path.join(project.assetsPath, 'fonts', path.basename(file));
|
||||
if (fs.existsSync(filePath)) {
|
||||
fs.unlinkSync(filePath);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
const isInstalledIOS = require('../isInstalled');
|
||||
const isInstalledPods = require('../../pods/isInstalled');
|
||||
|
||||
module.exports = function isInstalled(config, name) {
|
||||
return isInstalledIOS(config, name) || isInstalledPods(config, name);
|
||||
};
|
||||
@@ -0,0 +1,16 @@
|
||||
const registerDependencyIOS = require('../registerNativeModule');
|
||||
const registerDependencyPods = require('../../pods/registerNativeModule');
|
||||
|
||||
module.exports = function registerNativeModule(
|
||||
name,
|
||||
dependencyConfig,
|
||||
params,
|
||||
projectConfig
|
||||
) {
|
||||
if (projectConfig.podfile && dependencyConfig.podspec) {
|
||||
registerDependencyPods(name, dependencyConfig, projectConfig);
|
||||
}
|
||||
else {
|
||||
registerDependencyIOS(dependencyConfig, projectConfig);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,22 @@
|
||||
const compact = require('lodash').compact;
|
||||
const isInstalledIOS = require('../isInstalled');
|
||||
const isInstalledPods = require('../../pods/isInstalled');
|
||||
const unregisterDependencyIOS = require('../registerNativeModule');
|
||||
const unregisterDependencyPods = require('../../pods/registerNativeModule');
|
||||
|
||||
module.exports = function unregisterNativeModule(
|
||||
name,
|
||||
dependencyConfig,
|
||||
projectConfig,
|
||||
otherDependencies
|
||||
) {
|
||||
const isIosInstalled = isInstalledIOS(projectConfig, dependencyConfig);
|
||||
const isPodInstalled = isInstalledPods(projectConfig, dependencyConfig);
|
||||
if (isIosInstalled) {
|
||||
const iOSDependencies = compact(otherDependencies.map(d => d.config.ios));
|
||||
unregisterDependencyIOS(dependencyConfig, projectConfig, iOSDependencies);
|
||||
}
|
||||
else if (isPodInstalled) {
|
||||
unregisterDependencyPods(dependencyConfig, projectConfig);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,9 @@
|
||||
module.exports = function() {
|
||||
return {
|
||||
isInstalled: require('./common/isInstalled'),
|
||||
register: require('./common/registerNativeModule'),
|
||||
unregister: require('./common/unregisterNativeModule'),
|
||||
copyAssets: require('./copyAssets'),
|
||||
unlinkAssets: require('./unlinkAssets')
|
||||
};
|
||||
};
|
||||
+44
-93
@@ -26,16 +26,6 @@ const chalk = require('chalk');
|
||||
* run Flow. */
|
||||
const isEmpty = require('lodash').isEmpty;
|
||||
const promiseWaterfall = require('./promiseWaterfall');
|
||||
const registerDependencyAndroid = require('./android/registerNativeModule');
|
||||
const registerDependencyWindows = require('./windows/registerNativeModule');
|
||||
const registerDependencyIOS = require('./ios/registerNativeModule');
|
||||
const registerDependencyPods = require('./pods/registerNativeModule');
|
||||
const isInstalledAndroid = require('./android/isInstalled');
|
||||
const isInstalledWindows = require('./windows/isInstalled');
|
||||
const isInstalledIOS = require('./ios/isInstalled');
|
||||
const isInstalledPods = require('./pods/isInstalled');
|
||||
const copyAssetsAndroid = require('./android/copyAssets');
|
||||
const copyAssetsIOS = require('./ios/copyAssets');
|
||||
const getProjectDependencies = require('./getProjectDependencies');
|
||||
const getDependencyConfig = require('./getDependencyConfig');
|
||||
const pollParams = require('./pollParams');
|
||||
@@ -49,95 +39,55 @@ log.heading = 'rnpm-link';
|
||||
|
||||
const dedupeAssets = (assets) => uniqBy(assets, asset => path.basename(asset));
|
||||
|
||||
const linkDependency = (platforms, project, dependency) => {
|
||||
Object.keys(platforms || {})
|
||||
.forEach(platform => {
|
||||
if (!project[platform] || !dependency.config[platform]) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const linkDependencyAndroid = (androidProject, dependency) => {
|
||||
if (!androidProject || !dependency.config.android) {
|
||||
return null;
|
||||
}
|
||||
const linkConfig = platforms[platform] && platforms[platform].linkConfig && platforms[platform].linkConfig();
|
||||
if (!linkConfig || !linkConfig.isInstalled || !linkConfig.register) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const isInstalled = isInstalledAndroid(androidProject, dependency.name);
|
||||
const isInstalled = linkConfig.isInstalled(project[platform], dependency.config[platform]);
|
||||
|
||||
if (isInstalled) {
|
||||
log.info(chalk.grey(`Android module ${dependency.name} is already linked`));
|
||||
return null;
|
||||
}
|
||||
if (isInstalled) {
|
||||
log.info(chalk.grey(`Platform '${platform}' module ${dependency.name} is already linked`));
|
||||
return null;
|
||||
}
|
||||
|
||||
return pollParams(dependency.config.params).then(params => {
|
||||
log.info(`Linking ${dependency.name} android dependency`);
|
||||
return pollParams(dependency.config.params).then(params => {
|
||||
log.info(`Linking ${dependency.name} ${platform} dependency`);
|
||||
|
||||
registerDependencyAndroid(
|
||||
dependency.name,
|
||||
dependency.config.android,
|
||||
params,
|
||||
androidProject
|
||||
);
|
||||
linkConfig.register(
|
||||
dependency.name,
|
||||
dependency.config[platform],
|
||||
params,
|
||||
project[platform]
|
||||
);
|
||||
|
||||
log.info(`Android module ${dependency.name} has been successfully linked`);
|
||||
});
|
||||
log.info(`Platform '${platform}' module ${dependency.name} has been successfully linked`);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const linkDependencyWindows = (windowsProject, dependency) => {
|
||||
|
||||
if (!windowsProject || !dependency.config.windows) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const isInstalled = isInstalledWindows(windowsProject, dependency.config.windows);
|
||||
|
||||
if (isInstalled) {
|
||||
log.info(chalk.grey(`Windows module ${dependency.name} is already linked`));
|
||||
return null;
|
||||
}
|
||||
|
||||
return pollParams(dependency.config.params).then(params => {
|
||||
log.info(`Linking ${dependency.name} windows dependency`);
|
||||
|
||||
registerDependencyWindows(
|
||||
dependency.name,
|
||||
dependency.config.windows,
|
||||
params,
|
||||
windowsProject
|
||||
);
|
||||
|
||||
log.info(`Windows module ${dependency.name} has been successfully linked`);
|
||||
});
|
||||
};
|
||||
|
||||
const linkDependencyIOS = (iOSProject, dependency) => {
|
||||
if (!iOSProject || !dependency.config.ios) {
|
||||
return;
|
||||
}
|
||||
|
||||
const isInstalled = isInstalledIOS(iOSProject, dependency.config.ios) || isInstalledPods(iOSProject, dependency.config.ios);
|
||||
if (isInstalled) {
|
||||
log.info(chalk.grey(`iOS module ${dependency.name} is already linked`));
|
||||
return;
|
||||
}
|
||||
|
||||
log.info(`Linking ${dependency.name} ios dependency`);
|
||||
if (iOSProject.podfile && dependency.config.ios.podspec) {
|
||||
registerDependencyPods(dependency, iOSProject);
|
||||
}
|
||||
else {
|
||||
registerDependencyIOS(dependency.config.ios, iOSProject);
|
||||
}
|
||||
log.info(`iOS module ${dependency.name} has been successfully linked`);
|
||||
};
|
||||
|
||||
const linkAssets = (project, assets) => {
|
||||
const linkAssets = (platforms, project, assets) => {
|
||||
if (isEmpty(assets)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (project.ios) {
|
||||
log.info('Linking assets to ios project');
|
||||
copyAssetsIOS(assets, project.ios);
|
||||
}
|
||||
Object.keys(platforms || {})
|
||||
.forEach(platform => {
|
||||
const linkConfig = platforms[platform] && platforms[platform].linkConfig && platforms[platform].linkConfig();
|
||||
if (!linkConfig || !linkConfig.copyAssets) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (project.android) {
|
||||
log.info('Linking assets to android project');
|
||||
copyAssetsAndroid(assets, project.android.assetsPath);
|
||||
}
|
||||
log.info(`Linking assets to ${platform} project`);
|
||||
linkConfig.copyAssets(assets, project[platform]);
|
||||
});
|
||||
|
||||
log.info('Assets have been successfully linked to your project');
|
||||
};
|
||||
@@ -150,9 +100,11 @@ const linkAssets = (project, assets) => {
|
||||
* @param config CLI config, see local-cli/core/index.js
|
||||
*/
|
||||
function link(args: Array<string>, config: RNConfig) {
|
||||
var project;
|
||||
let project;
|
||||
let platforms;
|
||||
try {
|
||||
project = config.getProjectConfig();
|
||||
platforms = config.getPlatformConfig();
|
||||
} catch (err) {
|
||||
log.error(
|
||||
'ERRPACKAGEJSON',
|
||||
@@ -161,7 +113,8 @@ function link(args: Array<string>, config: RNConfig) {
|
||||
return Promise.reject(err);
|
||||
}
|
||||
|
||||
if (!project.android && !project.ios && !project.windows && findReactNativeScripts()) {
|
||||
const hasProjectConfig = Object.keys(platforms).reduce((acc, key) => acc || key in project, false);
|
||||
if (!hasProjectConfig && findReactNativeScripts()) {
|
||||
throw new Error(
|
||||
'`react-native link` can not be used in Create React Native App projects. ' +
|
||||
'If you need to include a library that relies on custom native code, ' +
|
||||
@@ -183,19 +136,17 @@ function link(args: Array<string>, config: RNConfig) {
|
||||
);
|
||||
|
||||
const assets = dedupeAssets(dependencies.reduce(
|
||||
(assets, dependency) => assets.concat(dependency.config.assets),
|
||||
(acc, dependency) => acc.concat(dependency.config.assets),
|
||||
project.assets
|
||||
));
|
||||
|
||||
const tasks = flatten(dependencies.map(dependency => [
|
||||
() => promisify(dependency.config.commands.prelink || commandStub),
|
||||
() => linkDependencyAndroid(project.android, dependency),
|
||||
() => linkDependencyIOS(project.ios, dependency),
|
||||
() => linkDependencyWindows(project.windows, dependency),
|
||||
() => linkDependency(platforms, project, dependency),
|
||||
() => promisify(dependency.config.commands.postlink || commandStub),
|
||||
]));
|
||||
|
||||
tasks.push(() => linkAssets(project, assets));
|
||||
tasks.push(() => linkAssets(platforms, project, assets));
|
||||
|
||||
return promiseWaterfall(tasks).catch(err => {
|
||||
log.error(
|
||||
|
||||
@@ -7,10 +7,10 @@ const findMarkedLinesInPodfile = require('./findMarkedLinesInPodfile');
|
||||
const addPodEntry = require('./addPodEntry');
|
||||
const savePodFile = require('./savePodFile');
|
||||
|
||||
module.exports = function registerNativeModulePods(dependency, iOSProject) {
|
||||
module.exports = function registerNativeModulePods(name, dependencyConfig, iOSProject) {
|
||||
const podLines = readPodfile(iOSProject.podfile);
|
||||
const linesToAddEntry = getLinesToAddEntry(podLines, iOSProject);
|
||||
addPodEntry(podLines, linesToAddEntry, dependency.config.ios.podspec, dependency.name);
|
||||
addPodEntry(podLines, linesToAddEntry, dependencyConfig.podspec, name);
|
||||
savePodFile(iOSProject.podfile, podLines);
|
||||
};
|
||||
|
||||
|
||||
+39
-79
@@ -1,18 +1,7 @@
|
||||
const log = require('npmlog');
|
||||
|
||||
const getProjectDependencies = require('./getProjectDependencies');
|
||||
const unregisterDependencyAndroid = require('./android/unregisterNativeModule');
|
||||
const unregisterDependencyWindows = require('./windows/unregisterNativeModule');
|
||||
const unregisterDependencyIOS = require('./ios/unregisterNativeModule');
|
||||
const unregisterDependencyPods = require('./pods/unregisterNativeModule');
|
||||
const isInstalledAndroid = require('./android/isInstalled');
|
||||
const isInstalledWindows = require('./windows/isInstalled');
|
||||
const isInstalledIOS = require('./ios/isInstalled');
|
||||
const isInstalledPods = require('./pods/isInstalled');
|
||||
const unlinkAssetsAndroid = require('./android/unlinkAssets');
|
||||
const unlinkAssetsIOS = require('./ios/unlinkAssets');
|
||||
const getDependencyConfig = require('./getDependencyConfig');
|
||||
const compact = require('lodash').compact;
|
||||
const difference = require('lodash').difference;
|
||||
const filter = require('lodash').filter;
|
||||
const flatten = require('lodash').flatten;
|
||||
@@ -23,66 +12,37 @@ const promisify = require('./promisify');
|
||||
|
||||
log.heading = 'rnpm-link';
|
||||
|
||||
const unlinkDependencyAndroid = (androidProject, dependency, packageName) => {
|
||||
if (!androidProject || !dependency.android) {
|
||||
return;
|
||||
}
|
||||
const unlinkDependency = (platforms, project, dependency, packageName, otherDependencies) => {
|
||||
|
||||
const isInstalled = isInstalledAndroid(androidProject, packageName);
|
||||
Object.keys(platforms || {})
|
||||
.forEach(platform => {
|
||||
if (!project[platform] || !dependency[platform]) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isInstalled) {
|
||||
log.info(`Android module ${packageName} is not installed`);
|
||||
return;
|
||||
}
|
||||
const linkConfig = platforms[platform] && platforms[platform].linkConfig && platforms[platform].linkConfig();
|
||||
if (!linkConfig || !linkConfig.isInstalled || !linkConfig.unregister) {
|
||||
return;
|
||||
}
|
||||
|
||||
log.info(`Unlinking ${packageName} android dependency`);
|
||||
const isInstalled = linkConfig.isInstalled(project[platform], dependency[platform]);
|
||||
|
||||
unregisterDependencyAndroid(packageName, dependency.android, androidProject);
|
||||
if (!isInstalled) {
|
||||
log.info(`Platform '${platform}' module ${packageName} is not installed`);
|
||||
return;
|
||||
}
|
||||
|
||||
log.info(`Android module ${packageName} has been successfully unlinked`);
|
||||
};
|
||||
log.info(`Unlinking ${packageName} ${platform} dependency`);
|
||||
|
||||
const unlinkDependencyWindows = (windowsProject, dependency, packageName) => {
|
||||
if (!windowsProject || !dependency.windows) {
|
||||
return;
|
||||
}
|
||||
linkConfig.unregister(
|
||||
packageName,
|
||||
dependency[platform],
|
||||
project[platform],
|
||||
otherDependencies
|
||||
);
|
||||
|
||||
const isInstalled = isInstalledWindows(windowsProject, dependency.windows);
|
||||
|
||||
if (!isInstalled) {
|
||||
log.info(`Windows module ${packageName} is not installed`);
|
||||
return;
|
||||
}
|
||||
|
||||
log.info(`Unlinking ${packageName} windows dependency`);
|
||||
|
||||
unregisterDependencyWindows(packageName, dependency.windows, windowsProject);
|
||||
|
||||
log.info(`Windows module ${packageName} has been successfully unlinked`);
|
||||
};
|
||||
|
||||
const unlinkDependencyIOS = (iOSProject, dependency, packageName, iOSDependencies) => {
|
||||
if (!iOSProject || !dependency.ios) {
|
||||
return;
|
||||
}
|
||||
|
||||
const isIosInstalled = isInstalledIOS(iOSProject, dependency.ios);
|
||||
const isPodInstalled = isInstalledPods(iOSProject, dependency.ios);
|
||||
if (!isIosInstalled && !isPodInstalled) {
|
||||
log.info(`iOS module ${packageName} is not installed`);
|
||||
return;
|
||||
}
|
||||
|
||||
log.info(`Unlinking ${packageName} ios dependency`);
|
||||
|
||||
if (isIosInstalled) {
|
||||
unregisterDependencyIOS(dependency.ios, iOSProject, iOSDependencies);
|
||||
}
|
||||
else if (isPodInstalled) {
|
||||
unregisterDependencyPods(dependency.ios, iOSProject);
|
||||
}
|
||||
|
||||
log.info(`iOS module ${packageName} has been successfully unlinked`);
|
||||
log.info(`Platform '${platform}' module ${dependency.name} has been successfully unlinked`);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -94,10 +54,12 @@ const unlinkDependencyIOS = (iOSProject, dependency, packageName, iOSDependencie
|
||||
function unlink(args, config) {
|
||||
const packageName = args[0];
|
||||
|
||||
var project;
|
||||
var dependency;
|
||||
let platforms;
|
||||
let project;
|
||||
let dependency;
|
||||
|
||||
try {
|
||||
platforms = config.getPlatformConfig();
|
||||
project = config.getProjectConfig();
|
||||
} catch (err) {
|
||||
log.error(
|
||||
@@ -119,13 +81,10 @@ function unlink(args, config) {
|
||||
|
||||
const allDependencies = getDependencyConfig(config, getProjectDependencies());
|
||||
const otherDependencies = filter(allDependencies, d => d.name !== packageName);
|
||||
const iOSDependencies = compact(otherDependencies.map(d => d.config.ios));
|
||||
|
||||
const tasks = [
|
||||
() => promisify(dependency.commands.preunlink || commandStub),
|
||||
() => unlinkDependencyAndroid(project.android, dependency, packageName),
|
||||
() => unlinkDependencyIOS(project.ios, dependency, packageName, iOSDependencies),
|
||||
() => unlinkDependencyWindows(project.windows, dependency, packageName),
|
||||
() => unlinkDependency(platforms, project, dependency, packageName, otherDependencies),
|
||||
() => promisify(dependency.commands.postunlink || commandStub)
|
||||
];
|
||||
|
||||
@@ -142,15 +101,16 @@ function unlink(args, config) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
if (project.ios) {
|
||||
log.info('Unlinking assets from ios project');
|
||||
unlinkAssetsIOS(assets, project.ios);
|
||||
}
|
||||
|
||||
if (project.android) {
|
||||
log.info('Unlinking assets from android project');
|
||||
unlinkAssetsAndroid(assets, project.android.assetsPath);
|
||||
}
|
||||
Object.keys(platforms || {})
|
||||
.forEach(platform => {
|
||||
const linkConfig = platforms[platform] && platforms[platform].linkConfig && platforms[platform].linkConfig();
|
||||
if (!linkConfig || !linkConfig.unlinkAssets) {
|
||||
return;
|
||||
}
|
||||
|
||||
log.info(`Unlinking assets from ${platform} project`);
|
||||
linkConfig.unlinkAssets(assets, project[platform]);
|
||||
});
|
||||
|
||||
log.info(
|
||||
`${packageName} assets has been successfully unlinked from your project`
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
const fs = require('fs');
|
||||
const makeUsingPatch = require('./patches/makeUsingPatch');
|
||||
|
||||
module.exports = function isInstalled(config, dependencyConfig) {
|
||||
return fs
|
||||
.readFileSync(config.mainPage)
|
||||
.indexOf(makeUsingPatch(dependencyConfig.packageUsingPath).patch) > -1;
|
||||
};
|
||||
@@ -1,23 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2013-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
const toCamelCase = require('lodash').camelCase;
|
||||
|
||||
module.exports = function applyParams(str, params, prefix) {
|
||||
return str.replace(
|
||||
/\$\{(\w+)\}/g,
|
||||
(pattern, param) => {
|
||||
const name = toCamelCase(prefix) + '_' + param;
|
||||
|
||||
return params[param]
|
||||
? `getResources().getString(R.string.${name})`
|
||||
: null;
|
||||
}
|
||||
);
|
||||
};
|
||||
@@ -1,11 +0,0 @@
|
||||
const fs = require('fs');
|
||||
|
||||
module.exports = function applyPatch(file, patch, flip = false) {
|
||||
|
||||
fs.writeFileSync(file, fs
|
||||
.readFileSync(file, 'utf8')
|
||||
.replace(patch.pattern, match => {
|
||||
return flip ? `${patch.patch}${match}` : `${match}${patch.patch}`;
|
||||
})
|
||||
);
|
||||
};
|
||||
@@ -1,10 +0,0 @@
|
||||
const applyParams = require('./applyParams');
|
||||
|
||||
module.exports = function makePackagePatch(packageInstance, params, prefix) {
|
||||
const processedInstance = applyParams(packageInstance, params, prefix);
|
||||
|
||||
return {
|
||||
pattern: 'new MainReactPackage()',
|
||||
patch: ',\n ' + processedInstance,
|
||||
};
|
||||
};
|
||||
@@ -1,14 +0,0 @@
|
||||
module.exports = function makeProjectPatch(windowsConfig) {
|
||||
|
||||
const projectInsert = `<ProjectReference Include="..\\${windowsConfig.relativeProjPath}">
|
||||
<Project>{${windowsConfig.pathGUID}}</Project>
|
||||
<Name>${windowsConfig.projectName}</Name>
|
||||
</ProjectReference>
|
||||
`;
|
||||
|
||||
return {
|
||||
pattern: '<ProjectReference Include="..\\..\\node_modules\\react-native-windows\\ReactWindows\\ReactNative\\ReactNative.csproj">',
|
||||
patch: projectInsert,
|
||||
unpatch: new RegExp(`<ProjectReference.+\\s+.+\\s+.+${windowsConfig.projectName}.+\\s+.+\\s`),
|
||||
};
|
||||
};
|
||||
@@ -1,12 +0,0 @@
|
||||
module.exports = function makeSolutionPatch(windowsConfig) {
|
||||
|
||||
const solutionInsert = `Project("{${windowsConfig.projectGUID.toUpperCase()}}") = "${windowsConfig.projectName}", "${windowsConfig.relativeProjPath}", "{${windowsConfig.pathGUID.toUpperCase()}}"
|
||||
EndProject
|
||||
`;
|
||||
|
||||
return {
|
||||
pattern: 'Global',
|
||||
patch: solutionInsert,
|
||||
unpatch: new RegExp(`Project.+${windowsConfig.projectName}.+\\s+EndProject\\s+`),
|
||||
};
|
||||
};
|
||||
@@ -1,6 +0,0 @@
|
||||
module.exports = function makeUsingPatch(packageImportPath) {
|
||||
return {
|
||||
pattern: 'using ReactNative.Modules.Core;',
|
||||
patch: '\n' + packageImportPath,
|
||||
};
|
||||
};
|
||||
@@ -1,9 +0,0 @@
|
||||
const fs = require('fs');
|
||||
|
||||
module.exports = function revokePatch(file, patch) {
|
||||
const unpatch = patch.unpatch || patch.patch;
|
||||
fs.writeFileSync(file, fs
|
||||
.readFileSync(file, 'utf8')
|
||||
.replace(unpatch, '')
|
||||
);
|
||||
};
|
||||
@@ -1,26 +0,0 @@
|
||||
const applyPatch = require('./patches/applyPatch');
|
||||
|
||||
const makeProjectPatch = require('./patches/makeProjectPatch');
|
||||
const makeSolutionPatch = require('./patches/makeSolutionPatch');
|
||||
const makeUsingPatch = require('./patches/makeUsingPatch');
|
||||
const makePackagePatch = require('./patches/makePackagePatch');
|
||||
|
||||
module.exports = function registerNativeWindowsModule(
|
||||
name,
|
||||
windowsConfig,
|
||||
params,
|
||||
projectConfig
|
||||
) {
|
||||
applyPatch(projectConfig.projectPath, makeProjectPatch(windowsConfig), true);
|
||||
applyPatch(projectConfig.solutionPath, makeSolutionPatch(windowsConfig), true);
|
||||
|
||||
applyPatch(
|
||||
projectConfig.mainPage,
|
||||
makePackagePatch(windowsConfig.packageInstance, params, name)
|
||||
);
|
||||
|
||||
applyPatch(
|
||||
projectConfig.mainPage,
|
||||
makeUsingPatch(windowsConfig.packageUsingPath)
|
||||
);
|
||||
};
|
||||
@@ -1,27 +0,0 @@
|
||||
const fs = require('fs');
|
||||
const toCamelCase = require('lodash').camelCase;
|
||||
|
||||
const revokePatch = require('./patches/revokePatch');
|
||||
const makeProjectPatch = require('./patches/makeProjectPatch');
|
||||
const makeSolutionPatch = require('./patches/makeSolutionPatch');
|
||||
const makeUsingPatch = require('./patches/makeUsingPatch');
|
||||
const makePackagePatch = require('./patches/makePackagePatch');
|
||||
|
||||
module.exports = function unregisterNativeWindowsModule(
|
||||
name,
|
||||
windowsConfig,
|
||||
projectConfig
|
||||
) {
|
||||
revokePatch(projectConfig.projectPath, makeProjectPatch(windowsConfig));
|
||||
revokePatch(projectConfig.solutionPath, makeSolutionPatch(windowsConfig));
|
||||
|
||||
revokePatch(
|
||||
projectConfig.mainPage,
|
||||
makePackagePatch(windowsConfig.packageInstance, {}, name)
|
||||
);
|
||||
|
||||
revokePatch(
|
||||
projectConfig.mainPage,
|
||||
makeUsingPatch(windowsConfig.packageUsingPath)
|
||||
);
|
||||
};
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "react-native",
|
||||
"version": "1000.0.0",
|
||||
"version": "0.51.1",
|
||||
"description": "A framework for building native apps using React",
|
||||
"license": "BSD-3-Clause",
|
||||
"repository": {
|
||||
@@ -207,4 +207,4 @@
|
||||
"shelljs": "^0.7.8",
|
||||
"sinon": "^2.2.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user