From efddf1d40acf6752fad0b201331b16621f9859aa Mon Sep 17 00:00:00 2001 From: samsafay Date: Tue, 2 Jan 2018 23:09:48 -0500 Subject: [PATCH 1/4] Setting ANDROID_LONG_TIMER_MESSAGE to '(ADVICE)' This commit is based on a suggestion made by a Firebase member https://github.com/facebook/react-native/issues/17083. Longer timers are used in critical parts of Firebase-SDK such as refreshing the token; Its a bad user experience if the token expires and users need to keep login to the application! We appreciate your cooperation. --- Libraries/Core/Timers/JSTimers.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Libraries/Core/Timers/JSTimers.js b/Libraries/Core/Timers/JSTimers.js index 45129f1b91ac70..4f5a5be313cd06 100644 --- a/Libraries/Core/Timers/JSTimers.js +++ b/Libraries/Core/Timers/JSTimers.js @@ -51,11 +51,7 @@ const IDLE_CALLBACK_FRAME_DEADLINE = 1; const MAX_TIMER_DURATION_MS = 60 * 1000; const IS_ANDROID = Platform.OS === 'android'; -const ANDROID_LONG_TIMER_MESSAGE = - 'Setting a timer for a long period of time, i.e. multiple minutes, is a ' + - 'performance and correctness issue on Android as it keeps the timer ' + - 'module awake, and timers can only be called when the app is in the foreground. ' + - 'See https://github.com/facebook/react-native/issues/12981 for more info.'; +const ANDROID_LONG_TIMER_MESSAGE = '(ADVICE)'; // Parallel arrays const callbacks: Array = []; From a55fe37feabb9ba4e095dbe44fd6181d368b54ee Mon Sep 17 00:00:00 2001 From: samsafay Date: Tue, 2 Jan 2018 23:45:24 -0500 Subject: [PATCH 2/4] Checking For the GET or HEAD in send method The following change is suggested by a Firebase member here. https://github.com/firebase/firebase-js-sdk/issues/283 It follows the whatwg.org's send method guidelines. https://xhr.spec.whatwg.org/#dom-xmlhttprequest-send At the section 3 of 4.5.6, it is suggests to check for the GET or HEAD methods, for every XMLHttpRequest send() method, then set the body to null if it is true. --- .../com/facebook/react/modules/network/NetworkingModule.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java index 297cd1ef4ff2fc..2c3086fa3b61fa 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java @@ -235,7 +235,7 @@ public void onProgress(long bytesWritten, long contentLength, boolean done) { String contentEncoding = requestHeaders.get(CONTENT_ENCODING_HEADER_NAME); requestBuilder.headers(requestHeaders); - if (data == null) { + if (data == null || method.toLowerCase() === 'get' || method.toLowerCase() === 'head') { requestBuilder.method(method, RequestBodyUtil.getEmptyBody(method)); } else if (data.hasKey(REQUEST_BODY_KEY_STRING)) { if (contentType == null) { From c463c729fe24ec542141f825c173226e90b125e8 Mon Sep 17 00:00:00 2001 From: samsafay Date: Wed, 3 Jan 2018 20:08:41 -0500 Subject: [PATCH 3/4] Update NetworkingModule.java --- .../com/facebook/react/modules/network/NetworkingModule.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java index 2c3086fa3b61fa..f50331c52e1c5d 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java @@ -235,7 +235,7 @@ public void onProgress(long bytesWritten, long contentLength, boolean done) { String contentEncoding = requestHeaders.get(CONTENT_ENCODING_HEADER_NAME); requestBuilder.headers(requestHeaders); - if (data == null || method.toLowerCase() === 'get' || method.toLowerCase() === 'head') { + if (data == null || method.toLowerCase().equals("get") || method.toLowerCase().equals("head")) { requestBuilder.method(method, RequestBodyUtil.getEmptyBody(method)); } else if (data.hasKey(REQUEST_BODY_KEY_STRING)) { if (contentType == null) { From 833c0cebd5cf730e94866828802e47f39f566ea7 Mon Sep 17 00:00:00 2001 From: samsafay Date: Sat, 10 Feb 2018 23:47:47 -0500 Subject: [PATCH 4/4] rebase the fork --- .circleci/README.md | 5 + .circleci/config.yml | 542 +- .eslintrc | 49 +- .flowconfig | 6 +- .gitignore | 9 +- CONTRIBUTING.md | 4 +- .../run-android-ci-instrumentation-tests.js | 1 - .../ReactContentSizeUpdateTest.js | 2 +- IntegrationTests/SizeFlexibilityUpdateTest.js | 2 +- .../Animated/src/__tests__/Animated-test.js | 6 +- .../src/__tests__/AnimatedNative-test.js | 110 +- .../Animated/src/__tests__/bezier-test.js | 116 +- .../Animated/src/createAnimatedComponent.js | 6 +- .../src/nodes/AnimatedInterpolation.js | 2 +- .../Animated/src/nodes/AnimatedValueXY.js | 4 +- Libraries/BatchedBridge/BatchedBridge.js | 2 +- .../__tests__/MessageQueue-test.js | 6 +- .../__tests__/NativeModules-test.js | 12 +- Libraries/Blob/Blob.js | 94 +- Libraries/Blob/BlobManager.js | 146 + Libraries/Blob/BlobRegistry.js | 41 + Libraries/Blob/BlobTypes.js | 9 +- Libraries/Blob/File.js | 58 + Libraries/Blob/FileReader.js | 156 + .../Blob/RCTBlob.xcodeproj/project.pbxproj | 32 +- Libraries/Blob/RCTBlobManager.h | 14 + Libraries/Blob/RCTBlobManager.m | 218 - Libraries/Blob/RCTBlobManager.mm | 291 + .../RCTFileReaderModule.h} | 4 +- Libraries/Blob/RCTFileReaderModule.m | 71 + Libraries/Blob/URL.js | 8 +- Libraries/Blob/__mocks__/BlobModule.js | 17 + Libraries/Blob/__mocks__/FileReaderModule.js | 21 + Libraries/Blob/__tests__/Blob-test.js | 84 + Libraries/Blob/__tests__/BlobManager-test.js | 27 + Libraries/Blob/__tests__/File-test.js | 46 + Libraries/Blob/__tests__/FileReader-test.js | 42 + Libraries/CameraRoll/CameraRoll.js | 102 +- Libraries/CameraRoll/RCTCameraRollManager.m | 2 +- .../Keyboard/KeyboardAvoidingView.js | 18 +- Libraries/Components/LazyRenderer.js | 2 +- .../Components/Navigation/NavigatorIOS.ios.js | 4 +- .../Picker/PickerAndroid.android.js | 2 +- Libraries/Components/Picker/PickerIOS.ios.js | 2 +- Libraries/Components/ScrollResponder.js | 78 +- Libraries/Components/ScrollView/ScrollView.js | 108 +- .../ScrollView/ScrollViewStickyHeader.js | 113 +- Libraries/Components/StatusBar/StatusBar.js | 2 +- Libraries/Components/Subscribable.js | 2 +- .../Components/TabBarIOS/TabBarItemIOS.ios.js | 4 +- Libraries/Components/TextInput/TextInput.js | 180 +- .../Touchable/TouchableHighlight.js | 2 +- .../TouchableNativeFeedback.android.js | 2 +- .../Components/Touchable/TouchableOpacity.js | 2 +- .../Touchable/TouchableWithoutFeedback.js | 2 +- Libraries/Components/View/View.js | 28 +- Libraries/Components/View/ViewContext.js | 23 + Libraries/Components/View/ViewPropTypes.js | 11 + .../Components/WebView/WebView.android.js | 2 +- Libraries/Components/WebView/WebView.ios.js | 2 +- Libraries/Core/InitializeCore.js | 6 +- Libraries/Core/Timers/JSTimers.js | 10 +- Libraries/Experimental/Incremental.js | 6 +- Libraries/Experimental/IncrementalGroup.js | 2 +- .../Experimental/IncrementalPresenter.js | 2 +- .../SwipeableRow/SwipeableFlatList.js | 2 +- .../SwipeableRow/SwipeableListView.js | 2 +- .../Experimental/SwipeableRow/SwipeableRow.js | 13 +- Libraries/Experimental/WindowedListView.js | 11 +- Libraries/Geolocation/Geolocation.js | 65 +- Libraries/Geolocation/RCTLocationObserver.m | 5 + Libraries/Image/AssetRegistry.js | 5 +- Libraries/Image/AssetSourceResolver.js | 41 +- Libraries/Image/Image.android.js | 170 +- Libraries/Image/Image.ios.js | 270 +- Libraries/Image/ImageEditor.js | 3 +- Libraries/Image/ImageResizeMode.js | 9 +- Libraries/Image/ImageSource.js | 1 + Libraries/Image/ImageSourcePropType.js | 1 + Libraries/Image/ImageStore.js | 7 +- Libraries/Image/ImageStylePropTypes.js | 3 +- Libraries/Image/nativeImageSource.js | 56 +- Libraries/Image/resolveAssetSource.js | 15 +- Libraries/Inspector/Inspector.js | 13 +- Libraries/Inspector/InspectorPanel.js | 8 +- Libraries/Interaction/InteractionManager.js | 3 + Libraries/Linking/Linking.js | 150 +- Libraries/Lists/FillRateHelper.js | 2 - Libraries/Lists/FlatList.js | 10 +- Libraries/Lists/ListView/ListView.js | 4 +- Libraries/Lists/MetroListView.js | 2 +- Libraries/Lists/SectionList.js | 2 +- Libraries/Lists/ViewabilityHelper.js | 3 + Libraries/Lists/VirtualizeUtils.js | 2 +- Libraries/Lists/VirtualizedList.js | 56 +- Libraries/Lists/VirtualizedSectionList.js | 7 +- .../__flowtests__/SectionList-flowtest.js | 3 + .../__snapshots__/FlatList-test.js.snap | 4 + .../__snapshots__/SectionList-test.js.snap | 5 + .../VirtualizedList-test.js.snap | 13 + Libraries/Modal/Modal.js | 113 +- .../Drivers/RCTFrameAnimation.m | 2 +- Libraries/Network/NetInfo.js | 171 +- Libraries/Network/RCTNetworking.h | 24 + Libraries/Network/RCTNetworking.ios.js | 4 +- Libraries/Network/RCTNetworking.mm | 85 +- Libraries/Network/XMLHttpRequest.js | 31 +- Libraries/Network/convertRequestBody.js | 11 +- Libraries/Network/fetch.js | 2 +- .../Performance/QuickPerformanceLogger.js | 96 +- Libraries/Performance/SamplingProfiler.js | 2 +- Libraries/Performance/Systrace.js | 5 +- .../PermissionsAndroid/PermissionsAndroid.js | 61 +- .../PushNotificationIOS.js | 202 +- Libraries/RCTTest/RCTTestRunner.m | 3 +- Libraries/ReactNative/FabricUIManager.js | 64 + .../ReactNative/ReactNativeFeatureFlags.js | 47 - Libraries/ReactNative/renderFabricSurface.js | 62 + .../ReactNative/requireNativeComponent.js | 20 +- Libraries/Renderer/REVISION | 2 +- Libraries/Renderer/ReactFabric-dev.js | 13712 ++++++++++++ Libraries/Renderer/ReactFabric-prod.js | 5773 ++++++ Libraries/Renderer/ReactNativeRenderer-dev.js | 17177 ++++++++-------- .../Renderer/ReactNativeRenderer-prod.js | 2573 +-- Libraries/Renderer/shims/ReactFabric.js | 23 + Libraries/Renderer/shims/ReactFeatureFlags.js | 4 +- Libraries/Renderer/shims/ReactTypes.js | 75 +- Libraries/StyleSheet/EdgeInsetsPropType.js | 12 +- Libraries/StyleSheet/LayoutPropTypes.js | 3 +- Libraries/StyleSheet/StyleSheetTypes.js | 47 +- Libraries/StyleSheet/flattenStyle.js | 3 + .../RCTSurfaceHostingComponent.mm | 6 + .../Text/BaseText/RCTBaseTextShadowView.h | 26 + .../Text/BaseText/RCTBaseTextShadowView.m | 125 + .../RCTBaseTextViewManager.h} | 11 +- .../Text/BaseText/RCTBaseTextViewManager.m | 57 + Libraries/Text/RCTConvert+Text.h | 8 +- Libraries/Text/RCTFontAttributes.h | 31 - Libraries/Text/RCTFontAttributes.m | 112 - .../Text/RCTText.xcodeproj/project.pbxproj | 566 +- Libraries/Text/RCTTextAttributes.h | 85 + Libraries/Text/RCTTextAttributes.m | 270 + .../Text/{ => RawText}/RCTRawTextShadowView.h | 6 +- .../Text/{ => RawText}/RCTRawTextShadowView.m | 30 +- .../{ => RawText}/RCTRawTextViewManager.h | 4 + .../{ => RawText}/RCTRawTextViewManager.m | 5 + Libraries/Text/Text.js | 383 +- .../Text/Text/NSTextStorage+FontScaling.h | 22 + .../Text/Text/NSTextStorage+FontScaling.m | 139 + Libraries/Text/Text/RCTTextShadowView.h | 55 +- Libraries/Text/Text/RCTTextShadowView.m | 805 +- Libraries/Text/Text/RCTTextView.h | 11 +- Libraries/Text/Text/RCTTextView.m | 124 +- Libraries/Text/Text/RCTTextViewManager.h | 4 +- Libraries/Text/Text/RCTTextViewManager.m | 147 +- .../Multiline/RCTMultilineTextInputView.h | 24 +- .../Multiline/RCTMultilineTextInputView.m | 358 +- .../RCTMultilineTextInputViewManager.h | 8 +- .../RCTMultilineTextInputViewManager.m | 61 - .../Text/TextInput/Multiline/RCTUITextView.h | 10 +- .../Text/TextInput/Multiline/RCTUITextView.m | 6 +- .../TextInput/RCTBackedTextInputDelegate.h | 4 + .../RCTBackedTextInputDelegateAdapter.h | 8 +- .../RCTBackedTextInputDelegateAdapter.m | 78 +- .../RCTBackedTextInputViewProtocol.h | 14 +- .../TextInput/RCTBaseTextInputShadowView.h | 27 + .../TextInput/RCTBaseTextInputShadowView.m | 251 + .../Text/TextInput/RCTBaseTextInputView.h | 44 +- .../Text/TextInput/RCTBaseTextInputView.m | 310 +- .../RCTBaseTextInputViewManager.h} | 4 +- .../TextInput/RCTBaseTextInputViewManager.m | 120 + .../Singleline/RCTSinglelineTextInputView.h | 12 +- .../Singleline/RCTSinglelineTextInputView.m | 113 +- .../RCTSinglelineTextInputViewManager.h | 8 +- .../RCTSinglelineTextInputViewManager.m | 64 +- Libraries/Text/TextProps.js | 55 + .../RCTVirtualTextShadowView.h} | 4 +- .../VirtualText/RCTVirtualTextShadowView.m | 75 + .../VirtualText/RCTVirtualTextViewManager.h | 14 + .../VirtualText/RCTVirtualTextViewManager.m | 28 + Libraries/Types/CoreEventTypes.js | 46 +- Libraries/Utilities/Dimensions.js | 24 +- Libraries/Utilities/HMRClient.js | 127 +- Libraries/Utilities/JSDevSupportModule.js | 28 + Libraries/Utilities/__tests__/utf8-test.js | 63 - Libraries/Utilities/asyncRequire.js | 121 - Libraries/Utilities/infoLog.js | 2 +- Libraries/Utilities/utf8.js | 91 - Libraries/Vibration/Vibration.js | 52 +- .../RCTWebSocket.xcodeproj/project.pbxproj | 6 + Libraries/WebSocket/RCTWebSocketExecutor.m | 2 +- Libraries/WebSocket/RCTWebSocketModule.h | 5 +- Libraries/WebSocket/RCTWebSocketModule.m | 7 +- Libraries/WebSocket/WebSocket.js | 29 +- Libraries/Wrapper/RCTWrapperShadowView.m | 9 +- Libraries/Wrapper/RCTWrapperView.m | 4 +- Libraries/polyfills/Array.es6.js | 2 +- Libraries/polyfills/Array.prototype.es6.js | 2 +- Libraries/polyfills/Number.es6.js | 3 - Libraries/polyfills/Object.es6.js | 2 - Libraries/polyfills/String.prototype.es6.js | 2 +- .../polyfills/__tests__/Object.es7-test.js | 2 - Libraries/polyfills/babelHelpers.js | 2 +- Libraries/polyfills/console.js | 4 +- Libraries/polyfills/error-guard.js | 2 - Libraries/vendor/core/Map.js | 2 +- .../selection/DocumentSelectionState.js | 2 +- Libraries/vendor/emitter/EventValidator.js | 6 +- README.md | 3 +- RNTester/RNTester.xcodeproj/project.pbxproj | 13 + .../RNTesterSnapshotTests.m | 1 - .../testARTExample_1-iOS10_tvOS.png | Bin 60322 -> 60243 bytes .../testLayoutExample_1-iOS10_tvOS.png | Bin 91552 -> 92422 bytes .../testScrollViewExample_1-iOS10_tvOS.png | Bin 98489 -> 168647 bytes .../testTabBarExample_1-iOS10@2x.png | Bin 79577 -> 79650 bytes .../testTabBarExample_1-iOS11@2x.png | Bin 79721 -> 79754 bytes .../testTabBarExample_1@2x.png | Bin 79888 -> 79887 bytes .../testTextExample_1-iOS10_tvOS.png | Bin 130214 -> 130268 bytes .../testViewExample_1-iOS10_tvOS.png | Bin 98347 -> 98312 bytes .../RNTesterLegacy.xcodeproj/project.pbxproj | 2117 -- .../xcschemes/RNTester-tvOS.xcscheme | 139 - .../xcshareddata/xcschemes/RNTester.xcscheme | 174 - .../RNTesterUnitTests/RCTAllocationTests.m | 6 +- .../RNTesterUnitTests/RCTBlobManagerTests.m | 104 + RNTester/RNTesterUnitTests/RCTBridgeTests.m | 292 - .../RNTesterUnitTests/RCTJSCExecutorTests.m | 45 - RNTester/android/app/BUCK | 10 +- RNTester/js/AccessibilityIOSExample.js | 3 + RNTester/js/ActivityIndicatorExample.js | 6 + RNTester/js/AnimatedGratuitousApp/AnExApp.js | 6 + RNTester/js/AnimatedGratuitousApp/AnExSet.js | 2 +- RNTester/js/AnimatedGratuitousApp/AnExTilt.js | 2 +- RNTester/js/CameraRollView.js | 2 +- RNTester/js/ImageExample.js | 30 +- RNTester/js/LayoutAnimationExample.js | 2 +- RNTester/js/ListViewExample.js | 2 +- RNTester/js/ListViewGridLayoutExample.js | 2 +- RNTester/js/ListViewPagingExample.js | 2 +- RNTester/js/NativeAnimationsExample.js | 6 + RNTester/js/PanResponderExample.js | 2 +- RNTester/js/PushNotificationIOSExample.js | 2 +- RNTester/js/RNTesterApp.android.js | 2 +- RNTester/js/RNTesterApp.ios.js | 2 +- RNTester/js/RNTesterSettingSwitchRow.js | 2 +- RNTester/js/ScrollViewExample.js | 333 +- RNTester/js/ScrollViewSimpleExample.js | 19 +- RNTester/js/SwipeableListViewExample.js | 2 +- RNTester/js/TextExample.ios.js | 21 + RNTester/js/TextInputExample.android.js | 11 +- RNTester/js/TextInputExample.ios.js | 108 + RNTester/js/WebViewExample.js | 2 +- RNTester/js/messagingtest.html | 4 +- React.podspec | 38 +- React/Base/RCTBatchedBridge.mm | 1103 - React/Base/RCTBridge+Private.h | 29 +- React/Base/RCTBridge.h | 4 +- React/Base/RCTBridge.m | 25 +- React/Base/RCTBridgeDelegate.h | 14 - React/Base/RCTBundleURLProvider.m | 2 +- React/Base/RCTConvert.m | 3 +- React/Base/RCTDefines.h | 17 + React/Base/RCTEventDispatcher.m | 2 +- React/Base/RCTModuleData.h | 6 - React/Base/RCTModuleData.mm | 40 - React/Base/RCTTouchHandler.m | 29 +- React/Base/RCTUtils.h | 2 +- React/Base/Surface/RCTSurface.h | 11 +- React/Base/Surface/RCTSurface.mm | 33 +- React/Base/Surface/RCTSurfaceRootShadowView.h | 3 - React/Base/Surface/RCTSurfaceRootShadowView.m | 58 +- .../RCTSurfaceHostingView.mm | 50 +- .../RCTSurfaceSizeMeasureMode.h | 12 + .../RCTSurfaceSizeMeasureMode.mm | 38 + React/CxxBridge/RCTCxxBridge.mm | 25 +- React/CxxBridge/RCTObjcExecutor.mm | 5 +- React/DevSupport/RCTDevMenu.m | 2 - .../DevSupport/RCTInspectorDevServerHelper.h | 3 +- .../DevSupport/RCTInspectorDevServerHelper.mm | 4 +- React/Executors/RCTJSCExecutor.h | 109 - React/Executors/RCTJSCExecutor.mm | 997 - .../Fabric/RCTFabricUIManager.h | 10 +- React/Fabric/RCTFabricUIManager.mm | 66 + .../RCTInspectorPackagerConnection.h | 10 +- .../RCTInspectorPackagerConnection.m | 21 + React/Modules/RCTAccessibilityManager.m | 3 +- React/Modules/RCTDevSettings.mm | 12 +- React/Modules/RCTDeviceInfo.m | 23 +- .../RCTRedBoxExtraDataViewController.m | 5 +- React/Modules/RCTUIManager.m | 65 +- React/React.xcodeproj/project.pbxproj | 60 +- React/ReactLegacy.xcodeproj/project.pbxproj | 3510 ---- React/UIUtils/RCTUIUtils.h | 37 + React/UIUtils/RCTUIUtils.m | 52 + React/Views/RCTComponentData.h | 2 - React/Views/RCTComponentData.m | 17 - React/Views/RCTFont.h | 10 + React/Views/RCTFont.mm | 51 +- React/Views/RCTModalHostView.m | 2 + React/Views/RCTNavigator.m | 2 +- React/Views/RCTRefreshControl.m | 2 +- React/Views/RCTShadowView+Layout.h | 34 + React/Views/RCTShadowView+Layout.m | 95 +- React/Views/RCTShadowView.h | 52 +- React/Views/RCTShadowView.m | 179 +- React/Views/RCTView.h | 2 +- React/Views/RCTViewManager.h | 14 - React/Views/RCTViewManager.m | 11 +- .../ScrollView/RCTScrollContentShadowView.m | 2 +- React/Views/ScrollView/RCTScrollView.h | 1 + React/Views/ScrollView/RCTScrollView.m | 95 +- React/Views/ScrollView/RCTScrollViewManager.m | 1 + ReactAndroid/DEFS | 113 - ReactAndroid/libs/BUCK | 2 - ReactAndroid/src/androidTest/assets/BUCK | 4 +- ReactAndroid/src/androidTest/buck-runner/BUCK | 6 +- .../java/com/facebook/react/testing/BUCK | 4 +- .../facebook/react/testing/idledetection/BUCK | 4 +- .../com/facebook/react/testing/network/BUCK | 4 +- .../java/com/facebook/react/tests/BUCK | 66 +- .../src/androidTest/js/JSResponderTestApp.js | 2 +- .../androidTest/js/PickerAndroidTestModule.js | 2 +- .../js/SubviewsClippingTestModule.js | 2 +- .../com/facebook/catalyst/appcompat/BUCK | 4 +- ReactAndroid/src/main/java/com/facebook/BUCK | 4 +- .../facebook/debug/debugoverlay/model/BUCK | 4 +- .../main/java/com/facebook/debug/holder/BUCK | 4 +- .../main/java/com/facebook/debug/tags/BUCK | 4 +- .../src/main/java/com/facebook/jni/BUCK | 4 +- .../src/main/java/com/facebook/perftest/BUCK | 4 +- .../com/facebook/proguard/annotations/BUCK | 4 +- .../src/main/java/com/facebook/react/BUCK | 4 +- .../com/facebook/react/DebugCorePackage.java | 13 +- .../com/facebook/react/ReactNativeHost.java | 9 +- .../com/facebook/react/ReactRootView.java | 33 +- .../java/com/facebook/react/animated/BUCK | 4 +- .../react/animated/ModulusAnimatedNode.java | 4 +- .../java/com/facebook/react/animation/BUCK | 4 +- .../main/java/com/facebook/react/bridge/BUCK | 4 +- .../react/bridge/FallbackJSBundleLoader.java | 2 +- .../facebook/react/bridge/ReactContext.java | 4 +- .../react/bridge/ReadableNativeArray.java | 139 +- .../react/bridge/ReadableNativeMap.java | 237 +- .../main/java/com/facebook/react/common/BUCK | 6 +- .../react/common/StandardCharsets.java | 38 + .../com/facebook/react/common/network/BUCK | 4 +- .../java/com/facebook/react/devsupport/BUCK | 7 +- .../react/devsupport/BundleDeltaClient.java | 121 + .../react/devsupport/BundleDownloader.java | 133 +- .../react/devsupport/DevServerHelper.java | 141 +- .../devsupport/DevSupportManagerImpl.java | 245 +- .../InspectorPackagerConnection.java | 33 +- .../react/devsupport/JSDevSupport.java | 70 + .../react/devsupport/RedBoxDialog.java | 14 +- .../react/devsupport/RedBoxHandler.java | 10 +- .../main/java/com/facebook/react/fabric/BUCK | 32 + .../react/fabric/FabricUIManagerModule.java | 114 + .../main/java/com/facebook/react/flat/BUCK | 4 +- .../facebook/react/flat/FlatViewGroup.java | 2 +- .../com/facebook/react/flat/RCTImageView.java | 2 +- .../facebook/react/flat/TextNodeRegion.java | 13 +- .../main/java/com/facebook/react/jstasks/BUCK | 22 +- .../facebook/react/module/annotations/BUCK | 4 +- .../java/com/facebook/react/module/model/BUCK | 4 +- .../com/facebook/react/module/processing/BUCK | 6 +- .../react/modules/accessibilityinfo/BUCK | 4 +- .../facebook/react/modules/appregistry/BUCK | 4 +- .../com/facebook/react/modules/appstate/BUCK | 4 +- .../java/com/facebook/react/modules/blob/BUCK | 6 +- .../react/modules/blob/BlobModule.java | 240 +- .../react/modules/blob/FileReaderModule.java | 91 + .../com/facebook/react/modules/camera/BUCK | 4 +- .../com/facebook/react/modules/clipboard/BUCK | 4 +- .../com/facebook/react/modules/common/BUCK | 4 +- .../java/com/facebook/react/modules/core/BUCK | 4 +- .../facebook/react/modules/datepicker/BUCK | 4 +- .../com/facebook/react/modules/debug/BUCK | 6 +- .../facebook/react/modules/deviceinfo/BUCK | 4 +- .../modules/deviceinfo/DeviceInfoModule.java | 30 +- .../com/facebook/react/modules/dialog/BUCK | 4 +- .../react/modules/dialog/DialogModule.java | 16 +- .../com/facebook/react/modules/fresco/BUCK | 4 +- .../react/modules/fresco/FrescoModule.java | 11 - .../facebook/react/modules/i18nmanager/BUCK | 4 +- .../com/facebook/react/modules/image/BUCK | 4 +- .../com/facebook/react/modules/intent/BUCK | 4 +- .../com/facebook/react/modules/location/BUCK | 4 +- .../com/facebook/react/modules/netinfo/BUCK | 4 +- .../network/.NetworkingModule.java.swp | Bin 0 -> 16384 bytes .../.NetworkingModule_BASE_5628.java.swp | Bin 0 -> 16384 bytes .../.NetworkingModule_LOCAL_5628.java.swp | Bin 0 -> 16384 bytes .../.NetworkingModule_REMOTE_5628.java.swp | Bin 0 -> 16384 bytes .../com/facebook/react/modules/network/BUCK | 4 +- .../modules/network/CountingOutputStream.java | 70 + .../modules/network/NetworkingModule.java | 221 +- .../network/NetworkingModule_BACKUP_5628.java | 716 + .../network/NetworkingModule_BASE_5628.java | 585 + .../network/NetworkingModule_LOCAL_5628.java | 585 + .../network/NetworkingModule_REMOTE_5628.java | 716 + .../modules/network/OkHttpClientFactory.java | 16 + .../modules/network/OkHttpClientProvider.java | 11 + .../modules/network/ProgressRequestBody.java | 67 +- .../network/ProgressiveStringDecoder.java | 91 + .../react/modules/network/ResponseUtil.java | 17 +- .../facebook/react/modules/permissions/BUCK | 4 +- .../com/facebook/react/modules/share/BUCK | 4 +- .../com/facebook/react/modules/statusbar/BUCK | 4 +- .../com/facebook/react/modules/storage/BUCK | 4 +- .../modules/systeminfo/AndroidInfoModule.java | 4 + .../facebook/react/modules/systeminfo/BUCK | 6 +- .../facebook/react/modules/timepicker/BUCK | 4 +- .../com/facebook/react/modules/toast/BUCK | 4 +- .../com/facebook/react/modules/vibration/BUCK | 4 +- .../com/facebook/react/modules/websocket/BUCK | 4 +- .../modules/websocket/WebSocketModule.java | 65 +- .../facebook/react/packagerconnection/BUCK | 4 +- .../java/com/facebook/react/processing/BUCK | 6 +- .../main/java/com/facebook/react/shell/BUCK | 4 +- .../react/shell/MainReactPackage.java | 9 + .../main/java/com/facebook/react/touch/BUCK | 4 +- .../java/com/facebook/react/uimanager/BUCK | 38 +- .../react/uimanager/DisplayMetricsHolder.java | 23 + .../IllegalViewOperationException.java | 14 + .../react/uimanager/LayoutShadowNode.java | 4 + .../uimanager/NativeViewHierarchyManager.java | 6 +- .../facebook/react/uimanager/RootView.java | 2 + .../react/uimanager/UIViewOperationQueue.java | 7 +- .../facebook/react/uimanager/ViewProps.java | 36 +- .../facebook/react/uimanager/annotations/BUCK | 4 +- .../com/facebook/react/uimanager/util/BUCK | 4 +- .../uimanager/util/ReactFindViewUtil.java | 51 +- .../main/java/com/facebook/react/util/BUCK | 4 +- .../java/com/facebook/react/views/art/BUCK | 4 +- .../com/facebook/react/views/checkbox/BUCK | 4 +- .../java/com/facebook/react/views/common/BUCK | 4 +- .../java/com/facebook/react/views/drawer/BUCK | 4 +- .../java/com/facebook/react/views/image/BUCK | 6 +- .../com/facebook/react/views/imagehelper/BUCK | 6 +- .../java/com/facebook/react/views/modal/BUCK | 4 +- .../react/views/modal/ReactModalHostView.java | 36 +- .../java/com/facebook/react/views/picker/BUCK | 4 +- .../com/facebook/react/views/progressbar/BUCK | 4 +- .../java/com/facebook/react/views/scroll/BUCK | 4 +- .../scroll/ReactHorizontalScrollView.java | 45 +- .../ReactHorizontalScrollViewManager.java | 9 + .../react/views/scroll/ReactScrollView.java | 42 +- .../views/scroll/ReactScrollViewHelper.java | 7 +- .../views/scroll/ReactScrollViewManager.java | 14 +- .../java/com/facebook/react/views/slider/BUCK | 4 +- .../facebook/react/views/swiperefresh/BUCK | 4 +- .../com/facebook/react/views/switchview/BUCK | 4 +- .../views/switchview/ReactSwitchManager.java | 1 + .../java/com/facebook/react/views/text/BUCK | 4 +- .../react/views/text/ReactTextView.java | 11 +- .../react/views/text/frescosupport/BUCK | 4 +- .../com/facebook/react/views/textinput/BUCK | 4 +- .../react/views/textinput/ReactEditText.java | 34 +- .../ReactEditTextInputConnectionWrapper.java | 163 + .../ReactTextInputKeyPressEvent.java | 53 + .../textinput/ReactTextInputManager.java | 16 +- .../com/facebook/react/views/toolbar/BUCK | 4 +- .../java/com/facebook/react/views/view/BUCK | 4 +- .../react/views/view/ReactViewGroup.java | 104 +- .../com/facebook/react/views/viewpager/BUCK | 4 +- .../com/facebook/react/views/webview/BUCK | 4 +- .../src/main/java/com/facebook/systrace/BUCK | 4 +- .../java/com/facebook/yoga/YogaAlign.java | 2 +- .../java/com/facebook/yoga/YogaConfig.java | 2 + .../java/com/facebook/yoga/YogaDimension.java | 2 +- .../java/com/facebook/yoga/YogaDirection.java | 2 +- .../java/com/facebook/yoga/YogaDisplay.java | 2 +- .../main/java/com/facebook/yoga/YogaEdge.java | 2 +- .../yoga/YogaExperimentalFeature.java | 2 +- .../com/facebook/yoga/YogaFlexDirection.java | 2 +- .../java/com/facebook/yoga/YogaJustify.java | 2 +- .../java/com/facebook/yoga/YogaLogLevel.java | 2 +- .../com/facebook/yoga/YogaMeasureMode.java | 2 +- .../main/java/com/facebook/yoga/YogaNode.java | 26 +- .../java/com/facebook/yoga/YogaNodeType.java | 2 +- .../java/com/facebook/yoga/YogaOverflow.java | 2 +- .../com/facebook/yoga/YogaPositionType.java | 2 +- .../com/facebook/yoga/YogaPrintOptions.java | 2 +- .../main/java/com/facebook/yoga/YogaUnit.java | 2 +- .../main/java/com/facebook/yoga/YogaWrap.java | 2 +- ReactAndroid/src/main/jni/first-party/fb/BUCK | 48 +- .../fb/include/fb/fbjni/Registration-inl.h | 2 +- .../src/main/jni/first-party/fb/jni/fbjni.cpp | 8 +- .../src/main/jni/first-party/fb/jni/java/BUCK | 4 +- .../src/main/jni/first-party/fbgloginit/BUCK | 6 +- .../src/main/jni/first-party/jni-hack/BUCK | 4 +- .../src/main/jni/first-party/yogajni/BUCK | 40 +- .../jni/first-party/yogajni/jni/YGJNI.cpp | 181 +- .../src/main/jni/packagerconnection/BUCK | 8 +- ReactAndroid/src/main/jni/prebuilt/BUCK | 7 +- .../main/jni/react/jni/AndroidJSCFactory.cpp | 4 +- .../main/jni/react/jni/AndroidJSCFactory.h | 2 +- ReactAndroid/src/main/jni/react/jni/BUCK | 14 +- .../src/main/jni/react/jni/OnLoad.cpp | 2 +- .../jni/react/jni/ReadableNativeArray.cpp | 66 +- .../main/jni/react/jni/ReadableNativeArray.h | 2 + .../main/jni/react/jni/ReadableNativeMap.cpp | 88 +- .../main/jni/react/jni/ReadableNativeMap.h | 5 + .../src/main/jni/react/perftests/BUCK | 10 +- .../src/main/jni/third-party/android-ndk/BUCK | 2 - .../src/main/jni/third-party/glibc/BUCK | 2 - .../java/com/facebook/common/logging/BUCK | 4 +- .../src/test/java/com/facebook/powermock/BUCK | 28 +- .../libraries/fresco/fresco-react-native/BUCK | 12 +- .../soloader/java/com/facebook/soloader/BUCK | 2 - .../src/main/libraries/textlayoutbuilder/BUCK | 8 +- ReactAndroid/src/main/res/BUCK | 10 +- .../res/devsupport/layout/redbox_view.xml | 178 +- .../main/res/devsupport/values-af/strings.xml | 7 + .../main/res/devsupport/values-ar/strings.xml | 7 + .../main/res/devsupport/values-as/strings.xml | 7 + .../main/res/devsupport/values-az/strings.xml | 7 + .../main/res/devsupport/values-bg/strings.xml | 7 + .../main/res/devsupport/values-bn/strings.xml | 7 + .../main/res/devsupport/values-bs/strings.xml | 7 + .../main/res/devsupport/values-ca/strings.xml | 7 + .../main/res/devsupport/values-cb/strings.xml | 7 + .../main/res/devsupport/values-cs/strings.xml | 7 + .../main/res/devsupport/values-da/strings.xml | 7 + .../main/res/devsupport/values-de/strings.xml | 7 + .../main/res/devsupport/values-el/strings.xml | 7 + .../res/devsupport/values-en-rGB/strings.xml | 7 + .../res/devsupport/values-es-rES/strings.xml | 7 + .../main/res/devsupport/values-es/strings.xml | 7 + .../main/res/devsupport/values-et/strings.xml | 7 + .../main/res/devsupport/values-fa/strings.xml | 7 + .../res/devsupport/values-fb-rLS/strings.xml | 7 + .../main/res/devsupport/values-fb/strings.xml | 7 + .../main/res/devsupport/values-fi/strings.xml | 7 + .../res/devsupport/values-fr-rCA/strings.xml | 7 + .../main/res/devsupport/values-fr/strings.xml | 7 + .../main/res/devsupport/values-gu/strings.xml | 7 + .../main/res/devsupport/values-hi/strings.xml | 7 + .../main/res/devsupport/values-hr/strings.xml | 7 + .../main/res/devsupport/values-hu/strings.xml | 7 + .../main/res/devsupport/values-in/strings.xml | 7 + .../main/res/devsupport/values-is/strings.xml | 7 + .../main/res/devsupport/values-it/strings.xml | 7 + .../main/res/devsupport/values-iw/strings.xml | 7 + .../main/res/devsupport/values-ja/strings.xml | 7 + .../main/res/devsupport/values-ka/strings.xml | 7 + .../main/res/devsupport/values-km/strings.xml | 7 + .../main/res/devsupport/values-kn/strings.xml | 7 + .../main/res/devsupport/values-ko/strings.xml | 7 + .../main/res/devsupport/values-lo/strings.xml | 7 + .../main/res/devsupport/values-lt/strings.xml | 7 + .../main/res/devsupport/values-lv/strings.xml | 7 + .../main/res/devsupport/values-mk/strings.xml | 7 + .../main/res/devsupport/values-ml/strings.xml | 7 + .../main/res/devsupport/values-mn/strings.xml | 7 + .../main/res/devsupport/values-mr/strings.xml | 7 + .../main/res/devsupport/values-ms/strings.xml | 7 + .../main/res/devsupport/values-my/strings.xml | 7 + .../main/res/devsupport/values-nb/strings.xml | 7 + .../main/res/devsupport/values-ne/strings.xml | 7 + .../main/res/devsupport/values-nl/strings.xml | 7 + .../main/res/devsupport/values-pa/strings.xml | 7 + .../main/res/devsupport/values-pl/strings.xml | 7 + .../res/devsupport/values-pt-rPT/strings.xml | 7 + .../main/res/devsupport/values-pt/strings.xml | 7 + .../main/res/devsupport/values-qz/strings.xml | 7 + .../main/res/devsupport/values-ro/strings.xml | 7 + .../main/res/devsupport/values-ru/strings.xml | 7 + .../main/res/devsupport/values-si/strings.xml | 7 + .../main/res/devsupport/values-sk/strings.xml | 7 + .../main/res/devsupport/values-sl/strings.xml | 7 + .../main/res/devsupport/values-sn/strings.xml | 7 + .../main/res/devsupport/values-sq/strings.xml | 7 + .../main/res/devsupport/values-sr/strings.xml | 7 + .../main/res/devsupport/values-sv/strings.xml | 7 + .../main/res/devsupport/values-sw/strings.xml | 7 + .../main/res/devsupport/values-ta/strings.xml | 7 + .../main/res/devsupport/values-te/strings.xml | 7 + .../main/res/devsupport/values-th/strings.xml | 7 + .../main/res/devsupport/values-tl/strings.xml | 7 + .../main/res/devsupport/values-tr/strings.xml | 7 + .../main/res/devsupport/values-uk/strings.xml | 7 + .../main/res/devsupport/values-ur/strings.xml | 7 + .../main/res/devsupport/values-vi/strings.xml | 7 + .../main/res/devsupport/values-wo/strings.xml | 7 + .../res/devsupport/values-zh-rCN/strings.xml | 7 + .../res/devsupport/values-zh-rHK/strings.xml | 7 + .../res/devsupport/values-zh-rTW/strings.xml | 7 + .../main/res/devsupport/values-zu/strings.xml | 7 + .../src/main/res/devsupport/values/styles.xml | 12 +- .../android/support-annotations/BUCK | 2 - .../main/third-party/android/support/v4/BUCK | 2 - .../android/support/v7/appcompat-orig/BUCK | 10 +- .../src/main/third-party/java/asm/BUCK | 14 +- .../java/buck-android-support/BUCK | 2 +- .../src/main/third-party/java/fest/BUCK | 8 +- .../third-party/java/infer-annotations/BUCK | 2 - .../src/main/third-party/java/javapoet/BUCK | 2 - .../src/main/third-party/java/jsr-305/BUCK | 2 - .../src/main/third-party/java/jsr-330/BUCK | 2 - .../src/main/third-party/java/junit/BUCK | 8 +- .../src/main/third-party/java/mockito/BUCK | 8 +- .../src/main/third-party/java/okhttp/BUCK | 2 - .../src/main/third-party/java/okio/BUCK | 2 - .../java/robolectric3/robolectric/BUCK | 34 +- .../src/main/third-party/java/sqlite/BUCK | 6 +- .../third-party/java/testing-support-lib/BUCK | 2 - .../java/com/facebook/common/logging/BUCK | 4 +- .../src/test/java/com/facebook/react/BUCK | 2 +- .../java/com/facebook/react/animated/BUCK | 2 +- .../test/java/com/facebook/react/bridge/BUCK | 4 +- .../java/com/facebook/react/devsupport/BUCK | 2 +- .../test/java/com/facebook/react/modules/BUCK | 3 +- .../react/modules/blob/BlobModuleTest.java | 159 + .../modules/network/NetworkingModuleTest.java | 9 +- .../network/ProgressiveStringDecoderTest.java | 138 + .../facebook/react/packagerconnection/BUCK | 2 +- .../java/com/facebook/react/uimanager/BUCK | 2 +- .../test/java/com/facebook/react/views/BUCK | 2 +- .../textinput/ReactTextInputPropertyTest.java | 27 +- .../test/java/org/mockito/configuration/BUCK | 4 +- ReactCommon/DEFS | 25 - ReactCommon/cxxreact/BUCK | 42 +- ReactCommon/cxxreact/CxxNativeModule.cpp | 2 +- ReactCommon/cxxreact/JSBundleType.cpp | 6 +- ReactCommon/cxxreact/JSCExecutor.cpp | 43 +- ReactCommon/cxxreact/JSCExecutor.h | 11 +- ReactCommon/cxxreact/JSCUtils.cpp | 30 +- ReactCommon/cxxreact/JSCUtils.h | 8 - ReactCommon/cxxreact/JSIndexedRAMBundle.cpp | 22 +- ReactCommon/cxxreact/ModuleRegistry.h | 2 +- ReactCommon/cxxreact/oss-compat-util.h | 103 - ReactCommon/cxxreact/tests/BUCK | 79 +- ReactCommon/jschelpers/BUCK | 12 +- ReactCommon/jschelpers/JSCWrapper.h | 4 - ReactCommon/jschelpers/Value.cpp | 9 + ReactCommon/jschelpers/Value.h | 9 + ReactCommon/jsinspector/BUCK | 19 +- .../jsinspector/InspectorInterfaces.cpp | 7 +- ReactCommon/jsinspector/InspectorInterfaces.h | 4 +- ReactCommon/microprofiler/BUCK | 4 +- ReactCommon/privatedata/BUCK | 2 +- ReactCommon/yoga/BUCK | 4 +- ReactCommon/yoga/yoga/Utils.cpp | 31 + ReactCommon/yoga/yoga/Utils.h | 104 + ReactCommon/yoga/yoga/YGNode.cpp | 384 +- ReactCommon/yoga/yoga/YGNode.h | 60 +- ReactCommon/yoga/yoga/YGNodePrint.cpp | 8 +- ReactCommon/yoga/yoga/Yoga-internal.h | 73 +- ReactCommon/yoga/yoga/Yoga.cpp | 2216 +- ReactCommon/yoga/yoga/Yoga.h | 8 + ReactNative/DEFS.bzl | 174 + Releases.md | 3 +- babel-preset/configs/main.js | 91 +- babel-preset/lib/resolvePlugins.js | 30 +- ...ringing-modern-web-techniques-to-mobile.md | 22 - blog/2015-09-14-react-native-for-android.md | 19 - ...-23-making-react-native-apps-accessible.md | 25 - blog/2016-03-24-introducing-hot-reloading.md | 214 - ...3-28-dive-into-react-native-performance.md | 23 - ...016-04-13-react-native-a-year-in-review.md | 20 - .../2016-07-06-toward-better-documentation.md | 69 - ...08-12-react-native-meetup-san-francisco.md | 110 - ...t-to-left-support-for-react-native-apps.md | 220 - ...08-exponent-talks-unraveling-navigation.md | 12 - ...6-headless-js-the-keyboard-api-and-more.md | 86 - ...ducing-button-yarn-and-a-public-roadmap.md | 58 - blog/2016-12-05-easier-upgrades.md | 121 - blog/2017-01-07-monthly-release-cadence.md | 36 - ...-02-14-using-native-driver-for-animated.md | 158 - blog/2017-03-13-better-list-views.md | 120 - ...2017-03-13-idx-the-existential-function.md | 48 - ...-13-introducing-create-react-native-app.md | 35 - blog/2017-06-21-react-native-monthly-1.md | 94 - blog/2017-07-28-react-native-monthly-2.md | 100 - ...react-native-performance-in-marketplace.md | 57 - blog/2017-08-30-react-native-monthly-3.md | 60 - blog/2017-09-21-react-native-monthly-4.md | 45 - blog/2017-11-06-react-native-monthly-5.md | 61 - blog/img/RNPerformanceStartup.png | Bin 63417 -> 0 bytes blog/img/animated-diagram.png | Bin 23808 -> 0 bytes blog/img/big-hero.jpg | Bin 112626 -> 0 bytes blog/img/blue-hero.jpg | Bin 57509 -> 0 bytes blog/img/button-android-ios.png | Bin 155271 -> 0 bytes blog/img/dark-hero.png | Bin 58300 -> 0 bytes blog/img/git-upgrade-conflict.png | Bin 94088 -> 0 bytes blog/img/git-upgrade-output.png | Bin 338859 -> 0 bytes blog/img/hmr-architecture.png | Bin 16358 -> 0 bytes blog/img/hmr-diamond.png | Bin 23722 -> 0 bytes blog/img/hmr-log.png | Bin 28927 -> 0 bytes blog/img/hmr-proxy.png | Bin 8692 -> 0 bytes blog/img/hmr-step.png | Bin 21653 -> 0 bytes blog/img/rnmsf-august-2016-airbnb.jpg | Bin 72990 -> 0 bytes blog/img/rnmsf-august-2016-docs.jpg | Bin 88037 -> 0 bytes blog/img/rnmsf-august-2016-hero.jpg | Bin 240482 -> 0 bytes blog/img/rnmsf-august-2016-netflix.jpg | Bin 78705 -> 0 bytes blog/img/rtl-ama-android-hebrew.png | Bin 486698 -> 0 bytes blog/img/rtl-ama-ios-arabic.png | Bin 455174 -> 0 bytes blog/img/rtl-demo-forcertl.png | Bin 19664 -> 0 bytes blog/img/rtl-demo-icon-ltr.png | Bin 15206 -> 0 bytes blog/img/rtl-demo-icon-rtl.png | Bin 15194 -> 0 bytes blog/img/rtl-demo-listitem-ltr.png | Bin 21532 -> 0 bytes blog/img/rtl-demo-listitem-rtl.png | Bin 21455 -> 0 bytes blog/img/rtl-demo-swipe-ltr.png | Bin 378053 -> 0 bytes blog/img/rtl-demo-swipe-rtl.png | Bin 380640 -> 0 bytes blog/img/rtl-rn-core-updates.png | Bin 48781 -> 0 bytes blog/img/yarn-rncli.png | Bin 55924 -> 0 bytes {danger => bots}/.babelrc | 0 bots/README.md | 19 +- {danger => bots}/dangerfile.js | 28 +- {danger => bots}/package.json | 0 danger/README.md | 12 - flow-github/metro.js | 4 + jest/preprocessor.js | 1 + local-cli/.eslintrc | 2 +- local-cli/__tests__/fs-mock-test.js | 2 - local-cli/bundle/buildBundle.js | 100 +- local-cli/bundle/bundle.js | 10 +- local-cli/bundle/bundleCommandLineArgs.js | 6 + local-cli/bundle/unbundle.js | 4 +- local-cli/core/__tests__/findPlugins.spec.js | 28 +- local-cli/core/findPlugins.js | 32 +- local-cli/core/index.js | 54 +- local-cli/core/makeCommand.js | 2 +- local-cli/core/windows/findNamespace.js | 30 - .../core/windows/findPackageClassName.js | 30 - local-cli/core/windows/findProject.js | 27 - local-cli/core/windows/findWindowsSolution.js | 60 - local-cli/core/windows/generateGUID.js | 10 - local-cli/core/windows/index.js | 114 - local-cli/dependencies/dependencies.js | 3 +- .../copyProjectTemplateAndReplace.js | 2 +- .../link/__tests__/android/applyPatch.spec.js | 2 +- .../__tests__/android/isInstalled.spec.js | 2 +- .../__tests__/android/makeBuildPatch.spec.js | 2 +- .../__tests__/android/makeImportPatch.spec.js | 2 +- .../android/makePackagePatch.spec.js | 2 +- .../android/makeSettingsPatch.spec.js | 2 +- .../android/makeStringsPatch.spec.js | 2 +- .../__tests__/getDependencyConfig.spec.js | 2 +- .../__tests__/getProjectDependencies.spec.js | 2 +- .../link/__tests__/groupFilesByType.spec.js | 2 +- .../__tests__/ios/addFileToProject.spec.js | 2 +- .../ios/addProjectToLibraries.spec.js | 2 +- .../__tests__/ios/addSharedLibraries.spec.js | 2 +- .../link/__tests__/ios/createGroup.spec.js | 2 +- .../__tests__/ios/getBuildProperty.spec.js | 2 +- local-cli/link/__tests__/ios/getGroup.spec.js | 2 +- .../__tests__/ios/getHeaderSearchPath.spec.js | 2 +- .../__tests__/ios/getHeadersInFolder.spec.js | 2 +- local-cli/link/__tests__/ios/getPlist.spec.js | 2 +- .../link/__tests__/ios/getPlistPath.spec.js | 2 +- .../link/__tests__/ios/getProducts.spec.js | 2 +- .../link/__tests__/ios/getTargets.spec.js | 35 + .../__tests__/ios/hasLibraryImported.spec.js | 2 +- .../link/__tests__/ios/isInstalled.spec.js | 2 +- .../ios/mapHeaderSearchPaths.spec.js | 2 +- .../ios/removeProjectFromLibraries.js | 2 +- .../ios/removeProjectFromProject.spec.js | 2 +- .../__tests__/ios/removeSharedLibrary.spec.js | 2 +- .../link/__tests__/ios/writePlist.spec.js | 2 +- local-cli/link/__tests__/link.spec.js | 66 +- .../__tests__/pods/findLineToAddPod.spec.js | 2 +- .../pods/findMarkedLinesInPodfile.spec.js | 2 +- .../__tests__/pods/findPodTargetLine.spec.js | 2 +- .../link/__tests__/pods/isInstalled.spec.js | 2 +- .../__tests__/pods/removePodEntry.spec.js | 2 +- .../link/__tests__/promiseWaterfall.spec.js | 2 +- local-cli/link/android/copyAssets.js | 9 + local-cli/link/android/fs.js | 9 + local-cli/link/android/isInstalled.js | 9 + local-cli/link/android/patches/applyParams.js | 2 +- local-cli/link/android/patches/applyPatch.js | 9 + .../link/android/patches/makeBuildPatch.js | 9 + .../link/android/patches/makeImportPatch.js | 9 + .../link/android/patches/makePackagePatch.js | 9 + .../link/android/patches/makeSettingsPatch.js | 9 + .../link/android/patches/makeStringsPatch.js | 9 + local-cli/link/android/patches/revokePatch.js | 9 + .../link/android/registerNativeModule.js | 9 + local-cli/link/android/unlinkAssets.js | 9 + .../link/android/unregisterNativeModule.js | 9 + local-cli/link/commandStub.js | 9 + local-cli/link/getDependencyConfig.js | 9 + local-cli/link/getProjectDependencies.js | 9 + local-cli/link/groupFilesByType.js | 9 + local-cli/link/ios/addFileToProject.js | 9 + local-cli/link/ios/addProjectToLibraries.js | 9 + local-cli/link/ios/addSharedLibraries.js | 9 + local-cli/link/ios/addToHeaderSearchPaths.js | 9 + local-cli/link/ios/copyAssets.js | 9 + local-cli/link/ios/createGroup.js | 11 +- local-cli/link/ios/createGroupWithMessage.js | 9 + local-cli/link/ios/getBuildProperty.js | 9 + local-cli/link/ios/getGroup.js | 9 + local-cli/link/ios/getHeaderSearchPath.js | 9 + local-cli/link/ios/getHeadersInFolder.js | 9 + local-cli/link/ios/getPlist.js | 9 + local-cli/link/ios/getPlistPath.js | 9 + local-cli/link/ios/getProducts.js | 9 + local-cli/link/ios/getTargets.js | 29 + local-cli/link/ios/hasLibraryImported.js | 9 + local-cli/link/ios/isInstalled.js | 9 + local-cli/link/ios/mapHeaderSearchPaths.js | 9 + local-cli/link/ios/registerNativeModule.js | 37 +- .../link/ios/removeFromHeaderSearchPaths.js | 9 + .../removeFromPbxItemContainerProxySection.js | 9 + .../ios/removeFromPbxReferenceProxySection.js | 9 + .../link/ios/removeFromProjectReferences.js | 9 + .../link/ios/removeFromStaticLibraries.js | 9 + local-cli/link/ios/removeProductGroup.js | 9 + .../link/ios/removeProjectFromLibraries.js | 9 + .../link/ios/removeProjectFromProject.js | 9 + local-cli/link/ios/removeSharedLibraries.js | 9 + local-cli/link/ios/unlinkAssets.js | 9 + local-cli/link/ios/unregisterNativeModule.js | 14 +- local-cli/link/ios/writePlist.js | 9 + local-cli/link/link.js | 91 +- local-cli/link/pods/addPodEntry.js | 9 + local-cli/link/pods/findLineToAddPod.js | 9 + .../link/pods/findMarkedLinesInPodfile.js | 9 + local-cli/link/pods/findPodTargetLine.js | 9 + local-cli/link/pods/isInstalled.js | 9 + local-cli/link/pods/readPodfile.js | 9 + local-cli/link/pods/registerNativeModule.js | 9 + local-cli/link/pods/removePodEntry.js | 9 + local-cli/link/pods/savePodFile.js | 9 + local-cli/link/pods/unregisterNativeModule.js | 9 + local-cli/link/pollParams.js | 9 + local-cli/link/promiseWaterfall.js | 9 + local-cli/link/promisify.js | 9 + local-cli/link/unlink.js | 58 +- local-cli/link/windows/isInstalled.js | 8 - local-cli/link/windows/patches/applyParams.js | 23 - local-cli/link/windows/patches/applyPatch.js | 11 - .../link/windows/patches/makePackagePatch.js | 10 - .../link/windows/patches/makeProjectPatch.js | 14 - .../link/windows/patches/makeSolutionPatch.js | 12 - .../link/windows/patches/makeUsingPatch.js | 6 - local-cli/link/windows/patches/revokePatch.js | 9 - .../link/windows/registerNativeModule.js | 26 - .../link/windows/unregisterNativeModule.js | 27 - local-cli/runAndroid/runAndroid.js | 14 +- .../__tests__/findMatchingSimulator-test.js | 33 + local-cli/runIOS/findMatchingSimulator.js | 4 +- local-cli/runIOS/runIOS.js | 42 +- .../middleware/getDevToolsMiddleware.js | 11 +- local-cli/server/runServer.js | 20 +- local-cli/server/server.js | 2 +- local-cli/server/util/messageSocket.js | 2 +- .../components/KeyboardSpacer.js | 11 +- local-cli/templates/HelloWorld/_flowconfig | 4 +- .../android/app/src/main/AndroidManifest.xml | 10 +- local-cli/util/Config.js | 3 + local-cli/util/isPackagerRunning.js | 4 +- package.json | 46 +- react-native-git-upgrade/README.md | 2 +- react-native-git-upgrade/cliEntry.js | 27 +- scripts/android-e2e-test.js | 2 +- scripts/launchPackager.bat | 2 +- scripts/launchPackager.command | 2 +- scripts/objc-test.sh | 3 +- scripts/packager.sh | 1 + scripts/process-podspecs.sh | 2 +- scripts/react-native-xcode.sh | 13 +- scripts/run-ci-e2e-tests.js | 18 +- scripts/sync-css-layout.sh | 6 +- third-party-podspecs/Folly.podspec | 6 +- .../{GLog.podspec => glog.podspec} | 3 +- 867 files changed, 46908 insertions(+), 28857 deletions(-) create mode 100644 .circleci/README.md create mode 100644 Libraries/Blob/BlobManager.js create mode 100644 Libraries/Blob/BlobRegistry.js create mode 100644 Libraries/Blob/File.js create mode 100644 Libraries/Blob/FileReader.js delete mode 100755 Libraries/Blob/RCTBlobManager.m create mode 100755 Libraries/Blob/RCTBlobManager.mm rename Libraries/{Text/TextInput/Multiline/RCTMultilineTextInputShadowView.h => Blob/RCTFileReaderModule.h} (77%) create mode 100644 Libraries/Blob/RCTFileReaderModule.m create mode 100644 Libraries/Blob/__mocks__/BlobModule.js create mode 100644 Libraries/Blob/__mocks__/FileReaderModule.js create mode 100644 Libraries/Blob/__tests__/Blob-test.js create mode 100644 Libraries/Blob/__tests__/BlobManager-test.js create mode 100644 Libraries/Blob/__tests__/File-test.js create mode 100644 Libraries/Blob/__tests__/FileReader-test.js create mode 100644 Libraries/Components/View/ViewContext.js create mode 100644 Libraries/ReactNative/FabricUIManager.js delete mode 100644 Libraries/ReactNative/ReactNativeFeatureFlags.js create mode 100644 Libraries/ReactNative/renderFabricSurface.js create mode 100644 Libraries/Renderer/ReactFabric-dev.js create mode 100644 Libraries/Renderer/ReactFabric-prod.js create mode 100644 Libraries/Renderer/shims/ReactFabric.js create mode 100644 Libraries/Text/BaseText/RCTBaseTextShadowView.h create mode 100644 Libraries/Text/BaseText/RCTBaseTextShadowView.m rename Libraries/Text/{TextInput/Multiline/RCTMultilineTextInputShadowView.m => BaseText/RCTBaseTextViewManager.h} (70%) create mode 100644 Libraries/Text/BaseText/RCTBaseTextViewManager.m delete mode 100644 Libraries/Text/RCTFontAttributes.h delete mode 100644 Libraries/Text/RCTFontAttributes.m create mode 100644 Libraries/Text/RCTTextAttributes.h create mode 100644 Libraries/Text/RCTTextAttributes.m rename Libraries/Text/{ => RawText}/RCTRawTextShadowView.h (79%) rename Libraries/Text/{ => RawText}/RCTRawTextShadowView.m (53%) rename Libraries/Text/{ => RawText}/RCTRawTextViewManager.h (89%) rename Libraries/Text/{ => RawText}/RCTRawTextViewManager.m (92%) create mode 100644 Libraries/Text/Text/NSTextStorage+FontScaling.h create mode 100644 Libraries/Text/Text/NSTextStorage+FontScaling.m create mode 100644 Libraries/Text/TextInput/RCTBaseTextInputShadowView.h create mode 100644 Libraries/Text/TextInput/RCTBaseTextInputShadowView.m rename Libraries/Text/{RCTFontAttributesDelegate.h => TextInput/RCTBaseTextInputViewManager.h} (75%) create mode 100644 Libraries/Text/TextInput/RCTBaseTextInputViewManager.m create mode 100644 Libraries/Text/TextProps.js rename Libraries/Text/{TextInput/Singleline/RCTSinglelineTextInputShadowView.h => VirtualText/RCTVirtualTextShadowView.h} (77%) create mode 100644 Libraries/Text/VirtualText/RCTVirtualTextShadowView.m create mode 100644 Libraries/Text/VirtualText/RCTVirtualTextViewManager.h create mode 100644 Libraries/Text/VirtualText/RCTVirtualTextViewManager.m create mode 100644 Libraries/Utilities/JSDevSupportModule.js delete mode 100644 Libraries/Utilities/__tests__/utf8-test.js delete mode 100644 Libraries/Utilities/asyncRequire.js delete mode 100644 Libraries/Utilities/utf8.js delete mode 100644 RNTester/RNTesterLegacy.xcodeproj/project.pbxproj delete mode 100644 RNTester/RNTesterLegacy.xcodeproj/xcshareddata/xcschemes/RNTester-tvOS.xcscheme delete mode 100644 RNTester/RNTesterLegacy.xcodeproj/xcshareddata/xcschemes/RNTester.xcscheme create mode 100644 RNTester/RNTesterUnitTests/RCTBlobManagerTests.m delete mode 100644 RNTester/RNTesterUnitTests/RCTBridgeTests.m delete mode 100644 RNTester/RNTesterUnitTests/RCTJSCExecutorTests.m delete mode 100644 React/Base/RCTBatchedBridge.mm create mode 100644 React/Base/Surface/SurfaceHostingView/RCTSurfaceSizeMeasureMode.mm delete mode 100644 React/Executors/RCTJSCExecutor.h delete mode 100644 React/Executors/RCTJSCExecutor.mm rename Libraries/Text/TextInput/Singleline/RCTSinglelineTextInputShadowView.m => React/Fabric/RCTFabricUIManager.h (68%) create mode 100644 React/Fabric/RCTFabricUIManager.mm delete mode 100644 React/ReactLegacy.xcodeproj/project.pbxproj create mode 100644 React/UIUtils/RCTUIUtils.h create mode 100644 React/UIUtils/RCTUIUtils.m delete mode 100644 ReactAndroid/DEFS create mode 100644 ReactAndroid/src/main/java/com/facebook/react/common/StandardCharsets.java create mode 100644 ReactAndroid/src/main/java/com/facebook/react/devsupport/BundleDeltaClient.java create mode 100644 ReactAndroid/src/main/java/com/facebook/react/devsupport/JSDevSupport.java create mode 100644 ReactAndroid/src/main/java/com/facebook/react/fabric/BUCK create mode 100644 ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManagerModule.java create mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/blob/FileReaderModule.java create mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/network/.NetworkingModule.java.swp create mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/network/.NetworkingModule_BASE_5628.java.swp create mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/network/.NetworkingModule_LOCAL_5628.java.swp create mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/network/.NetworkingModule_REMOTE_5628.java.swp create mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/network/CountingOutputStream.java create mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule_BACKUP_5628.java create mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule_BASE_5628.java create mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule_LOCAL_5628.java create mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule_REMOTE_5628.java create mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/network/OkHttpClientFactory.java create mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/network/ProgressiveStringDecoder.java create mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditTextInputConnectionWrapper.java create mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputKeyPressEvent.java create mode 100644 ReactAndroid/src/main/res/devsupport/values-af/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-ar/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-as/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-az/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-bg/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-bn/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-bs/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-ca/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-cb/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-cs/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-da/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-de/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-el/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-en-rGB/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-es-rES/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-es/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-et/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-fa/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-fb-rLS/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-fb/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-fi/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-fr-rCA/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-fr/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-gu/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-hi/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-hr/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-hu/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-in/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-is/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-it/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-iw/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-ja/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-ka/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-km/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-kn/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-ko/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-lo/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-lt/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-lv/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-mk/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-ml/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-mn/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-mr/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-ms/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-my/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-nb/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-ne/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-nl/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-pa/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-pl/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-pt-rPT/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-pt/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-qz/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-ro/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-ru/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-si/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-sk/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-sl/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-sn/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-sq/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-sr/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-sv/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-sw/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-ta/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-te/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-th/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-tl/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-tr/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-uk/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-ur/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-vi/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-wo/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-zh-rCN/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-zh-rHK/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-zh-rTW/strings.xml create mode 100644 ReactAndroid/src/main/res/devsupport/values-zu/strings.xml create mode 100644 ReactAndroid/src/test/java/com/facebook/react/modules/blob/BlobModuleTest.java create mode 100644 ReactAndroid/src/test/java/com/facebook/react/modules/network/ProgressiveStringDecoderTest.java delete mode 100644 ReactCommon/DEFS delete mode 100644 ReactCommon/cxxreact/oss-compat-util.h create mode 100644 ReactCommon/yoga/yoga/Utils.cpp create mode 100644 ReactCommon/yoga/yoga/Utils.h create mode 100644 ReactNative/DEFS.bzl delete mode 100644 blog/2015-03-26-react-native-bringing-modern-web-techniques-to-mobile.md delete mode 100644 blog/2015-09-14-react-native-for-android.md delete mode 100644 blog/2015-11-23-making-react-native-apps-accessible.md delete mode 100644 blog/2016-03-24-introducing-hot-reloading.md delete mode 100644 blog/2016-03-28-dive-into-react-native-performance.md delete mode 100644 blog/2016-04-13-react-native-a-year-in-review.md delete mode 100644 blog/2016-07-06-toward-better-documentation.md delete mode 100644 blog/2016-08-12-react-native-meetup-san-francisco.md delete mode 100644 blog/2016-08-19-right-to-left-support-for-react-native-apps.md delete mode 100644 blog/2016-09-08-exponent-talks-unraveling-navigation.md delete mode 100644 blog/2016-10-25-0.36-headless-js-the-keyboard-api-and-more.md delete mode 100644 blog/2016-11-08-introducing-button-yarn-and-a-public-roadmap.md delete mode 100644 blog/2016-12-05-easier-upgrades.md delete mode 100644 blog/2017-01-07-monthly-release-cadence.md delete mode 100644 blog/2017-02-14-using-native-driver-for-animated.md delete mode 100644 blog/2017-03-13-better-list-views.md delete mode 100644 blog/2017-03-13-idx-the-existential-function.md delete mode 100644 blog/2017-03-13-introducing-create-react-native-app.md delete mode 100644 blog/2017-06-21-react-native-monthly-1.md delete mode 100644 blog/2017-07-28-react-native-monthly-2.md delete mode 100644 blog/2017-08-07-react-native-performance-in-marketplace.md delete mode 100644 blog/2017-08-30-react-native-monthly-3.md delete mode 100644 blog/2017-09-21-react-native-monthly-4.md delete mode 100644 blog/2017-11-06-react-native-monthly-5.md delete mode 100644 blog/img/RNPerformanceStartup.png delete mode 100644 blog/img/animated-diagram.png delete mode 100644 blog/img/big-hero.jpg delete mode 100644 blog/img/blue-hero.jpg delete mode 100644 blog/img/button-android-ios.png delete mode 100644 blog/img/dark-hero.png delete mode 100644 blog/img/git-upgrade-conflict.png delete mode 100644 blog/img/git-upgrade-output.png delete mode 100644 blog/img/hmr-architecture.png delete mode 100644 blog/img/hmr-diamond.png delete mode 100644 blog/img/hmr-log.png delete mode 100644 blog/img/hmr-proxy.png delete mode 100644 blog/img/hmr-step.png delete mode 100644 blog/img/rnmsf-august-2016-airbnb.jpg delete mode 100644 blog/img/rnmsf-august-2016-docs.jpg delete mode 100644 blog/img/rnmsf-august-2016-hero.jpg delete mode 100644 blog/img/rnmsf-august-2016-netflix.jpg delete mode 100644 blog/img/rtl-ama-android-hebrew.png delete mode 100644 blog/img/rtl-ama-ios-arabic.png delete mode 100644 blog/img/rtl-demo-forcertl.png delete mode 100644 blog/img/rtl-demo-icon-ltr.png delete mode 100644 blog/img/rtl-demo-icon-rtl.png delete mode 100644 blog/img/rtl-demo-listitem-ltr.png delete mode 100644 blog/img/rtl-demo-listitem-rtl.png delete mode 100644 blog/img/rtl-demo-swipe-ltr.png delete mode 100644 blog/img/rtl-demo-swipe-rtl.png delete mode 100644 blog/img/rtl-rn-core-updates.png delete mode 100644 blog/img/yarn-rncli.png rename {danger => bots}/.babelrc (100%) rename {danger => bots}/dangerfile.js (90%) rename {danger => bots}/package.json (100%) delete mode 100644 danger/README.md delete mode 100644 local-cli/core/windows/findNamespace.js delete mode 100644 local-cli/core/windows/findPackageClassName.js delete mode 100644 local-cli/core/windows/findProject.js delete mode 100644 local-cli/core/windows/findWindowsSolution.js delete mode 100644 local-cli/core/windows/generateGUID.js delete mode 100644 local-cli/core/windows/index.js create mode 100644 local-cli/link/__tests__/ios/getTargets.spec.js create mode 100644 local-cli/link/ios/getTargets.js delete mode 100644 local-cli/link/windows/isInstalled.js delete mode 100644 local-cli/link/windows/patches/applyParams.js delete mode 100644 local-cli/link/windows/patches/applyPatch.js delete mode 100644 local-cli/link/windows/patches/makePackagePatch.js delete mode 100644 local-cli/link/windows/patches/makeProjectPatch.js delete mode 100644 local-cli/link/windows/patches/makeSolutionPatch.js delete mode 100644 local-cli/link/windows/patches/makeUsingPatch.js delete mode 100644 local-cli/link/windows/patches/revokePatch.js delete mode 100644 local-cli/link/windows/registerNativeModule.js delete mode 100644 local-cli/link/windows/unregisterNativeModule.js rename third-party-podspecs/{GLog.podspec => glog.podspec} (96%) diff --git a/.circleci/README.md b/.circleci/README.md new file mode 100644 index 00000000000000..9c944ef6d105c0 --- /dev/null +++ b/.circleci/README.md @@ -0,0 +1,5 @@ +# Circle CI + +This directory is home to the Circle CI configuration file. Circle is our continuous integration service provider. You can see the overall status of React Native's builds at https://circleci.com/gh/facebook/react-native + +You may also see an individual PR's build status by scrolling down to the Checks section in the PR. diff --git a/.circleci/config.yml b/.circleci/config.yml index 27e9ccbecdb154..4f169608b7f8aa 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,48 +1,44 @@ aliases: - - &restore-node-cache + # Cache Management + - &restore-yarn-cache keys: - - v1-dependencies-{{ arch }}-{{ checksum "package.json" }} + - v1-yarn-{{ arch }}-{{ checksum "package.json" }} # Fallback in case checksum fails - - v1-dependencies-{{ arch }}- - - - &save-node-cache + - v1-yarn-{{ arch }}- + - &save-yarn-cache paths: - node_modules - key: v1-dependencies-{{ arch }}-{{ checksum "package.json" }} + - ~/.cache/yarn + key: v1-yarn-{{ arch }}-{{ checksum "package.json" }} - &restore-cache-analysis keys: - - v1-analysis-dependencies-{{ arch }}-{{ checksum "package.json" }}{{ checksum "danger/package.json" }} + - v1-analysis-dependencies-{{ arch }}-{{ checksum "package.json" }}{{ checksum "bots/package.json" }} # Fallback in case checksum fails - v1-analysis-dependencies-{{ arch }}- - &save-cache-analysis paths: - - danger/node_modules + - bots/node_modules - node_modules - key: v1-analysis-dependencies-{{ arch }}-{{ checksum "package.json" }}{{ checksum "danger/package.json" }} + key: v1-analysis-dependencies-{{ arch }}-{{ checksum "package.json" }}{{ checksum "bots/package.json" }} - &restore-cache-android-packages keys: - - v2-android-sdkmanager-packages-{{ arch }}-{{ checksum "scripts/circle-ci-android-setup.sh" }} + - v1-android-sdkmanager-packages-{{ arch }}-api-26-alpha-{{ checksum "scripts/circle-ci-android-setup.sh" }} # Fallback in case checksum fails - - v2-android-sdkmanager-packages-{{ arch }}- + - v1-android-sdkmanager-packages-{{ arch }}-api-26-alpha- - &save-cache-android-packages paths: - /opt/android/sdk - key: v2-android-sdkmanager-packages-{{ arch }}-{{ checksum "scripts/circle-ci-android-setup.sh" }} + key: v1-android-sdkmanager-packages-{{ arch }}-api-26-alpha-{{ checksum "scripts/circle-ci-android-setup.sh" }} - &restore-cache-ndk keys: - - v1-android-ndk-{{ arch }}-r10e-32-64 - - - &install-ndk - | - source scripts/circle-ci-android-setup.sh && getAndroidNDK - + - v2-android-ndk-{{ arch }}-r10e-32-64 - &save-cache-ndk paths: - /opt/ndk - key: v1-android-ndk-{{ arch }}-r10e-32-64 + key: v2-android-ndk-{{ arch }}-r10e-32-64 - &restore-cache-buck keys: @@ -60,36 +56,7 @@ aliases: - ~/watchman key: v1-watchman-{{ arch }}-v4.9.0 - - &install-node-dependencies - | - 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.11.16.01 --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 - - - &run-lint-checks - | - npm run lint - - - &run-flow-checks - | - npm run flow -- check - - + # Branch Filtering - &filter-only-master-stable branches: only: @@ -112,8 +79,41 @@ aliases: - /.*-stable/ - gh-pages - - &create-ndk-directory + # Dependency Management + - &install-ndk + | + source scripts/circle-ci-android-setup.sh && getAndroidNDK + + - &yarn + | + yarn install --non-interactive --cache-folder ~/.cache/yarn + + - &install-yarn + | + curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add - + echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list + sudo apt-get update && sudo apt-get install yarn + + - &install-node-dependencies + | + 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.11.16.01 --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 + + - &create-ndk-directory + name: Create Android NDK Directory + command: | if [[ ! -e /opt/ndk ]]; then sudo mkdir /opt/ndk fi @@ -122,7 +122,8 @@ aliases: # 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 - | + name: Configure Environment Variables + command: | echo 'export PATH=${ANDROID_NDK}:~/react-native/gradle-2.9/bin:~/buck/bin:$PATH' >> $BASH_ENV source $BASH_ENV @@ -130,29 +131,49 @@ aliases: | source scripts/circle-ci-android-setup.sh && getAndroidSDK - - &install-build-dependencies - | + - &install-android-build-dependencies + name: Install Android 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 file -y + # Test Definitions + - &run-js-tests + name: JavaScript Test Suite + command: yarn test-ci + + - &run-lint-checks + name: Lint code + command: yarn lint --format junit -o ~/react-native/reports/junit/js-lint-results.xml + when: always + + - &run-flow-checks + name: Check for errors in code using Flow + command: yarn flow check + when: always + - &build-android-app name: Build Android App command: | buck build ReactAndroid/src/main/java/com/facebook/react buck build ReactAndroid/src/main/java/com/facebook/react/shell + - &create-avd + name: Create Android Virtual Device + command: source scripts/circle-ci-android-setup.sh && createAVD + + - &launch-avd + name: Launch Android Virtual Device in Background + command: source scripts/circle-ci-android-setup.sh && launchAVD + background: true + - &wait-for-avd name: Wait for Android Virtual Device command: source scripts/circle-ci-android-setup.sh && waitForAVD - - &check-js-bundle - name: Check for JavaScript Bundle - command: | - if [[ ! -e ReactAndroid/src/androidTest/assets/AndroidTestBundle.js ]]; then - echo "JavaScript bundle missing, verify build-js-bundle step"; exit 1; - else - echo "JavaScript bundle found."; - fi + - &build-js-bundle + name: Build JavaScript Bundle + command: node local-cli/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 - &compile-native-libs name: Compile Native Libs for Unit and Integration Tests @@ -160,24 +181,54 @@ aliases: no_output_timeout: 6m - &run-android-unit-tests - name: Unit Tests + name: Run Unit Tests command: buck test ReactAndroid/src/test/... --config build.threads=$BUILD_THREADS - - &run-android-integration-tests - 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 + - &run-android-instrumentation-tests + name: Run Instrumentation Tests + command: | + if [[ ! -e ReactAndroid/src/androidTest/assets/AndroidTestBundle.js ]]; then + echo "JavaScript bundle missing, cannot run instrumentation tests. Verify build-js-bundle step completed successfully."; exit 1; + fi + 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 - &collect-android-test-results 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/ \; + find . -type f -regex ".*/build/test-results/debug/.*xml" -exec cp {} ~/react-native/reports/junit/ \; + find . -type f -regex ".*/outputs/androidTest-results/connected/.*xml" -exec cp {} ~/react-native/reports/junit/ \; + find . -type f -regex ".*/buck-out/gen/ReactAndroid/src/test/.*/.*xml" -exec cp {} ~/react-native/reports/junit/ \; when: always + - &setup-artifacts + name: Initial Setup + command: | + mkdir -p ~/react-native/reports/junit/ + + - &run-objc_ios-tests + name: Objective-C iOS Test Suite + command: ./scripts/objc-test-ios.sh + + - &run-objc-tvos-tests + name: Objective-C tvOS Test Suite + command: ./scripts/objc-test-tvos.sh + + - &run-objc-ios-e2e-tests + name: Objective-C iOS End-to-End Test Suite + command: node ./scripts/run-ci-e2e-tests.js --ios --js --retries 3; + + - &run-objc-tvos-e2e-tests + name: Objective-C tvOS End-to-End Test Suite + command: node ./scripts/run-ci-e2e-tests.js --tvos --js --retries 3; + defaults: &defaults working_directory: ~/react-native +js_defaults: &js_defaults + <<: *defaults + docker: + - image: circleci/node:8 + android_defaults: &android_defaults <<: *defaults docker: @@ -191,125 +242,168 @@ android_defaults: &android_defaults - ANDROID_NDK: '/opt/ndk/android-ndk-r10e' - BUILD_THREADS: 2 +macos_defaults: &macos_defaults + <<: *defaults + macos: + xcode: "9.0" + version: 2 jobs: - # Runs JavaScript lint and flow checks - run-js-checks: - <<: *defaults - docker: - - image: circleci/node:8 + + # Set up a Node environment for downstream jobs + checkout_code: + <<: *js_defaults steps: - checkout - - restore-cache: *restore-node-cache - - run: *install-node-dependencies - - save-cache: *save-node-cache + - run: *setup-artifacts + + - restore-cache: *restore-yarn-cache + - run: *yarn + - save-cache: *save-yarn-cache + + - persist_to_workspace: + root: . + paths: . + + # Runs JavaScript lint and flow checks. + # Currently will fail a PR if lint/flow raises issues. + js_checks: + <<: *js_defaults + steps: + - attach_workspace: + at: ~/react-native + - run: *run-lint-checks - run: *run-flow-checks + - store_test_results: + path: ~/react-native/reports/junit + - store_artifacts: + path: ~/react-native/reports/junit + - store_artifacts: + path: ~/react-native/yarn.lock + # Runs JavaScript tests on Node 8 - test-js-node-8: - <<: *defaults - docker: - - image: circleci/node:8 + test_javascript: + <<: *js_defaults steps: - - checkout - - restore-cache: *restore-node-cache - - run: *install-node-dependencies - - save-cache: *save-node-cache - - run: *run-node-tests + - attach_workspace: + at: ~/react-native + + - run: *run-js-tests + + - store_test_results: + path: ~/react-native/reports/junit + - store_artifacts: + path: ~/react-native/reports/junit # Runs JavaScript tests on Node 6 - test-js-node-6: + test_javascript_node6_compatibility: <<: *defaults docker: - image: circleci/node:6 steps: - checkout - - restore-cache: *restore-node-cache - - run: *install-node-dependencies - - save-cache: *save-node-cache - - run: *run-node-tests + - run: *setup-artifacts + + - restore-cache: *restore-yarn-cache + - run: *yarn + - save-cache: *save-yarn-cache + + - run: *run-js-tests + + - store_test_results: + path: ~/react-native/reports/junit + - store_artifacts: + path: ~/react-native/reports/junit # Runs unit tests on iOS devices - test-objc-ios: - <<: *defaults - macos: - xcode: "9.0" + test_objc_ios: + <<: *macos_defaults dependencies: pre: - xcrun instruments -w "iPhone 5s (10.3.1)" || true steps: - - checkout - - restore-cache: *restore-node-cache - - run: *install-node-dependencies - - save-cache: *save-node-cache - - run: ./scripts/objc-test-ios.sh + - attach_workspace: + at: ~/react-native + + - run: *run-objc_ios-tests + + - store_test_results: + path: ~/react-native/reports/junit + - store_artifacts: + path: ~/react-native/reports/junit # Runs unit tests on tvOS devices - test-objc-tvos: - <<: *defaults - macos: - xcode: "9.0" + test_objc_tvos: + <<: *macos_defaults dependencies: pre: - xcrun instruments -w "Apple TV 1080p (10.0)" || true steps: - - checkout - - restore-cache: *restore-node-cache - - run: *install-node-dependencies - - save-cache: *save-node-cache - - run: ./scripts/objc-test-tvos.sh + - attach_workspace: + at: ~/react-native + + - run: *run-objc-tvos-tests + + - store_test_results: + path: ~/react-native/reports/junit + - store_artifacts: + path: ~/react-native/reports/junit # Runs end to end tests - test-objc-e2e: - <<: *defaults - macos: - xcode: "9.0" + test_objc_ios_e2e: + <<: *macos_defaults dependencies: pre: - xcrun instruments -w "iPhone 5s (10.3.1)" || true steps: - - checkout - - restore-cache: *restore-node-cache - - run: *install-node-dependencies - - save-cache: *save-node-cache - - run: node ./scripts/run-ci-e2e-tests.js --ios --js --retries 3; + - attach_workspace: + at: ~/react-native + + - run: *run-objc-ios-e2e-tests + + - store_test_results: + path: ~/react-native/reports/junit + - store_artifacts: + path: ~/react-native/reports/junit # Checks podspec - test-podspec: + test_podspec: <<: *defaults macos: xcode: "9.0" steps: - - checkout - - restore-cache: *restore-node-cache - - run: *install-node-dependencies - - save-cache: *save-node-cache + - attach_workspace: + at: ~/react-native + - run: ./scripts/process-podspecs.sh # Publishes new version onto npm - deploy: + publish_npm_package: <<: *android_defaults steps: - - checkout + - attach_workspace: + at: ~/react-native - # Configure Android dependencies + # Configure Android SDK and related dependencies - run: *configure-android-path - - run: *install-build-dependencies + - run: *install-android-build-dependencies - restore-cache: *restore-cache-android-packages - run: *install-android-packages - save-cache: *save-cache-android-packages + + # Install Android NDK - run: *create-ndk-directory - restore-cache: *restore-cache-ndk - run: *install-ndk - save-cache: *save-cache-ndk + + # Fetch dependencies using BUCK - 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 + - 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 @@ -317,6 +411,12 @@ jobs: - run: buck fetch ReactAndroid/src/androidTest/... - run: ./gradlew :ReactAndroid:downloadBoost :ReactAndroid:downloadDoubleConversion :ReactAndroid:downloadFolly :ReactAndroid:downloadGlog :ReactAndroid:downloadJSCHeaders + - run: *install-node + - run: *install-yarn + - restore-cache: *restore-yarn-cache + - run: *yarn + - save-cache: *save-yarn-cache + - run: name: Publish React Native Package command: | @@ -330,64 +430,37 @@ jobs: echo "Skipping deploy." fi - # Build JavaScript bundle for Android tests - build-js-bundle: - <<: *defaults - docker: - - image: circleci/node:8 - steps: - - checkout - - restore-cache: *restore-node-cache - - run: *install-node-dependencies - - save-cache: *save-node-cache - - run: - name: Build JavaScript Bundle - command: node local-cli/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 - - persist_to_workspace: - root: ReactAndroid/src/androidTest/assets/ - paths: - - AndroidTestBundle.js - - store_artifacts: - path: ReactAndroid/src/androidTest/assets/AndroidTestBundle.js - - # Runs unit tests tests on Android - test-android: + # Set up an Android environment for downstream jobs + test_android: <<: *android_defaults steps: - - checkout - - # Configure Android dependencies + - attach_workspace: + at: ~/react-native + + # Configure Android SDK and related dependencies - run: *configure-android-path - - run: *install-build-dependencies + - run: *install-android-build-dependencies - restore-cache: *restore-cache-android-packages - 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 - - run: - name: Launch Android Virtual Device in Background - command: source scripts/circle-ci-android-setup.sh && launchAVD - background: true - + - run: *create-avd + - run: *launch-avd + # Keep configuring Android dependencies while AVD boots up + + # Install Android NDK - run: *create-ndk-directory - restore-cache: *restore-cache-ndk - run: *install-ndk - save-cache: *save-cache-ndk + # Fetch dependencies using BUCK - 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 - - 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 @@ -395,53 +468,57 @@ jobs: - run: buck fetch ReactAndroid/src/androidTest/... - run: ./gradlew :ReactAndroid:downloadBoost :ReactAndroid:downloadDoubleConversion :ReactAndroid:downloadFolly :ReactAndroid:downloadGlog :ReactAndroid:downloadJSCHeaders + # Build and compile - run: *build-android-app - run: *compile-native-libs - # 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: *check-js-bundle + # Build JavaScript Bundle for instrumentation tests + - run: *install-node + - run: *build-js-bundle # Wait for AVD to finish booting before running tests - run: *wait-for-avd - # Tests + # Test Suite - run: *run-android-unit-tests - - run: *run-android-integration-tests + - run: *run-android-instrumentation-tests # post (always runs) - run: *collect-android-test-results - store_test_results: - path: ~/junit + path: ~/react-native/reports/junit - store_artifacts: - path: ~/junit + path: ~/react-native/reports/junit - analyze-pull-request: - <<: *defaults - docker: - - image: circleci/node:8 + + # 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: + <<: *js_defaults steps: - - checkout + - attach_workspace: + at: ~/react-native + - restore-cache: *restore-cache-analysis - - run: *install-node-dependencies + - run: *yarn - run: - name: Install Dependencies + name: Install Additional Dependencies command: | - if [ -n "$CIRCLE_PULL_REQUEST" ]; then - npm install github@0.2.4 - cd danger - npm install --no-package-lock --no-spin --no-progress + if [ -n "$CIRCLE_PR_NUMBER" ]; then + yarn add github@0.2.4 + cd bots + yarn install --non-interactive --cache-folder ~/.cache/yarn else echo "Skipping dependency installation." fi - save-cache: *save-cache-analysis + - run: name: Analyze Pull Request command: | - if [ -n "$CIRCLE_PULL_REQUEST" ]; then - cd danger && DANGER_GITHUB_API_TOKEN="e622517d9f1136ea8900""07c6373666312cdfaa69" npm run danger + if [ -n "$CIRCLE_PR_NUMBER" ]; then + cd bots && DANGER_GITHUB_API_TOKEN="e622517d9f1136ea8900""07c6373666312cdfaa69" yarn danger else echo "Skipping pull request analysis." fi @@ -449,52 +526,87 @@ jobs: - run: name: Analyze Code command: | - if [ -n "$CIRCLE_PULL_REQUEST" ]; then - cat <(echo eslint; npm run lint --silent -- --format=json; echo flow; npm run flow --silent -- check --json) | GITHUB_TOKEN="af6ef0d15709bc91d""06a6217a5a826a226fb57b7" CI_USER=$CIRCLE_PROJECT_USERNAME CI_REPO=$CIRCLE_PROJECT_REPONAME PULL_REQUEST_NUMBER=$CIRCLE_PR_NUMBER node bots/code-analysis-bot.js + if [ -n "$CIRCLE_PR_NUMBER" ]; then + cat <(echo eslint; yarn --silent lint --format=json; echo flow; yarn --silent flow check --json) | GITHUB_TOKEN="af6ef0d15709bc91d""06a6217a5a826a226fb57b7" CI_USER=$CIRCLE_PROJECT_USERNAME CI_REPO=$CIRCLE_PROJECT_REPONAME PULL_REQUEST_NUMBER=$CIRCLE_PR_NUMBER node bots/code-analysis-bot.js else echo "Skipping code analysis." fi when: always - + # Workflows enables us to run multiple jobs in parallel workflows: version: 2 - build: + test: jobs: + # Checkout repo and run Yarn + - checkout_code: + filters: *filter-ignore-gh-pages + # Run lint and flow checks - - run-js-checks: + - js_checks: filters: *filter-ignore-gh-pages + requires: + - checkout_code - # Test JavaScript on Node 8 and 6 - - test-js-node-8: + # Test JavaScript + - test_javascript: filters: *filter-ignore-gh-pages - - test-js-node-6: + requires: + - checkout_code + + # Test JavaScript using Node 6, the minimum supported version + - test_javascript_node6_compatibility: filters: *filter-ignore-gh-pages # Test Android - - build-js-bundle: + - test_android: filters: *filter-ignore-gh-pages - - test-android: requires: - - build-js-bundle + - checkout_code # Test iOS & tvOS - - test-objc-ios: + - test_objc_ios: filters: *filter-ignore-gh-pages - - test-objc-tvos: + requires: + - checkout_code + - test_objc_tvos: filters: *filter-ignore-gh-pages - - test-objc-e2e: + requires: + - checkout_code + + # End-to-end tests + - test_objc_ios_e2e: filters: *filter-ignore-gh-pages - - # If we are on a stable branch, deploy to `npm` - - hold: - type: approval - - deploy: - filters: *filter-only-stable requires: - - hold - - - analyze-pull-request: + - checkout_code + + # Only runs on PRs + analyze: + jobs: + # Checkout repo and run Yarn + - checkout_code: + filters: *filter-ignore-master-stable + + # Run code checks + - analyze_pr: filters: *filter-ignore-master-stable + requires: + - checkout_code + + # Only runs on NN-stable branches + deploy: + jobs: + # Checkout repo and run Yarn + - checkout_code: + filters: *filter-only-stable + + # If we are on a stable branch, wait for approval to deploy to npm + - approve_publish_npm_package: + filters: *filter-only-stable + type: approval + - publish_npm_package: + requires: + - checkout_code + - approve_publish_npm_package diff --git a/.eslintrc b/.eslintrc index 12076e6a13e34a..167d6a58776566 100644 --- a/.eslintrc +++ b/.eslintrc @@ -3,19 +3,17 @@ "parser": "babel-eslint", - "ecmaFeatures": { - "jsx": true - }, - "env": { "es6": true, - "jasmine": true, + "jest": true, }, "plugins": [ + "eslint-comments", "flowtype", "prettier", - "react" + "react", + "jest" ], // Map from global var to bool specifying if it can be redefined @@ -57,11 +55,6 @@ }, "rules": { - // Flow Plugin - // The following rules are made available via `eslint-plugin-flowtype` - "flowtype/define-flow-type": 1, - "flowtype/use-flow-type": 1, - // General // This must be disallowed in this repo because the minimum supported @@ -81,7 +74,7 @@ "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-keys": 1, // disallow duplicate keys when creating object literals + "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 @@ -95,7 +88,7 @@ "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": 1, // disallow unreachable statements after a return, throw, continue, or break statement + "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 @@ -116,7 +109,7 @@ "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": 1, // disallow use of eval() + "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 @@ -129,7 +122,7 @@ "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": 1, // disallow use of new operator for Function object + "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"; @@ -174,6 +167,18 @@ "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"], @@ -183,12 +188,12 @@ "key-spacing": 0, "keyword-spacing": 1, // enforce spacing before and after keywords - "jsx-quotes": [1, "prefer-double"], + "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, "self"], // enforces consistent naming when capturing the current execution context (off by default) + "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) @@ -196,6 +201,7 @@ "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 @@ -244,6 +250,13 @@ "react/prop-types": 0, "react/react-in-jsx-scope": 1, "react/self-closing-comp": 1, - "react/wrap-multilines": 0 + "react/wrap-multilines": 0, + + // 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, } } diff --git a/.flowconfig b/.flowconfig index f63fddf53a8f7a..735e7816a35829 100644 --- a/.flowconfig +++ b/.flowconfig @@ -6,7 +6,7 @@ .*/local-cli/templates/.* ; Ignore the Dangerfile -/danger/dangerfile.js +/bots/dangerfile.js ; Ignore "BUCK" generated dirs /\.buckd/ @@ -51,7 +51,5 @@ suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(\\)? *\\(site=[a-z,_]* suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError -unsafe.enable_getters_and_setters=true - [version] -^0.61.0 +^0.65.0 diff --git a/.gitignore b/.gitignore index 15a2a9668a1a9f..19c3bbdce24975 100644 --- a/.gitignore +++ b/.gitignore @@ -36,6 +36,9 @@ buck-out /ReactAndroid/src/main/jni/prebuilt/lib/x86/ /ReactAndroid/src/main/gen +# Watchman +.watchmanconfig + # Android .idea .gradle @@ -47,7 +50,11 @@ local.properties node_modules *.log .nvm -/danger/node_modules/ +/bots/node_modules/ + +# TODO: Check in yarn.lock in open source. Right now we need to keep it out +# from the GitHub repo as importing it might conflict with internal workspaces +*/**/yarn.lock # OS X .DS_Store diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 86206c295af7e5..34a94428f2542b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -14,7 +14,7 @@ There are many ways to contribute to React Native, and many of them do not invol * Simply start using React Native. Go through the [Getting Started](https://facebook.github.io/react-native/docs/getting-started.html) guide. Does everything work as expected? If not, we're always looking for improvements. Let us know by [opening an issue](https://facebook.github.io/react-native/docs/contributing.html#reporting-new-issues). * Look through the [open issues](https://github.com/facebook/react-native/issues). Provide workarounds, ask for clarification, or suggest labels. Help [triage issues](https://facebook.github.io/react-native/docs/contributing.html#triaging-issues-and-pull-requests). * If you find an issue you would like to fix, [open a pull request](https://facebook.github.io/react-native/docs/contributing.html#your-first-pull-request). Issues tagged as [_Good first issue_](https://github.com/facebook/react-native/labels/Good%20first%20issue) are a good place to get started. -* Read through the [React Native docs](https://facebook.github.io/react-native/docs/getting-started.html). If you find anything that is confusing or can be improved, you can make edits by clicking "Improve this page" at the bottom of most docs. +* Read through the [React Native docs](https://facebook.github.io/react-native/docs/getting-started.html). If you find anything that is confusing or can be improved, you can make edits by clicking the "EDIT" button in the top-right corner of most docs. * Browse [Stack Overflow](https://stackoverflow.com/questions/tagged/react-native) and answer questions. This will help you get familiarized with common pitfalls or misunderstandings, which can be useful when contributing updates to the documentation. * Take a look at the [features requested](https://react-native.canny.io/feature-requests) by others in the community and consider opening a pull request if you see something you want to work on. @@ -78,7 +78,7 @@ Working on your first Pull Request? You can learn how from this free video serie [**How to Contribute to an Open Source Project on GitHub**](https://egghead.io/courses/how-to-contribute-to-an-open-source-project-on-github) -We have a list of [beginner friendly issues](https://github.com/facebook/react-native/labels/Good%20First%20Task) to help you get your feet wet in the React Native codebase and familiar with our contribution process. This is a great place to get started. +We have a list of [beginner friendly issues](https://github.com/facebook/react-native/labels/Good%20first%20issue) to help you get your feet wet in the React Native codebase and familiar with our contribution process. This is a great place to get started. ### Proposing a change diff --git a/ContainerShip/scripts/run-android-ci-instrumentation-tests.js b/ContainerShip/scripts/run-android-ci-instrumentation-tests.js index 00a9f4955814db..34ee3336a168d2 100644 --- a/ContainerShip/scripts/run-android-ci-instrumentation-tests.js +++ b/ContainerShip/scripts/run-android-ci-instrumentation-tests.js @@ -20,7 +20,6 @@ * --package - com.facebook.react.tests * --retries [num] - how many times to retry possible flaky commands: npm install and running tests, default 1 */ -/*eslint-disable no-undef */ const argv = require('yargs').argv; const async = require('async'); diff --git a/IntegrationTests/ReactContentSizeUpdateTest.js b/IntegrationTests/ReactContentSizeUpdateTest.js index 07ae0ed661ce15..3524ef92ed385e 100644 --- a/IntegrationTests/ReactContentSizeUpdateTest.js +++ b/IntegrationTests/ReactContentSizeUpdateTest.js @@ -30,7 +30,7 @@ var ReactContentSizeUpdateTest = createReactClass({ mixins: [Subscribable.Mixin, TimerMixin], - componentWillMount: function() { + UNSAFE_componentWillMount: function() { this.addListenerOn( RCTNativeAppEventEmitter, 'rootViewDidChangeIntrinsicSize', diff --git a/IntegrationTests/SizeFlexibilityUpdateTest.js b/IntegrationTests/SizeFlexibilityUpdateTest.js index 5d580f8fc6a028..77895f40006498 100644 --- a/IntegrationTests/SizeFlexibilityUpdateTest.js +++ b/IntegrationTests/SizeFlexibilityUpdateTest.js @@ -27,7 +27,7 @@ var SizeFlexibilityUpdateTest = createReactClass({ displayName: 'SizeFlexibilityUpdateTest', mixins: [Subscribable.Mixin], - componentWillMount: function() { + UNSAFE_componentWillMount: function() { this.addListenerOn( RCTNativeAppEventEmitter, 'rootViewDidChangeIntrinsicSize', diff --git a/Libraries/Animated/src/__tests__/Animated-test.js b/Libraries/Animated/src/__tests__/Animated-test.js index 1ddbb38d559f06..c8f2b94223df26 100644 --- a/Libraries/Animated/src/__tests__/Animated-test.js +++ b/Libraries/Animated/src/__tests__/Animated-test.js @@ -94,11 +94,11 @@ describe('Animated tests', () => { opacity: anim, }, }; - c.componentWillMount(); + c.UNSAFE_componentWillMount(); expect(anim.__detach).not.toBeCalled(); c._component = {}; - c.componentWillReceiveProps({ + c.UNSAFE_componentWillReceiveProps({ style: { opacity: anim, }, @@ -120,7 +120,7 @@ describe('Animated tests', () => { opacity: anim, }, }; - c.componentWillMount(); + c.UNSAFE_componentWillMount(); Animated.timing(anim, {toValue: 10, duration: 1000}).start(callback); c._component = {}; diff --git a/Libraries/Animated/src/__tests__/AnimatedNative-test.js b/Libraries/Animated/src/__tests__/AnimatedNative-test.js index 9390830c4b36e0..d3f59368ea6098 100644 --- a/Libraries/Animated/src/__tests__/AnimatedNative-test.js +++ b/Libraries/Animated/src/__tests__/AnimatedNative-test.js @@ -29,7 +29,7 @@ const NativeAnimatedHelper = require('NativeAnimatedHelper'); function createAndMountComponent(ComponentClass, props) { const component = new ComponentClass(); component.props = props; - component.componentWillMount(); + component.UNSAFE_componentWillMount(); // Simulate that refs were set. component._component = {}; component.componentDidMount(); @@ -80,7 +80,7 @@ describe('Native Animated', () => { anim.setValue(0.5); - expect(nativeAnimatedModule.setAnimatedNodeValue).toBeCalledWith(jasmine.any(Number), 0.5); + expect(nativeAnimatedModule.setAnimatedNodeValue).toBeCalledWith(expect.any(Number), 0.5); expect(c.refs.node.setNativeProps).not.toHaveBeenCalled(); }); @@ -95,12 +95,12 @@ describe('Native Animated', () => { }); expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith( - jasmine.any(Number), + expect.any(Number), {type: 'value', value: 0, offset: 10}, ); anim.setOffset(20); expect(nativeAnimatedModule.setAnimatedNodeOffset) - .toBeCalledWith(jasmine.any(Number), 20); + .toBeCalledWith(expect.any(Number), 20); }); it('should flatten offset', () => { @@ -113,12 +113,12 @@ describe('Native Animated', () => { }); expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith( - jasmine.any(Number), + expect.any(Number), {type: 'value', value: 0, offset: 0}, ); anim.flattenOffset(); expect(nativeAnimatedModule.flattenAnimatedNodeOffset) - .toBeCalledWith(jasmine.any(Number)); + .toBeCalledWith(expect.any(Number)); }); it('should extract offset', () => { @@ -131,12 +131,12 @@ describe('Native Animated', () => { }); expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith( - jasmine.any(Number), + expect.any(Number), {type: 'value', value: 0, offset: 0}, ); anim.extractOffset(); expect(nativeAnimatedModule.extractAnimatedNodeOffset) - .toBeCalledWith(jasmine.any(Number)); + .toBeCalledWith(expect.any(Number)); }); }); @@ -214,14 +214,14 @@ describe('Native Animated', () => { ); const c = createAndMountComponent(Animated.View, {onTouchMove: event}); expect(nativeAnimatedModule.addAnimatedEventToView).toBeCalledWith( - jasmine.any(Number), + expect.any(Number), 'onTouchMove', {nativeEventPath: ['state', 'foo'], animatedValueTag: value.__getNativeTag()}, ); c.componentWillUnmount(); expect(nativeAnimatedModule.removeAnimatedEventFromView).toBeCalledWith( - jasmine.any(Number), + expect.any(Number), 'onTouchMove', value.__getNativeTag(), ); @@ -271,10 +271,10 @@ describe('Native Animated', () => { expect(nativeAnimatedModule.connectAnimatedNodes).toHaveBeenCalledTimes(2); expect(nativeAnimatedModule.startAnimatingNode).toBeCalledWith( - jasmine.any(Number), - jasmine.any(Number), - {type: 'frames', frames: jasmine.any(Array), toValue: jasmine.any(Number), iterations: 1}, - jasmine.any(Function) + expect.any(Number), + expect.any(Number), + {type: 'frames', frames: expect.any(Array), toValue: expect.any(Number), iterations: 1}, + expect.any(Function) ); expect(nativeAnimatedModule.disconnectAnimatedNodes).toHaveBeenCalledTimes(2); @@ -292,11 +292,11 @@ describe('Native Animated', () => { Animated.timing(anim, {toValue: 10, duration: 1000, useNativeDriver: true}).start(); expect(nativeAnimatedModule.createAnimatedNode) - .toBeCalledWith(jasmine.any(Number), {type: 'value', value: 0, offset: 0}); + .toBeCalledWith(expect.any(Number), {type: 'value', value: 0, offset: 0}); expect(nativeAnimatedModule.createAnimatedNode) - .toBeCalledWith(jasmine.any(Number), {type: 'style', style: {opacity: jasmine.any(Number)}}); + .toBeCalledWith(expect.any(Number), {type: 'style', style: {opacity: expect.any(Number)}}); expect(nativeAnimatedModule.createAnimatedNode) - .toBeCalledWith(jasmine.any(Number), {type: 'props', props: {style: jasmine.any(Number)}}); + .toBeCalledWith(expect.any(Number), {type: 'props', props: {style: expect.any(Number)}}); }); it('sends a valid graph description for Animated.add nodes', () => { @@ -312,8 +312,8 @@ describe('Native Animated', () => { }); expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith( - jasmine.any(Number), - {type: 'addition', input: jasmine.any(Array)}, + expect.any(Number), + {type: 'addition', input: expect.any(Array)}, ); const additionCalls = nativeAnimatedModule.createAnimatedNode.mock.calls.filter( (call) => call[1].type === 'addition' @@ -344,8 +344,8 @@ describe('Native Animated', () => { }); expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith( - jasmine.any(Number), - {type: 'multiplication', input: jasmine.any(Array)}, + expect.any(Number), + {type: 'multiplication', input: expect.any(Array)}, ); const multiplicationCalls = nativeAnimatedModule.createAnimatedNode.mock.calls.filter( (call) => call[1].type === 'multiplication' @@ -376,7 +376,7 @@ describe('Native Animated', () => { }); expect(nativeAnimatedModule.createAnimatedNode) - .toBeCalledWith(jasmine.any(Number), {type: 'division', input: jasmine.any(Array)}); + .toBeCalledWith(expect.any(Number), {type: 'division', input: expect.any(Array)}); const divisionCalls = nativeAnimatedModule.createAnimatedNode.mock.calls.filter( (call) => call[1].type === 'division' ); @@ -404,8 +404,8 @@ describe('Native Animated', () => { }); expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith( - jasmine.any(Number), - {type: 'modulus', modulus: 4, input: jasmine.any(Number)}, + expect.any(Number), + {type: 'modulus', modulus: 4, input: expect.any(Number)}, ); const moduloCalls = nativeAnimatedModule.createAnimatedNode.mock.calls.filter( (call) => call[1].type === 'modulus' @@ -435,11 +435,11 @@ describe('Native Animated', () => { }); expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith( - jasmine.any(Number), + expect.any(Number), {type: 'value', value: 10, offset: 0} ); expect(nativeAnimatedModule.createAnimatedNode) - .toBeCalledWith(jasmine.any(Number), { + .toBeCalledWith(expect.any(Number), { type: 'interpolation', inputRange: [10, 20], outputRange: [0, 1], @@ -466,11 +466,11 @@ describe('Native Animated', () => { }); expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith( - jasmine.any(Number), + expect.any(Number), { type: 'transform', transforms: [{ - nodeTag: jasmine.any(Number), + nodeTag: expect.any(Number), property: 'translateX', type: 'animated', }, { @@ -493,8 +493,8 @@ describe('Native Animated', () => { }); expect(nativeAnimatedModule.createAnimatedNode).toBeCalledWith( - jasmine.any(Number), - {type: 'diffclamp', input: jasmine.any(Number), max: 20, min: 0}, + expect.any(Number), + {type: 'diffclamp', input: expect.any(Number), max: 20, min: 0}, ); const diffClampCalls = nativeAnimatedModule.createAnimatedNode.mock.calls.filter( (call) => call[1].type === 'diffclamp' @@ -570,9 +570,9 @@ describe('Native Animated', () => { }); expect(nativeAnimatedModule.createAnimatedNode) - .toBeCalledWith(jasmine.any(Number), { type: 'style', style: { opacity: jasmine.any(Number) }}); + .toBeCalledWith(expect.any(Number), { type: 'style', style: { opacity: expect.any(Number) }}); expect(nativeAnimatedModule.createAnimatedNode) - .toBeCalledWith(jasmine.any(Number), { type: 'props', props: { style: jasmine.any(Number) }}); + .toBeCalledWith(expect.any(Number), { type: 'props', props: { style: expect.any(Number) }}); }); }); @@ -582,10 +582,10 @@ describe('Native Animated', () => { Animated.timing(anim, {toValue: 10, duration: 1000, useNativeDriver: true}).start(); expect(nativeAnimatedModule.startAnimatingNode).toBeCalledWith( - jasmine.any(Number), - jasmine.any(Number), - {type: 'frames', frames: jasmine.any(Array), toValue: jasmine.any(Number), iterations: 1}, - jasmine.any(Function) + expect.any(Number), + expect.any(Number), + {type: 'frames', frames: expect.any(Array), toValue: expect.any(Number), iterations: 1}, + expect.any(Function) ); }); @@ -593,8 +593,8 @@ describe('Native Animated', () => { const anim = new Animated.Value(0); Animated.spring(anim, {toValue: 10, friction: 5, tension: 164, useNativeDriver: true}).start(); expect(nativeAnimatedModule.startAnimatingNode).toBeCalledWith( - jasmine.any(Number), - jasmine.any(Number), + expect.any(Number), + expect.any(Number), { type: 'spring', stiffness: 679.08, @@ -607,7 +607,7 @@ describe('Native Animated', () => { toValue: 10, iterations: 1, }, - jasmine.any(Function) + expect.any(Function) ); Animated.spring(anim, { @@ -618,8 +618,8 @@ describe('Native Animated', () => { useNativeDriver: true }).start(); expect(nativeAnimatedModule.startAnimatingNode).toBeCalledWith( - jasmine.any(Number), - jasmine.any(Number), + expect.any(Number), + expect.any(Number), { type: 'spring', stiffness: 1000, @@ -632,13 +632,13 @@ describe('Native Animated', () => { toValue: 10, iterations: 1, }, - jasmine.any(Function) + expect.any(Function) ); Animated.spring(anim, {toValue: 10, bounciness: 8, speed: 10, useNativeDriver: true}).start(); expect(nativeAnimatedModule.startAnimatingNode).toBeCalledWith( - jasmine.any(Number), - jasmine.any(Number), + expect.any(Number), + expect.any(Number), { type: 'spring', damping: 23.05223140901191, @@ -651,7 +651,7 @@ describe('Native Animated', () => { toValue: 10, iterations: 1, }, - jasmine.any(Function) + expect.any(Function) ); }); @@ -660,10 +660,10 @@ describe('Native Animated', () => { Animated.decay(anim, {velocity: 10, deceleration: 0.1, useNativeDriver: true}).start(); expect(nativeAnimatedModule.startAnimatingNode).toBeCalledWith( - jasmine.any(Number), - jasmine.any(Number), + expect.any(Number), + expect.any(Number), {type: 'decay', deceleration: 0.1, velocity: 10, iterations: 1}, - jasmine.any(Function) + expect.any(Function) ); }); @@ -675,10 +675,10 @@ describe('Native Animated', () => { ).start(); expect(nativeAnimatedModule.startAnimatingNode).toBeCalledWith( - jasmine.any(Number), - jasmine.any(Number), + expect.any(Number), + expect.any(Number), {type: 'decay', deceleration: 0.1, velocity: 10, iterations: 10}, - jasmine.any(Function) + expect.any(Function) ); }); @@ -688,10 +688,10 @@ describe('Native Animated', () => { animation.start(); expect(nativeAnimatedModule.startAnimatingNode).toBeCalledWith( - jasmine.any(Number), - jasmine.any(Number), - {type: 'frames', frames: jasmine.any(Array), toValue: jasmine.any(Number), iterations: 1}, - jasmine.any(Function) + expect.any(Number), + expect.any(Number), + {type: 'frames', frames: expect.any(Array), toValue: expect.any(Number), iterations: 1}, + expect.any(Function) ); const animationId = nativeAnimatedModule.startAnimatingNode.mock.calls[0][0]; diff --git a/Libraries/Animated/src/__tests__/bezier-test.js b/Libraries/Animated/src/__tests__/bezier-test.js index a44b9be465ae38..3f1070a48fd71e 100644 --- a/Libraries/Animated/src/__tests__/bezier-test.js +++ b/Libraries/Animated/src/__tests__/bezier-test.js @@ -5,100 +5,132 @@ * @copyright 2014-2015 Gaetan Renaudeau. MIT License. * @noflow * @emails oncall+react_native + * @format */ -/* eslint-disable */ - 'use strict'; var bezier = require('bezier'); -var identity = function (x) { return x; }; +var identity = function(x) { + return x; +}; -function assertClose (a, b, precision = 3) { +function assertClose(a, b, precision = 3) { expect(a).toBeCloseTo(b, precision); } -function makeAssertCloseWithPrecision (precision) { - return function (a, b) { +function makeAssertCloseWithPrecision(precision) { + return function(a, b) { assertClose(a, b, precision); }; } -function allEquals (be1, be2, samples, assertion) { - if (!assertion) assertion = assertClose; - for (var i=0; i<=samples; ++i) { +function allEquals(be1, be2, samples, assertion) { + if (!assertion) { + assertion = assertClose; + } + for (var i = 0; i <= samples; ++i) { var x = i / samples; assertion(be1(x), be2(x)); } } -function repeat (n) { - return function (f) { - for (var i=0; i { - MessageQueueTestModule.testHook2 = jasmine.createSpy(); - expect(MessageQueueTestModule.testHook2.calls.count()).toEqual(0); + MessageQueueTestModule.testHook2 = jest.fn(); + expect(MessageQueueTestModule.testHook2.mock.calls.length).toEqual(0); queue.__callFunction('MessageQueueTestModule', 'testHook2', [2]); - expect(MessageQueueTestModule.testHook2.calls.count()).toEqual(1); + expect(MessageQueueTestModule.testHook2.mock.calls.length).toEqual(1); }); it('should store callbacks', () => { diff --git a/Libraries/BatchedBridge/__tests__/NativeModules-test.js b/Libraries/BatchedBridge/__tests__/NativeModules-test.js index 8abdf33cb28527..88435513e72966 100644 --- a/Libraries/BatchedBridge/__tests__/NativeModules-test.js +++ b/Libraries/BatchedBridge/__tests__/NativeModules-test.js @@ -57,8 +57,8 @@ describe('MessageQueue', function() { }); it('should make round trip and clear memory', function() { - const onFail = jasmine.createSpy(); - const onSucc = jasmine.createSpy(); + const onFail = jest.fn(); + const onSucc = jest.fn(); // Perform communication NativeModules.RemoteModule1.promiseMethod('paloAlto', 'menloPark', onFail, onSucc); @@ -98,8 +98,8 @@ describe('MessageQueue', function() { expect(function() { BatchedBridge.__invokeCallback(firstSuccCBID, ['firstSucc']); }).toThrow(); - expect(onFail.calls.count()).toBe(1); - expect(onSucc.calls.count()).toBe(0); + expect(onFail.mock.calls.length).toBe(1); + expect(onSucc.mock.calls.length).toBe(0); // Handle the second remote invocation by signaling success. BatchedBridge.__invokeCallback(secondSuccCBID, ['secondSucc']); @@ -107,7 +107,7 @@ describe('MessageQueue', function() { expect(function() { BatchedBridge.__invokeCallback(secondFailCBID, ['secondFail']); }).toThrow(); - expect(onFail.calls.count()).toBe(1); - expect(onSucc.calls.count()).toBe(1); + expect(onFail.mock.calls.length).toBe(1); + expect(onSucc.mock.calls.length).toBe(1); }); }); diff --git a/Libraries/Blob/Blob.js b/Libraries/Blob/Blob.js index 590f48fc50dcc3..3f077a05d71fc1 100644 --- a/Libraries/Blob/Blob.js +++ b/Libraries/Blob/Blob.js @@ -8,19 +8,12 @@ * * @providesModule Blob * @flow + * @format */ 'use strict'; -const invariant = require('fbjs/lib/invariant'); -/* $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 uuid = require('uuid'); - -const { BlobModule } = require('NativeModules'); - -import type { BlobProps } from 'BlobTypes'; +import type {BlobData, BlobOptions} from 'BlobTypes'; /** * Opaque JS representation of some binary data in native. @@ -60,51 +53,16 @@ import type { BlobProps } from 'BlobTypes'; * Reference: https://developer.mozilla.org/en-US/docs/Web/API/Blob */ class Blob { - /** - * Size of the data contained in the Blob object, in bytes. - */ - size: number; - /* - * String indicating the MIME type of the data contained in the Blob. - * If the type is unknown, this string is empty. - */ - type: string; - - /* - * Unique id to identify the blob on native side (non-standard) - */ - blobId: string; - /* - * Offset to indicate part of blob, used when sliced (non-standard) - */ - offset: number; - - /** - * Construct blob instance from blob data from native. - * Used internally by modules like XHR, WebSocket, etc. - */ - static create(props: BlobProps): Blob { - return Object.assign(Object.create(Blob.prototype), props); - } + _data: ?BlobData; /** * Constructor for JS consumers. * Currently we only support creating Blobs from other Blobs. * Reference: https://developer.mozilla.org/en-US/docs/Web/API/Blob/Blob */ - constructor(parts: Array, options: any) { - const blobId = uuid(); - let size = 0; - parts.forEach((part) => { - invariant(part instanceof Blob, 'Can currently only create a Blob from other Blobs'); - size += part.size; - }); - BlobModule.createFromParts(parts, blobId); - return Blob.create({ - blobId, - offset: 0, - size, - }); + constructor(parts: Array = [], options?: BlobOptions) { + const BlobManager = require('BlobManager'); + this.data = BlobManager.createFromParts(parts, options).data; } /* @@ -112,9 +70,22 @@ class Blob { * the data in the specified range of bytes of the source Blob. * Reference: https://developer.mozilla.org/en-US/docs/Web/API/Blob/slice */ + set data(data: ?BlobData) { + this._data = data; + } + + get data(): BlobData { + if (!this._data) { + throw new Error('Blob has been closed and is no longer available'); + } + + return this._data; + } + slice(start?: number, end?: number): Blob { - let offset = this.offset; - let size = this.size; + const BlobManager = require('BlobManager'); + let {offset, size} = this.data; + if (typeof start === 'number') { if (start > size) { start = size; @@ -129,8 +100,8 @@ class Blob { size = end - start; } } - return Blob.create({ - blobId: this.blobId, + return BlobManager.createFromOptions({ + blobId: this.data.blobId, offset, size, }); @@ -149,7 +120,24 @@ class Blob { * `new Blob([blob, ...])` actually copies the data in memory. */ close() { - BlobModule.release(this.blobId); + const BlobManager = require('BlobManager'); + BlobManager.release(this.data.blobId); + this.data = null; + } + + /** + * Size of the data contained in the Blob object, in bytes. + */ + get size(): number { + return this.data.size; + } + + /* + * String indicating the MIME type of the data contained in the Blob. + * If the type is unknown, this string is empty. + */ + get type(): string { + return this.data.type || ''; } } diff --git a/Libraries/Blob/BlobManager.js b/Libraries/Blob/BlobManager.js new file mode 100644 index 00000000000000..a1cf9b489e6007 --- /dev/null +++ b/Libraries/Blob/BlobManager.js @@ -0,0 +1,146 @@ +/** + * 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. + * + * @providesModule BlobManager + * @flow + * @format + */ + +'use strict'; + +const Blob = require('Blob'); +const BlobRegistry = require('BlobRegistry'); +const {BlobModule} = require('NativeModules'); + +import type {BlobData, BlobOptions} from 'BlobTypes'; + +/*eslint-disable no-bitwise */ +/*eslint-disable eqeqeq */ + +/** + * Based on the rfc4122-compliant solution posted at + * http://stackoverflow.com/questions/105034 + */ +function uuidv4(): string { + return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => { + const r = (Math.random() * 16) | 0, + v = c == 'x' ? r : (r & 0x3) | 0x8; + return v.toString(16); + }); +} + +/** + * Module to manage blobs. Wrapper around the native blob module. + */ +class BlobManager { + /** + * If the native blob module is available. + */ + static isAvailable = !!BlobModule; + + /** + * Create blob from existing array of blobs. + */ + static createFromParts( + parts: Array, + options?: BlobOptions, + ): Blob { + const blobId = uuidv4(); + const items = parts.map(part => { + if ( + part instanceof ArrayBuffer || + (global.ArrayBufferView && part instanceof global.ArrayBufferView) + ) { + throw new Error( + "Creating blobs from 'ArrayBuffer' and 'ArrayBufferView' are not supported", + ); + } + if (part instanceof Blob) { + return { + data: part.data, + type: 'blob', + }; + } else { + return { + data: String(part), + type: 'string', + }; + } + }); + const size = items.reduce((acc, curr) => { + if (curr.type === 'string') { + return acc + global.unescape(encodeURI(curr.data)).length; + } else { + return acc + curr.data.size; + } + }, 0); + + BlobModule.createFromParts(items, blobId); + + return BlobManager.createFromOptions({ + blobId, + offset: 0, + size, + type: options ? options.type : '', + lastModified: options ? options.lastModified : Date.now(), + }); + } + + /** + * Create blob instance from blob data from native. + * Used internally by modules like XHR, WebSocket, etc. + */ + static createFromOptions(options: BlobData): Blob { + BlobRegistry.register(options.blobId); + return Object.assign(Object.create(Blob.prototype), {data: options}); + } + + /** + * Deallocate resources for a blob. + */ + static release(blobId: string): void { + BlobRegistry.unregister(blobId); + if (BlobRegistry.has(blobId)) { + return; + } + BlobModule.release(blobId); + } + + /** + * Inject the blob content handler in the networking module to support blob + * requests and responses. + */ + static addNetworkingHandler(): void { + BlobModule.addNetworkingHandler(); + } + + /** + * Indicate the websocket should return a blob for incoming binary + * messages. + */ + static addWebSocketHandler(socketId: number): void { + BlobModule.addWebSocketHandler(socketId); + } + + /** + * Indicate the websocket should no longer return a blob for incoming + * binary messages. + */ + static removeWebSocketHandler(socketId: number): void { + BlobModule.removeWebSocketHandler(socketId); + } + + /** + * Send a blob message to a websocket. + */ + static sendOverSocket(blob: Blob, socketId: number): void { + BlobModule.sendOverSocket(blob.data, socketId); + } +} + +module.exports = BlobManager; diff --git a/Libraries/Blob/BlobRegistry.js b/Libraries/Blob/BlobRegistry.js new file mode 100644 index 00000000000000..925e78f3a78453 --- /dev/null +++ b/Libraries/Blob/BlobRegistry.js @@ -0,0 +1,41 @@ +/** + * 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. + * + * @providesModule BlobRegistry + * @flow + * @format + */ + +const registry: {[key: string]: number} = {}; + +const register = (id: string) => { + if (registry[id]) { + registry[id]++; + } else { + registry[id] = 1; + } +}; + +const unregister = (id: string) => { + if (registry[id]) { + registry[id]--; + if (registry[id] <= 0) { + delete registry[id]; + } + } +}; + +const has = (id: string) => { + return registry[id] && registry[id] > 0; +}; + +module.exports = { + register, + unregister, + has, +}; diff --git a/Libraries/Blob/BlobTypes.js b/Libraries/Blob/BlobTypes.js index 8201df47bc306f..c053c08cfc8deb 100644 --- a/Libraries/Blob/BlobTypes.js +++ b/Libraries/Blob/BlobTypes.js @@ -8,18 +8,21 @@ * * @providesModule BlobTypes * @flow + * @format */ 'use strict'; -export type BlobProps = { +export type BlobData = { blobId: string, offset: number, size: number, + name?: string, type?: string, + lastModified?: number, }; -export type FileProps = BlobProps & { - name: string, +export type BlobOptions = { + type: string, lastModified: number, }; diff --git a/Libraries/Blob/File.js b/Libraries/Blob/File.js new file mode 100644 index 00000000000000..8e999b20f41dd0 --- /dev/null +++ b/Libraries/Blob/File.js @@ -0,0 +1,58 @@ +/** + * 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. + * + * @providesModule File + * @flow + * @format + */ +'use strict'; + +const Blob = require('Blob'); + +const invariant = require('fbjs/lib/invariant'); + +import type {BlobOptions} from 'BlobTypes'; + +/** + * The File interface provides information about files. + */ +class File extends Blob { + /** + * Constructor for JS consumers. + */ + constructor( + parts: Array, + name: string, + options?: BlobOptions, + ) { + invariant( + parts != null && name != null, + 'Failed to construct `File`: Must pass both `parts` and `name` arguments.', + ); + + super(parts, options); + this.data.name = name; + } + + /** + * Name of the file. + */ + get name(): string { + invariant(this.data.name != null, 'Files must have a name set.'); + return this.data.name; + } + + /* + * Last modified time of the file. + */ + get lastModified(): number { + return this.data.lastModified || 0; + } +} + +module.exports = File; diff --git a/Libraries/Blob/FileReader.js b/Libraries/Blob/FileReader.js new file mode 100644 index 00000000000000..121f7ef76caa21 --- /dev/null +++ b/Libraries/Blob/FileReader.js @@ -0,0 +1,156 @@ +/** + * 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. + * + * @providesModule FileReader + * @flow + * @format + */ + +'use strict'; + +const EventTarget = require('event-target-shim'); +const Blob = require('Blob'); +const {FileReaderModule} = require('NativeModules'); + +type ReadyState = + | 0 // EMPTY + | 1 // LOADING + | 2; // DONE + +type ReaderResult = string | ArrayBuffer; + +const READER_EVENTS = [ + 'abort', + 'error', + 'load', + 'loadstart', + 'loadend', + 'progress', +]; + +const EMPTY = 0; +const LOADING = 1; +const DONE = 2; + +class FileReader extends EventTarget(...READER_EVENTS) { + static EMPTY = EMPTY; + static LOADING = LOADING; + static DONE = DONE; + + EMPTY = EMPTY; + LOADING = LOADING; + DONE = DONE; + + _readyState: ReadyState; + _error: ?Error; + _result: ?ReaderResult; + _aborted: boolean = false; + _subscriptions: Array<*> = []; + + constructor() { + super(); + this._reset(); + } + + _reset(): void { + this._readyState = EMPTY; + this._error = null; + this._result = null; + } + + _clearSubscriptions(): void { + this._subscriptions.forEach(sub => sub.remove()); + this._subscriptions = []; + } + + _setReadyState(newState: ReadyState) { + this._readyState = newState; + this.dispatchEvent({type: 'readystatechange'}); + if (newState === DONE) { + if (this._aborted) { + this.dispatchEvent({type: 'abort'}); + } else if (this._error) { + this.dispatchEvent({type: 'error'}); + } else { + this.dispatchEvent({type: 'load'}); + } + this.dispatchEvent({type: 'loadend'}); + } + } + + readAsArrayBuffer() { + throw new Error('FileReader.readAsArrayBuffer is not implemented'); + } + + readAsDataURL(blob: Blob) { + this._aborted = false; + + FileReaderModule.readAsDataURL(blob.data).then( + (text: string) => { + if (this._aborted) { + return; + } + this._result = text; + this._setReadyState(DONE); + }, + error => { + if (this._aborted) { + return; + } + this._error = error; + this._setReadyState(DONE); + }, + ); + } + + readAsText(blob: Blob, encoding: string = 'UTF-8') { + this._aborted = false; + + FileReaderModule.readAsText(blob.data, encoding).then( + (text: string) => { + if (this._aborted) { + return; + } + this._result = text; + this._setReadyState(DONE); + }, + error => { + if (this._aborted) { + return; + } + this._error = error; + this._setReadyState(DONE); + }, + ); + } + + abort() { + this._aborted = true; + // only call onreadystatechange if there is something to abort, as per spec + if (this._readyState !== EMPTY && this._readyState !== DONE) { + this._reset(); + this._setReadyState(DONE); + } + // Reset again after, in case modified in handler + this._reset(); + } + + get readyState(): ReadyState { + return this._readyState; + } + + get error(): ?Error { + return this._error; + } + + get result(): ?ReaderResult { + return this._result; + } +} + +module.exports = FileReader; diff --git a/Libraries/Blob/RCTBlob.xcodeproj/project.pbxproj b/Libraries/Blob/RCTBlob.xcodeproj/project.pbxproj index bb5944caae6ad0..2ffded6f074d39 100755 --- a/Libraries/Blob/RCTBlob.xcodeproj/project.pbxproj +++ b/Libraries/Blob/RCTBlob.xcodeproj/project.pbxproj @@ -7,12 +7,18 @@ objects = { /* Begin PBXBuildFile section */ + 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 */; }; 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 */; }; AD08711A1E2162C8007D136D /* RCTBlobManager.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = AD9A43C11DFC7126008DC588 /* RCTBlobManager.h */; }; - AD9A43C31DFC7126008DC588 /* RCTBlobManager.m in Sources */ = {isa = PBXBuildFile; fileRef = AD9A43C21DFC7126008DC588 /* RCTBlobManager.m */; }; - ADD01A711E09404A00F6D226 /* RCTBlobManager.m in Sources */ = {isa = PBXBuildFile; fileRef = AD9A43C21DFC7126008DC588 /* RCTBlobManager.m */; }; + AD9A43C31DFC7126008DC588 /* RCTBlobManager.mm in Sources */ = {isa = PBXBuildFile; fileRef = AD9A43C21DFC7126008DC588 /* RCTBlobManager.mm */; }; + ADD01A711E09404A00F6D226 /* RCTBlobManager.mm in Sources */ = {isa = PBXBuildFile; fileRef = AD9A43C21DFC7126008DC588 /* RCTBlobManager.mm */; }; + ADDFBA6C1F33455F0064C998 /* RCTFileReaderModule.h in Headers */ = {isa = PBXBuildFile; fileRef = ADDFBA6A1F33455F0064C998 /* RCTFileReaderModule.h */; }; + ADDFBA6D1F33455F0064C998 /* RCTFileReaderModule.m in Sources */ = {isa = PBXBuildFile; fileRef = ADDFBA6B1F33455F0064C998 /* RCTFileReaderModule.m */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -22,6 +28,7 @@ dstPath = include/RCTBlob; dstSubfolderSpec = 16; files = ( + 19BA88FE1F84391700741C5A /* RCTFileReaderModule.h in Copy Headers */, AD08711A1E2162C8007D136D /* RCTBlobManager.h in Copy Headers */, ); name = "Copy Headers"; @@ -33,6 +40,7 @@ dstPath = include/RCTBlob; dstSubfolderSpec = 16; files = ( + 19BA89001F84392F00741C5A /* RCTFileReaderModule.h in Copy Headers */, AD0871131E215B28007D136D /* RCTBlobManager.h in Copy Headers */, ); name = "Copy Headers"; @@ -42,17 +50,21 @@ /* Begin PBXFileReference section */ 358F4ED71D1E81A9004DF814 /* libRCTBlob.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRCTBlob.a; sourceTree = BUILT_PRODUCTS_DIR; }; - AD9A43C11DFC7126008DC588 /* RCTBlobManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTBlobManager.h; sourceTree = ""; }; - AD9A43C21DFC7126008DC588 /* RCTBlobManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTBlobManager.m; sourceTree = ""; }; + AD9A43C11DFC7126008DC588 /* RCTBlobManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = RCTBlobManager.h; sourceTree = ""; }; + AD9A43C21DFC7126008DC588 /* RCTBlobManager.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = RCTBlobManager.mm; sourceTree = ""; }; ADD01A681E09402E00F6D226 /* libRCTBlob-tvOS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libRCTBlob-tvOS.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + ADDFBA6A1F33455F0064C998 /* RCTFileReaderModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = RCTFileReaderModule.h; sourceTree = ""; }; + ADDFBA6B1F33455F0064C998 /* RCTFileReaderModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTFileReaderModule.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXGroup section */ 358F4ECE1D1E81A9004DF814 = { isa = PBXGroup; children = ( + ADDFBA6A1F33455F0064C998 /* RCTFileReaderModule.h */, + ADDFBA6B1F33455F0064C998 /* RCTFileReaderModule.m */, AD9A43C11DFC7126008DC588 /* RCTBlobManager.h */, - AD9A43C21DFC7126008DC588 /* RCTBlobManager.m */, + AD9A43C21DFC7126008DC588 /* RCTBlobManager.mm */, 358F4ED81D1E81A9004DF814 /* Products */, ); indentWidth = 2; @@ -77,6 +89,7 @@ buildActionMask = 2147483647; files = ( AD0871161E215EC9007D136D /* RCTBlobManager.h in Headers */, + ADDFBA6C1F33455F0064C998 /* RCTFileReaderModule.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -84,6 +97,7 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + 19BA88FF1F84392900741C5A /* RCTFileReaderModule.h in Headers */, AD0871181E215ED1007D136D /* RCTBlobManager.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; @@ -132,7 +146,7 @@ isa = PBXProject; attributes = { LastUpgradeCheck = 0730; - ORGANIZATIONNAME = "Silk Labs"; + ORGANIZATIONNAME = Facebook; TargetAttributes = { 358F4ED61D1E81A9004DF814 = { CreatedOnToolsVersion = 7.3; @@ -166,7 +180,8 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - AD9A43C31DFC7126008DC588 /* RCTBlobManager.m in Sources */, + ADDFBA6D1F33455F0064C998 /* RCTFileReaderModule.m in Sources */, + AD9A43C31DFC7126008DC588 /* RCTBlobManager.mm in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -174,7 +189,8 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - ADD01A711E09404A00F6D226 /* RCTBlobManager.m in Sources */, + 19BA89011F84393D00741C5A /* RCTFileReaderModule.m in Sources */, + ADD01A711E09404A00F6D226 /* RCTBlobManager.mm in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Libraries/Blob/RCTBlobManager.h b/Libraries/Blob/RCTBlobManager.h index 03b3ffc60a6fb4..8e8d355f60b7ac 100755 --- a/Libraries/Blob/RCTBlobManager.h +++ b/Libraries/Blob/RCTBlobManager.h @@ -13,4 +13,18 @@ @interface RCTBlobManager : NSObject +- (NSString *)store:(NSData *)data; + +- (void)store:(NSData *)data withId:(NSString *)blobId; + +- (NSData *)resolve:(NSDictionary *)blob; + +- (NSData *)resolve:(NSString *)blobId offset:(NSInteger)offset size:(NSInteger)size; + +- (NSData *)resolveURL:(NSURL *)url; + +- (void)remove:(NSString *)blobId; + +- (void)createFromParts:(NSArray *> *)parts withId:(NSString *)blobId; + @end diff --git a/Libraries/Blob/RCTBlobManager.m b/Libraries/Blob/RCTBlobManager.m deleted file mode 100755 index d556d634a1c7ff..00000000000000 --- a/Libraries/Blob/RCTBlobManager.m +++ /dev/null @@ -1,218 +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. - */ - -#import "RCTBlobManager.h" - -#import -#import - -static NSString *const kBlobUriScheme = @"blob"; - -@interface _RCTBlobContentHandler : NSObject - -- (instancetype)initWithBlobManager:(RCTBlobManager *)blobManager; - -@end - - -@implementation RCTBlobManager -{ - NSMutableDictionary *_blobs; - _RCTBlobContentHandler *_contentHandler; - NSOperationQueue *_queue; -} - -RCT_EXPORT_MODULE(BlobModule) - -@synthesize bridge = _bridge; - -+ (BOOL)requiresMainQueueSetup -{ - return NO; -} - -- (NSDictionary *)constantsToExport -{ - return @{ - @"BLOB_URI_SCHEME": kBlobUriScheme, - @"BLOB_URI_HOST": [NSNull null], - }; -} - -- (dispatch_queue_t)methodQueue -{ - return [[_bridge webSocketModule] methodQueue]; -} - -- (NSString *)store:(NSData *)data -{ - NSString *blobId = [NSUUID UUID].UUIDString; - [self store:data withId:blobId]; - return blobId; -} - -- (void)store:(NSData *)data withId:(NSString *)blobId -{ - if (!_blobs) { - _blobs = [NSMutableDictionary new]; - } - - _blobs[blobId] = data; -} - -- (NSData *)resolve:(NSDictionary *)blob -{ - NSString *blobId = [RCTConvert NSString:blob[@"blobId"]]; - NSNumber *offset = [RCTConvert NSNumber:blob[@"offset"]]; - NSNumber *size = [RCTConvert NSNumber:blob[@"size"]]; - - return [self resolve:blobId - offset:offset ? [offset integerValue] : 0 - size:size ? [size integerValue] : -1]; -} - -- (NSData *)resolve:(NSString *)blobId offset:(NSInteger)offset size:(NSInteger)size -{ - NSData *data = _blobs[blobId]; - if (!data) { - return nil; - } - if (offset != 0 || (size != -1 && size != data.length)) { - data = [data subdataWithRange:NSMakeRange(offset, size)]; - } - return data; -} - -RCT_EXPORT_METHOD(enableBlobSupport:(nonnull NSNumber *)socketID) -{ - if (!_contentHandler) { - _contentHandler = [[_RCTBlobContentHandler alloc] initWithBlobManager:self]; - } - [[_bridge webSocketModule] setContentHandler:_contentHandler forSocketID:socketID]; -} - -RCT_EXPORT_METHOD(disableBlobSupport:(nonnull NSNumber *)socketID) -{ - [[_bridge webSocketModule] setContentHandler:nil forSocketID:socketID]; -} - -RCT_EXPORT_METHOD(sendBlob:(NSDictionary *)blob socketID:(nonnull NSNumber *)socketID) -{ - [[_bridge webSocketModule] sendData:[self resolve:blob] forSocketID:socketID]; -} - -RCT_EXPORT_METHOD(createFromParts:(NSArray *> *)parts withId:(NSString *)blobId) -{ - NSMutableData *data = [NSMutableData new]; - for (NSDictionary *part in parts) { - NSData *partData = [self resolve:part]; - [data appendData:partData]; - } - [self store:data withId:blobId]; -} - -RCT_EXPORT_METHOD(release:(NSString *)blobId) -{ - [_blobs removeObjectForKey:blobId]; -} - -#pragma mark - RCTURLRequestHandler methods - -- (BOOL)canHandleRequest:(NSURLRequest *)request -{ - return [request.URL.scheme caseInsensitiveCompare:kBlobUriScheme] == NSOrderedSame; -} - -- (id)sendRequest:(NSURLRequest *)request withDelegate:(id)delegate -{ - // Lazy setup - if (!_queue) { - _queue = [NSOperationQueue new]; - _queue.maxConcurrentOperationCount = 2; - } - - __weak __block NSBlockOperation *weakOp; - __block NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{ - NSURLResponse *response = [[NSURLResponse alloc] initWithURL:request.URL - MIMEType:nil - expectedContentLength:-1 - textEncodingName:nil]; - - [delegate URLRequest:weakOp didReceiveResponse:response]; - - NSURLComponents *components = [[NSURLComponents alloc] initWithURL:request.URL resolvingAgainstBaseURL:NO]; - - NSString *blobId = components.path; - NSInteger offset = 0; - NSInteger size = -1; - - if (components.queryItems) { - for (NSURLQueryItem *queryItem in components.queryItems) { - if ([queryItem.name isEqualToString:@"offset"]) { - offset = [queryItem.value integerValue]; - } - if ([queryItem.name isEqualToString:@"size"]) { - size = [queryItem.value integerValue]; - } - } - } - - NSData *data; - if (blobId) { - data = [self resolve:blobId offset:offset size:size]; - } - NSError *error; - if (data) { - [delegate URLRequest:weakOp didReceiveData:data]; - } else { - error = [[NSError alloc] initWithDomain:NSURLErrorDomain code:NSURLErrorBadURL userInfo:nil]; - } - [delegate URLRequest:weakOp didCompleteWithError:error]; - }]; - - weakOp = op; - [_queue addOperation:op]; - return op; -} - -- (void)cancelRequest:(NSOperation *)op -{ - [op cancel]; -} - -@end - -@implementation _RCTBlobContentHandler { - __weak RCTBlobManager *_blobManager; -} - -- (instancetype)initWithBlobManager:(RCTBlobManager *)blobManager -{ - if (self = [super init]) { - _blobManager = blobManager; - } - return self; -} - -- (id)processMessage:(id)message forSocketID:(NSNumber *)socketID withType:(NSString *__autoreleasing _Nonnull *)type -{ - if (![message isKindOfClass:[NSData class]]) { - *type = @"text"; - return message; - } - - *type = @"blob"; - return @{ - @"blobId": [_blobManager store:message], - @"offset": @0, - @"size": @(((NSData *)message).length), - }; -} - -@end diff --git a/Libraries/Blob/RCTBlobManager.mm b/Libraries/Blob/RCTBlobManager.mm new file mode 100755 index 00000000000000..aa45072553dcbe --- /dev/null +++ b/Libraries/Blob/RCTBlobManager.mm @@ -0,0 +1,291 @@ +/** + * 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. + */ + +#import "RCTBlobManager.h" + +#import + +#import +#import +#import +#import + +static NSString *const kBlobURIScheme = @"blob"; + +@interface RCTBlobManager () + +@end + +@implementation RCTBlobManager +{ + // Blobs should be thread safe since they are used from the websocket and networking module, + // make sure to use proper locking when accessing this. + NSMutableDictionary *_blobs; + std::mutex _blobsMutex; + + NSOperationQueue *_queue; +} + +RCT_EXPORT_MODULE(BlobModule) + +@synthesize bridge = _bridge; + +- (void)setBridge:(RCTBridge *)bridge +{ + _bridge = bridge; + + std::lock_guard lock(_blobsMutex); + _blobs = [NSMutableDictionary new]; +} + ++ (BOOL)requiresMainQueueSetup +{ + return NO; +} + +- (NSDictionary *)constantsToExport +{ + return @{ + @"BLOB_URI_SCHEME": kBlobURIScheme, + @"BLOB_URI_HOST": [NSNull null], + }; +} + +- (NSString *)store:(NSData *)data +{ + NSString *blobId = [NSUUID UUID].UUIDString; + [self store:data withId:blobId]; + return blobId; +} + +- (void)store:(NSData *)data withId:(NSString *)blobId +{ + std::lock_guard lock(_blobsMutex); + _blobs[blobId] = data; +} + +- (NSData *)resolve:(NSDictionary *)blob +{ + NSString *blobId = [RCTConvert NSString:blob[@"blobId"]]; + NSNumber *offset = [RCTConvert NSNumber:blob[@"offset"]]; + NSNumber *size = [RCTConvert NSNumber:blob[@"size"]]; + return [self resolve:blobId + offset:offset ? [offset integerValue] : 0 + size:size ? [size integerValue] : -1]; +} + +- (NSData *)resolve:(NSString *)blobId offset:(NSInteger)offset size:(NSInteger)size +{ + NSData *data; + { + std::lock_guard lock(_blobsMutex); + data = _blobs[blobId]; + } + if (!data) { + return nil; + } + if (offset != 0 || (size != -1 && size != data.length)) { + data = [data subdataWithRange:NSMakeRange(offset, size)]; + } + return data; +} + +- (NSData *)resolveURL:(NSURL *)url +{ + NSURLComponents *components = [[NSURLComponents alloc] initWithURL:url resolvingAgainstBaseURL:NO]; + + NSString *blobId = components.path; + NSInteger offset = 0; + NSInteger size = -1; + + if (components.queryItems) { + for (NSURLQueryItem *queryItem in components.queryItems) { + if ([queryItem.name isEqualToString:@"offset"]) { + offset = [queryItem.value integerValue]; + } + if ([queryItem.name isEqualToString:@"size"]) { + size = [queryItem.value integerValue]; + } + } + } + + if (blobId) { + return [self resolve:blobId offset:offset size:size]; + } + return nil; +} + +- (void)remove:(NSString *)blobId +{ + std::lock_guard lock(_blobsMutex); + [_blobs removeObjectForKey:blobId]; +} + +RCT_EXPORT_METHOD(addNetworkingHandler) +{ + dispatch_async(_bridge.networking.methodQueue, ^{ + [self->_bridge.networking addRequestHandler:self]; + [self->_bridge.networking addResponseHandler:self]; + }); +} + +RCT_EXPORT_METHOD(addWebSocketHandler:(nonnull NSNumber *)socketID) +{ + dispatch_async(_bridge.webSocketModule.methodQueue, ^{ + [self->_bridge.webSocketModule setContentHandler:self forSocketID:socketID]; + }); +} + +RCT_EXPORT_METHOD(removeWebSocketHandler:(nonnull NSNumber *)socketID) +{ + dispatch_async(_bridge.webSocketModule.methodQueue, ^{ + [self->_bridge.webSocketModule setContentHandler:nil forSocketID:socketID]; + }); +} + +// @lint-ignore FBOBJCUNTYPEDCOLLECTION1 +RCT_EXPORT_METHOD(sendOverSocket:(NSDictionary *)blob socketID:(nonnull NSNumber *)socketID) +{ + dispatch_async(_bridge.webSocketModule.methodQueue, ^{ + [self->_bridge.webSocketModule sendData:[self resolve:blob] forSocketID:socketID]; + }); +} + +RCT_EXPORT_METHOD(createFromParts:(NSArray *> *)parts withId:(NSString *)blobId) +{ + NSMutableData *data = [NSMutableData new]; + for (NSDictionary *part in parts) { + NSString *type = [RCTConvert NSString:part[@"type"]]; + + if ([type isEqualToString:@"blob"]) { + NSData *partData = [self resolve:part[@"data"]]; + [data appendData:partData]; + } else if ([type isEqualToString:@"string"]) { + NSData *partData = [[RCTConvert NSString:part[@"data"]] dataUsingEncoding:NSUTF8StringEncoding]; + [data appendData:partData]; + } else { + [NSException raise:@"Invalid type for blob" format:@"%@ is invalid", type]; + } + } + [self store:data withId:blobId]; +} + +RCT_EXPORT_METHOD(release:(NSString *)blobId) +{ + [self remove:blobId]; +} + +#pragma mark - RCTURLRequestHandler methods + +- (BOOL)canHandleRequest:(NSURLRequest *)request +{ + return [request.URL.scheme caseInsensitiveCompare:kBlobURIScheme] == NSOrderedSame; +} + +- (id)sendRequest:(NSURLRequest *)request withDelegate:(id)delegate +{ + // Lazy setup + if (!_queue) { + _queue = [NSOperationQueue new]; + _queue.maxConcurrentOperationCount = 2; + } + + __weak __typeof(self) weakSelf = self; + __weak __block NSBlockOperation *weakOp; + __block NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{ + __typeof(self) strongSelf = weakSelf; + if (!strongSelf) { + return; + } + NSURLResponse *response = [[NSURLResponse alloc] initWithURL:request.URL + MIMEType:nil + expectedContentLength:-1 + textEncodingName:nil]; + + [delegate URLRequest:weakOp didReceiveResponse:response]; + + NSData *data = [strongSelf resolveURL:response.URL]; + NSError *error; + if (data) { + [delegate URLRequest:weakOp didReceiveData:data]; + } else { + error = [[NSError alloc] initWithDomain:NSURLErrorDomain code:NSURLErrorBadURL userInfo:nil]; + } + [delegate URLRequest:weakOp didCompleteWithError:error]; + }]; + + weakOp = op; + [_queue addOperation:op]; + return op; +} + +- (void)cancelRequest:(NSOperation *)op +{ + [op cancel]; +} + +#pragma mark - RCTNetworkingRequestHandler methods + +// @lint-ignore FBOBJCUNTYPEDCOLLECTION1 +- (BOOL)canHandleNetworkingRequest:(NSDictionary *)data +{ + return data[@"blob"] != nil; +} + +// @lint-ignore FBOBJCUNTYPEDCOLLECTION1 +- (NSDictionary *)handleNetworkingRequest:(NSDictionary *)data +{ + // @lint-ignore FBOBJCUNTYPEDCOLLECTION1 + NSDictionary *blob = [RCTConvert NSDictionary:data[@"blob"]]; + + NSString *contentType = @"application/octet-stream"; + NSString *blobType = [RCTConvert NSString:blob[@"type"]]; + if (blobType != nil && blobType.length > 0) { + contentType = blob[@"type"]; + } + + return @{@"body": [self resolve:blob], @"contentType": contentType}; +} + +- (BOOL)canHandleNetworkingResponse:(NSString *)responseType +{ + return [responseType isEqualToString:@"blob"]; +} + +- (id)handleNetworkingResponse:(NSURLResponse *)response data:(NSData *)data +{ + return @{ + @"blobId": [self store:data], + @"offset": @0, + @"size": @(data.length), + @"name": RCTNullIfNil([response suggestedFilename]), + @"type": RCTNullIfNil([response MIMEType]), + }; +} + +#pragma mark - RCTWebSocketContentHandler methods + +- (id)processWebsocketMessage:(id)message + forSocketID:(NSNumber *)socketID + withType:(NSString *__autoreleasing _Nonnull *)type +{ + if (![message isKindOfClass:[NSData class]]) { + *type = @"text"; + return message; + } + + *type = @"blob"; + return @{ + @"blobId": [self store:message], + @"offset": @0, + @"size": @(((NSData *)message).length), + }; +} + +@end diff --git a/Libraries/Text/TextInput/Multiline/RCTMultilineTextInputShadowView.h b/Libraries/Blob/RCTFileReaderModule.h similarity index 77% rename from Libraries/Text/TextInput/Multiline/RCTMultilineTextInputShadowView.h rename to Libraries/Blob/RCTFileReaderModule.h index 27198d9dbff864..8728c7c3dc0b67 100644 --- a/Libraries/Text/TextInput/Multiline/RCTMultilineTextInputShadowView.h +++ b/Libraries/Blob/RCTFileReaderModule.h @@ -7,8 +7,8 @@ * of patent rights can be found in the PATENTS file in the same directory. */ -#import +#import -@interface RCTMultilineTextInputShadowView : RCTShadowView +@interface RCTFileReaderModule : NSObject @end diff --git a/Libraries/Blob/RCTFileReaderModule.m b/Libraries/Blob/RCTFileReaderModule.m new file mode 100644 index 00000000000000..debbae8cbd771b --- /dev/null +++ b/Libraries/Blob/RCTFileReaderModule.m @@ -0,0 +1,71 @@ +/** + * 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. + */ + + +#import "RCTFileReaderModule.h" + +#import +#import + +#import "RCTBlobManager.h" + + +@implementation RCTFileReaderModule + +RCT_EXPORT_MODULE(FileReaderModule) + +@synthesize bridge = _bridge; + +RCT_EXPORT_METHOD(readAsText:(NSDictionary *)blob + encoding:(NSString *)encoding + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject) +{ + RCTBlobManager *blobManager = [[self bridge] moduleForClass:[RCTBlobManager class]]; + NSData *data = [blobManager resolve:blob]; + + if (data == nil) { + reject(RCTErrorUnspecified, + [NSString stringWithFormat:@"Unable to resolve data for blob: %@", [RCTConvert NSString:blob[@"blobId"]]], nil); + } else { + NSStringEncoding stringEncoding; + + if (encoding == nil) { + stringEncoding = NSUTF8StringEncoding; + } else { + stringEncoding = CFStringConvertEncodingToNSStringEncoding(CFStringConvertIANACharSetNameToEncoding((CFStringRef) encoding)); + } + + NSString *text = [[NSString alloc] initWithData:data encoding:stringEncoding]; + + resolve(text); + } +} + +RCT_EXPORT_METHOD(readAsDataURL:(NSDictionary *)blob + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject) +{ + RCTBlobManager *blobManager = [[self bridge] moduleForClass:[RCTBlobManager class]]; + NSData *data = [blobManager resolve:blob]; + + if (data == nil) { + reject(RCTErrorUnspecified, + [NSString stringWithFormat:@"Unable to resolve data for blob: %@", [RCTConvert NSString:blob[@"blobId"]]], nil); + } else { + NSString *type = [RCTConvert NSString:blob[@"type"]]; + NSString *text = [NSString stringWithFormat:@"data:%@;base64,%@", + type != nil && [type length] > 0 ? type : @"application/octet-stream", + [data base64EncodedStringWithOptions:0]]; + + resolve(text); + } +} + +@end diff --git a/Libraries/Blob/URL.js b/Libraries/Blob/URL.js index ed40cae6567dc9..8b761ca708ce0b 100644 --- a/Libraries/Blob/URL.js +++ b/Libraries/Blob/URL.js @@ -52,16 +52,16 @@ if (BlobModule && typeof BlobModule.BLOB_URI_SCHEME === 'string') { */ class URL { constructor() { - throw new Error('Creating BlobURL objects is not supported yet.'); + throw new Error('Creating URL objects is not supported yet.'); } static createObjectURL(blob: Blob) { if (BLOB_URL_PREFIX === null) { throw new Error('Cannot create URL for blob!'); } - return `${BLOB_URL_PREFIX}${blob.blobId}?offset=${blob.offset}&size=${ - blob.size - }`; + return `${BLOB_URL_PREFIX}${blob.data.blobId}?offset=${ + blob.data.offset + }&size=${blob.size}`; } static revokeObjectURL(url: string) { diff --git a/Libraries/Blob/__mocks__/BlobModule.js b/Libraries/Blob/__mocks__/BlobModule.js new file mode 100644 index 00000000000000..1cbda950883312 --- /dev/null +++ b/Libraries/Blob/__mocks__/BlobModule.js @@ -0,0 +1,17 @@ +/** + * 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. + * + * @flow + * @format + */ +const BlobModule = { + createFromParts() {}, + release() {}, +}; + +module.exports = BlobModule; diff --git a/Libraries/Blob/__mocks__/FileReaderModule.js b/Libraries/Blob/__mocks__/FileReaderModule.js new file mode 100644 index 00000000000000..d4b35e00c24cc2 --- /dev/null +++ b/Libraries/Blob/__mocks__/FileReaderModule.js @@ -0,0 +1,21 @@ +/** + * 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. + * + * @flow + * @format + */ +const FileReaderModule = { + async readAsText() { + return ''; + }, + async readAsDataURL() { + return 'data:text/plain;base64,NDI='; + }, +}; + +module.exports = FileReaderModule; diff --git a/Libraries/Blob/__tests__/Blob-test.js b/Libraries/Blob/__tests__/Blob-test.js new file mode 100644 index 00000000000000..85532c819494f9 --- /dev/null +++ b/Libraries/Blob/__tests__/Blob-test.js @@ -0,0 +1,84 @@ +/** + * 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. + * + * @format + * @emails oncall+react_native + */ +'use strict'; + +jest.setMock('NativeModules', { + BlobModule: require('../__mocks__/BlobModule'), +}); + +var Blob = require('Blob'); + +describe('Blob', function() { + it('should create empty blob', () => { + const blob = new Blob(); + expect(blob).toBeInstanceOf(Blob); + expect(blob.data.offset).toBe(0); + expect(blob.data.size).toBe(0); + expect(blob.size).toBe(0); + expect(blob.type).toBe(''); + }); + + it('should create blob from other blobs and strings', () => { + const blobA = new Blob(); + const blobB = new Blob(); + const textA = 'i \u2665 dogs'; + const textB = '\uD800\uDC00'; + const textC = + 'Z\u0351\u036B\u0343\u036A\u0302\u036B\u033D\u034F\u0334\u0319\u0324' + + '\u031E\u0349\u035A\u032F\u031E\u0320\u034DA\u036B\u0357\u0334\u0362' + + '\u0335\u031C\u0330\u0354L\u0368\u0367\u0369\u0358\u0320G\u0311\u0357' + + '\u030E\u0305\u035B\u0341\u0334\u033B\u0348\u034D\u0354\u0339O\u0342' + + '\u030C\u030C\u0358\u0328\u0335\u0339\u033B\u031D\u0333!\u033F\u030B' + + '\u0365\u0365\u0302\u0363\u0310\u0301\u0301\u035E\u035C\u0356\u032C' + + '\u0330\u0319\u0317'; + + blobA.data.size = 34540; + blobB.data.size = 65452; + + const blob = new Blob([blobA, blobB, textA, textB, textC]); + + expect(blob.size).toBe( + blobA.size + + blobB.size + + global.Buffer.byteLength(textA, 'UTF-8') + + global.Buffer.byteLength(textB, 'UTF-8') + + global.Buffer.byteLength(textC, 'UTF-8'), + ); + expect(blob.type).toBe(''); + }); + + it('should slice a blob', () => { + const blob = new Blob(); + + blob.data.size = 34546; + + const sliceA = blob.slice(0, 2354); + + expect(sliceA.data.offset).toBe(0); + expect(sliceA.size).toBe(2354); + expect(sliceA.type).toBe(''); + + const sliceB = blob.slice(2384, 7621); + + expect(sliceB.data.offset).toBe(2384); + expect(sliceB.size).toBe(7621 - 2384); + expect(sliceB.type).toBe(''); + }); + + it('should close a blob', () => { + const blob = new Blob(); + + blob.close(); + + expect(() => blob.size).toThrow(); + }); +}); diff --git a/Libraries/Blob/__tests__/BlobManager-test.js b/Libraries/Blob/__tests__/BlobManager-test.js new file mode 100644 index 00000000000000..6422861b0d2780 --- /dev/null +++ b/Libraries/Blob/__tests__/BlobManager-test.js @@ -0,0 +1,27 @@ +/** + * 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. + * + * @format + * @emails oncall+react_native + */ +'use strict'; + +jest.setMock('NativeModules', { + BlobModule: require('../__mocks__/BlobModule'), +}); + +var Blob = require('Blob'); +var BlobManager = require('BlobManager'); + +describe('BlobManager', function() { + it('should create blob from parts', () => { + const blob = BlobManager.createFromParts([], {type: 'text/html'}); + expect(blob).toBeInstanceOf(Blob); + expect(blob.type).toBe('text/html'); + }); +}); diff --git a/Libraries/Blob/__tests__/File-test.js b/Libraries/Blob/__tests__/File-test.js new file mode 100644 index 00000000000000..99957873242ff6 --- /dev/null +++ b/Libraries/Blob/__tests__/File-test.js @@ -0,0 +1,46 @@ +/** + * 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. + * + * @format + * @emails oncall+react_native + */ +'use strict'; + +jest.setMock('NativeModules', { + BlobModule: require('../__mocks__/BlobModule'), +}); + +const File = require('File'); + +describe('File', function() { + it('should create empty file', () => { + const file = new File([], 'test.jpg'); + expect(file).toBeInstanceOf(File); + expect(file.data.offset).toBe(0); + expect(file.data.size).toBe(0); + expect(file.size).toBe(0); + expect(file.type).toBe(''); + expect(file.name).toBe('test.jpg'); + expect(file.lastModified).toEqual(expect.any(Number)); + }); + + it('should create empty file with type', () => { + const file = new File([], 'test.jpg', {type: 'image/jpeg'}); + expect(file.type).toBe('image/jpeg'); + }); + + it('should create empty file with lastModified', () => { + const file = new File([], 'test.jpg', {lastModified: 1337}); + expect(file.lastModified).toBe(1337); + }); + + it('should throw on invalid arguments', () => { + expect(() => new File()).toThrow(); + expect(() => new File([])).toThrow(); + }); +}); diff --git a/Libraries/Blob/__tests__/FileReader-test.js b/Libraries/Blob/__tests__/FileReader-test.js new file mode 100644 index 00000000000000..58a0e92f6218f7 --- /dev/null +++ b/Libraries/Blob/__tests__/FileReader-test.js @@ -0,0 +1,42 @@ +/** + * 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. + * + * @format + * @emails oncall+react_native + */ +'use strict'; + +jest.unmock('event-target-shim').setMock('NativeModules', { + BlobModule: require('../__mocks__/BlobModule'), + FileReaderModule: require('../__mocks__/FileReaderModule'), +}); + +var Blob = require('Blob'); +var FileReader = require('FileReader'); + +describe('FileReader', function() { + it('should read blob as text', async () => { + const e = await new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.onload = resolve; + reader.onerror = reject; + reader.readAsText(new Blob()); + }); + expect(e.target.result).toBe(''); + }); + + it('should read blob as data URL', async () => { + const e = await new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.onload = resolve; + reader.onerror = reject; + reader.readAsDataURL(new Blob()); + }); + expect(e.target.result).toBe('data:text/plain;base64,NDI='); + }); +}); diff --git a/Libraries/CameraRoll/CameraRoll.js b/Libraries/CameraRoll/CameraRoll.js index 78f8d365aaea24..91fba6d8fe893c 100644 --- a/Libraries/CameraRoll/CameraRoll.js +++ b/Libraries/CameraRoll/CameraRoll.js @@ -147,15 +147,9 @@ const getPhotosReturnChecker = createStrictShapeTypeChecker({ }); /** - * `CameraRoll` provides access to the local camera roll / gallery. - * Before using this you must link the `RCTCameraRoll` library. - * You can refer to [Linking](docs/linking-libraries-ios.html) for help. - * - * ### Permissions - * The user's permission is required in order to access the Camera Roll on devices running iOS 10 or later. - * Add the `NSPhotoLibraryUsageDescription` key in your `Info.plist` with a string that describes how your - * app will use this data. This key will appear as `Privacy - Photo Library Usage Description` in Xcode. + * `CameraRoll` provides access to the local camera roll or photo library. * + * See https://facebook.github.io/react-native/docs/cameraroll.html */ class CameraRoll { static GroupTypesOptions: Object = GROUP_TYPES_OPTIONS; @@ -176,18 +170,9 @@ class CameraRoll { } /** - * Saves the photo or video to the camera roll / gallery. - * - * On Android, the tag must be a local image or video URI, such as `"file:///sdcard/img.png"`. - * - * On iOS, the tag can be any image URI (including local, remote asset-library and base64 data URIs) - * or a local video file URI (remote or data URIs are not supported for saving video at this time). - * - * If the tag has a file extension of .mov or .mp4, it will be inferred as a video. Otherwise - * it will be treated as a photo. To override the automatic choice, you can pass an optional - * `type` parameter that must be one of 'photo' or 'video'. + * Saves the photo or video to the camera roll or photo library. * - * Returns a Promise which will resolve with the new URI. + * See https://facebook.github.io/react-native/docs/cameraroll.html#savetocameraroll */ static saveToCameraRoll( tag: string, @@ -218,84 +203,7 @@ class CameraRoll { * Returns a Promise with photo identifier objects from the local camera * roll of the device matching shape defined by `getPhotosReturnChecker`. * - * Expects a params object of the following shape: - * - * - `first` : {number} : The number of photos wanted in reverse order of the photo application (i.e. most recent first for SavedPhotos). - * - `after` : {string} : A cursor that matches `page_info { end_cursor }` returned from a previous call to `getPhotos`. - * - `groupTypes` : {string} : Specifies which group types to filter the results to. Valid values are: - * - `Album` - * - `All` - * - `Event` - * - `Faces` - * - `Library` - * - `PhotoStream` - * - `SavedPhotos` // default - * - `groupName` : {string} : Specifies filter on group names, like 'Recent Photos' or custom album titles. - * - `assetType` : {string} : Specifies filter on asset type. Valid values are: - * - `All` - * - `Videos` - * - `Photos` // default - * - `mimeTypes` : {string} : Filter by mimetype (e.g. image/jpeg). - * - * Returns a Promise which when resolved will be of the following shape: - * - * - `edges` : {Array} An array of node objects - * - `node`: {object} An object with the following shape: - * - `type`: {string} - * - `group_name`: {string} - * - `image`: {object} : An object with the following shape: - * - `uri`: {string} - * - `height`: {number} - * - `width`: {number} - * - `isStored`: {boolean} - * - `timestamp`: {number} - * - `location`: {object} : An object with the following shape: - * - `latitude`: {number} - * - `longitude`: {number} - * - `altitude`: {number} - * - `heading`: {number} - * - `speed`: {number} - * - `page_info` : {object} : An object with the following shape: - * - `has_next_page`: {boolean} - * - `start_cursor`: {string} - * - `end_cursor`: {string} - * - * Loading images: - * ``` - * _handleButtonPress = () => { - * CameraRoll.getPhotos({ - * first: 20, - * assetType: 'All', - * }) - * .then(r => { - * this.setState({ photos: r.edges }); - * }) - * .catch((err) => { - * //Error Loading Images - * }); - * }; - * render() { - * return ( - * - *