diff --git a/Examples/2048/2048/AppDelegate.m b/Examples/2048/2048/AppDelegate.m index 2413b3552..b4b1769ff 100644 --- a/Examples/2048/2048/AppDelegate.m +++ b/Examples/2048/2048/AppDelegate.m @@ -36,7 +36,7 @@ * on the same Wi-Fi network. */ - jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/Examples/2048/Game2048.bundle?platform=ios"]; + jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/Examples/2048/Game2048.bundle?platform=ios&dev=true"]; /** * OPTION 2 diff --git a/Examples/Movies/Movies.xcodeproj/project.pbxproj b/Examples/Movies/Movies.xcodeproj/project.pbxproj index 21fc0cb88..f3937e428 100644 --- a/Examples/Movies/Movies.xcodeproj/project.pbxproj +++ b/Examples/Movies/Movies.xcodeproj/project.pbxproj @@ -216,7 +216,7 @@ 83CBB9F71A601CBA00E9B192 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0610; + LastUpgradeCheck = 0700; ORGANIZATIONNAME = Facebook; }; buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "Movies" */; @@ -358,6 +358,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LIBRARY_SEARCH_PATHS = "$(inherited)"; OTHER_LDFLAGS = "-ObjC"; + PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = Movies; USER_HEADER_SEARCH_PATHS = "$(SRCROOT)/../../Libraries/**"; }; @@ -376,6 +377,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LIBRARY_SEARCH_PATHS = "$(inherited)"; OTHER_LDFLAGS = "-ObjC"; + PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = Movies; USER_HEADER_SEARCH_PATHS = "$(SRCROOT)/../../Libraries/**"; }; @@ -401,6 +403,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_OPTIMIZATION_LEVEL = 0; diff --git a/Examples/Movies/Movies.xcodeproj/xcshareddata/xcschemes/Movies.xcscheme b/Examples/Movies/Movies.xcodeproj/xcshareddata/xcschemes/Movies.xcscheme index 18b45cad0..4cb2fa20a 100644 --- a/Examples/Movies/Movies.xcodeproj/xcshareddata/xcschemes/Movies.xcscheme +++ b/Examples/Movies/Movies.xcodeproj/xcshareddata/xcschemes/Movies.xcscheme @@ -1,6 +1,6 @@ + + - + - + CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier - com.facebook.$(PRODUCT_NAME:rfc1034identifier) + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName @@ -33,6 +33,11 @@ 1 LSRequiresIPhoneOS + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + UILaunchStoryboardName LaunchScreen UIRequiredDeviceCapabilities @@ -47,11 +52,5 @@ UIViewControllerBasedStatusBarAppearance - NSAppTransportSecurity - - - NSAllowsArbitraryLoads - - diff --git a/Examples/Movies/getStyleFromScore.js b/Examples/Movies/getStyleFromScore.js index 98feaa50b..1d5b599b6 100644 --- a/Examples/Movies/getStyleFromScore.js +++ b/Examples/Movies/getStyleFromScore.js @@ -22,7 +22,9 @@ var { var MAX_VALUE = 200; -function getStyleFromScore(score: number): {color: string} { +import type { StyleObj } from 'StyleSheetTypes'; + +function getStyleFromScore(score: number): StyleObj { if (score < 0) { return styles.noScore; } diff --git a/Examples/SampleApp/iOS/SampleApp/AppDelegate.m b/Examples/SampleApp/iOS/SampleApp/AppDelegate.m index b1c018ca5..d49b891a2 100644 --- a/Examples/SampleApp/iOS/SampleApp/AppDelegate.m +++ b/Examples/SampleApp/iOS/SampleApp/AppDelegate.m @@ -31,7 +31,7 @@ * on the same Wi-Fi network. */ - jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/Examples/SampleApp/index.ios.bundle"]; + jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/Examples/SampleApp/index.ios.bundle?platform=ios&dev=true"]; /** * OPTION 2 diff --git a/Examples/TicTacToe/TicTacToe/AppDelegate.m b/Examples/TicTacToe/TicTacToe/AppDelegate.m index aa746ba69..f0199b6dd 100644 --- a/Examples/TicTacToe/TicTacToe/AppDelegate.m +++ b/Examples/TicTacToe/TicTacToe/AppDelegate.m @@ -36,7 +36,7 @@ * on the same Wi-Fi network. */ - jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/Examples/TicTacToe/TicTacToeApp.bundle?platform=ios"]; + jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/Examples/TicTacToe/TicTacToeApp.bundle?platform=ios&dev=true"]; /** * OPTION 2 diff --git a/Examples/UIExplorer/AnimatedExample.js b/Examples/UIExplorer/AnimatedExample.js new file mode 100644 index 000000000..e417cacbe --- /dev/null +++ b/Examples/UIExplorer/AnimatedExample.js @@ -0,0 +1,230 @@ +/** + * The examples provided by Facebook are for non-commercial testing and + * evaluation purposes only. + * + * Facebook reserves all rights not expressly granted. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL + * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * @flow + */ +'use strict'; + +var React = require('react-native'); +var { + Animated, + Easing, + StyleSheet, + Text, + View, +} = React; +var UIExplorerButton = require('./UIExplorerButton'); + +exports.framework = 'React'; +exports.title = 'Animated - Examples'; +exports.description = 'Animated provides a powerful ' + + 'and easy-to-use API for building modern, ' + + 'interactive user experiences.'; + +exports.examples = [ + { + title: 'FadeInView', + description: 'Uses a simple timing animation to ' + + 'bring opacity from 0 to 1 when the component ' + + 'mounts.', + render: function() { + class FadeInView extends React.Component { + constructor(props) { + super(props); + this.state = { + fadeAnim: new Animated.Value(0), // opacity 0 + }; + } + componentDidMount() { + Animated.timing( // Uses easing functions + this.state.fadeAnim, // The value to drive + { + toValue: 1, // Target + duration: 2000, // Configuration + }, + ).start(); // Don't forget start! + } + render() { + return ( + + {this.props.children} + + ); + } + } + class FadeInExample extends React.Component { + constructor(props) { + super(props); + this.state = { + show: true, + }; + } + render() { + return ( + + { + this.setState((state) => ( + {show: !state.show} + )); + }}> + Press to {this.state.show ? + 'Hide' : 'Show'} + + {this.state.show && + + FadeInView + + } + + ); + } + } + return ; + }, + }, + { + title: 'Transform Bounce', + description: 'One `Animated.Value` is driven by a ' + + 'spring with custom constants and mapped to an ' + + 'ordered set of transforms. Each transform has ' + + 'an interpolation to convert the value into the ' + + 'right range and units.', + render: function() { + this.anim = this.anim || new Animated.Value(0); + return ( + + { + Animated.spring(this.anim, { + toValue: 0, // Returns to the start + velocity: 3, // Velocity makes it move + tension: -10, // Slow + friction: 1, // Oscillate a lot + }).start(); }}> + Press to Fling it! + + + Transforms! + + + ); + }, + }, + { + title: 'Composite Animations with Easing', + description: 'Sequence, parallel, delay, and ' + + 'stagger with different easing functions.', + render: function() { + this.anims = this.anims || [1,2,3].map( + () => new Animated.Value(0) + ); + return ( + + { + var timing = Animated.timing; + Animated.sequence([ // One after the other + timing(this.anims[0], { + toValue: 200, + easing: Easing.linear, + }), + Animated.delay(400), // Use with sequence + timing(this.anims[0], { + toValue: 0, + easing: Easing.elastic(2), // Springy + }), + Animated.delay(400), + Animated.stagger(200, + this.anims.map((anim) => timing( + anim, {toValue: 200} + )).concat( + this.anims.map((anim) => timing( + anim, {toValue: 0} + ))), + ), + Animated.delay(400), + Animated.parallel([ + Easing.inOut(Easing.quad), // Symmetric + Easing.back(1.5), // Goes backwards first + Easing.ease // Default bezier + ].map((easing, ii) => ( + timing(this.anims[ii], { + toValue: 320, easing, duration: 3000, + }) + ))), + Animated.delay(400), + Animated.stagger(200, + this.anims.map((anim) => timing(anim, { + toValue: 0, + easing: Easing.bounce, // Like a ball + duration: 2000, + })), + ), + ]).start(); }}> + Press to Animate + + {['Composite', 'Easing', 'Animations!'].map( + (text, ii) => ( + + {text} + + ) + )} + + ); + }, + }, + { + title: 'Continuous Interactions', + description: 'Gesture events, chaining, 2D ' + + 'values, interrupting and transitioning ' + + 'animations, etc.', + render: () => ( + Checkout the Gratuitous Animation App! + ), + } +]; + +var styles = StyleSheet.create({ + content: { + backgroundColor: 'deepskyblue', + borderWidth: 1, + borderColor: 'dodgerblue', + padding: 20, + margin: 20, + borderRadius: 10, + alignItems: 'center', + }, +}); diff --git a/Examples/UIExplorer/AnimationExample/AnExApp.js b/Examples/UIExplorer/AnimatedGratuitousApp/AnExApp.js similarity index 100% rename from Examples/UIExplorer/AnimationExample/AnExApp.js rename to Examples/UIExplorer/AnimatedGratuitousApp/AnExApp.js diff --git a/Examples/UIExplorer/AnimationExample/AnExBobble.js b/Examples/UIExplorer/AnimatedGratuitousApp/AnExBobble.js similarity index 100% rename from Examples/UIExplorer/AnimationExample/AnExBobble.js rename to Examples/UIExplorer/AnimatedGratuitousApp/AnExBobble.js diff --git a/Examples/UIExplorer/AnimationExample/AnExChained.js b/Examples/UIExplorer/AnimatedGratuitousApp/AnExChained.js similarity index 100% rename from Examples/UIExplorer/AnimationExample/AnExChained.js rename to Examples/UIExplorer/AnimatedGratuitousApp/AnExChained.js diff --git a/Examples/UIExplorer/AnimationExample/AnExScroll.js b/Examples/UIExplorer/AnimatedGratuitousApp/AnExScroll.js similarity index 100% rename from Examples/UIExplorer/AnimationExample/AnExScroll.js rename to Examples/UIExplorer/AnimatedGratuitousApp/AnExScroll.js diff --git a/Examples/UIExplorer/AnimationExample/AnExSet.js b/Examples/UIExplorer/AnimatedGratuitousApp/AnExSet.js similarity index 100% rename from Examples/UIExplorer/AnimationExample/AnExSet.js rename to Examples/UIExplorer/AnimatedGratuitousApp/AnExSet.js diff --git a/Examples/UIExplorer/AnimationExample/AnExSlides.md b/Examples/UIExplorer/AnimatedGratuitousApp/AnExSlides.md similarity index 100% rename from Examples/UIExplorer/AnimationExample/AnExSlides.md rename to Examples/UIExplorer/AnimatedGratuitousApp/AnExSlides.md diff --git a/Examples/UIExplorer/AnimationExample/AnExTilt.js b/Examples/UIExplorer/AnimatedGratuitousApp/AnExTilt.js similarity index 100% rename from Examples/UIExplorer/AnimationExample/AnExTilt.js rename to Examples/UIExplorer/AnimatedGratuitousApp/AnExTilt.js diff --git a/Examples/UIExplorer/ImageExample.js b/Examples/UIExplorer/ImageExample.js index cea7b5511..5e47dcb54 100644 --- a/Examples/UIExplorer/ImageExample.js +++ b/Examples/UIExplorer/ImageExample.js @@ -325,6 +325,18 @@ exports.examples = [ ); }, }, + { + title: 'Animated GIF', + render: function() { + return ( + + ); + }, + platform: 'ios', + }, { title: 'Cap Insets', description: @@ -384,5 +396,9 @@ var styles = StyleSheet.create({ }, horizontal: { flexDirection: 'row', - } + }, + gif: { + flex: 1, + height: 200, + }, }); diff --git a/Examples/UIExplorer/TimerExample.js b/Examples/UIExplorer/TimerExample.js index b5923b350..8ef94cafe 100644 --- a/Examples/UIExplorer/TimerExample.js +++ b/Examples/UIExplorer/TimerExample.js @@ -18,27 +18,12 @@ var React = require('react-native'); var { AlertIOS, - StyleSheet, Text, TouchableHighlight, View, } = React; var TimerMixin = require('react-timer-mixin'); - -var Button = React.createClass({ - render: function() { - return ( - - - {this.props.children} - - - ); - }, -}); +var UIExplorerButton = require('./UIExplorerButton'); var TimerTester = React.createClass({ mixins: [TimerMixin], @@ -52,9 +37,9 @@ var TimerTester = React.createClass({ render: function() { var args = 'fn' + (this.props.dt !== undefined ? ', ' + this.props.dt : ''); return ( - + ); }, @@ -112,18 +97,6 @@ var TimerTester = React.createClass({ }, }); -var styles = StyleSheet.create({ - button: { - borderColor: 'gray', - borderRadius: 8, - borderWidth: 1, - padding: 10, - margin: 5, - alignItems: 'center', - justifyContent: 'center', - }, -}); - exports.framework = 'React'; exports.title = 'Timers, TimerMixin'; exports.description = 'The TimerMixin provides timer functions for executing ' + @@ -183,9 +156,9 @@ exports.examples = [ if (this.state.showTimer) { var timer = [ , - + ]; var toggleText = 'Unmount timer'; } else { @@ -195,9 +168,9 @@ exports.examples = [ return ( {timer} - + ); }, diff --git a/Examples/UIExplorer/UIExplorer.xcodeproj/project.pbxproj b/Examples/UIExplorer/UIExplorer.xcodeproj/project.pbxproj index 9ec430af5..02e2c9e13 100644 --- a/Examples/UIExplorer/UIExplorer.xcodeproj/project.pbxproj +++ b/Examples/UIExplorer/UIExplorer.xcodeproj/project.pbxproj @@ -15,6 +15,7 @@ 134A8A2A1AACED7A00945AAE /* libRCTGeolocation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 134A8A251AACED6A00945AAE /* libRCTGeolocation.a */; }; 138D6A171B53CD440074A87E /* RCTCacheTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 138D6A151B53CD440074A87E /* RCTCacheTests.m */; }; 138D6A181B53CD440074A87E /* RCTShadowViewTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 138D6A161B53CD440074A87E /* RCTShadowViewTests.m */; }; + 138DEE241B9EDFB6007F4EA5 /* libRCTCameraRoll.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 138DEE091B9EDDDB007F4EA5 /* libRCTCameraRoll.a */; }; 1393D0381B68CD1300E1B601 /* RCTModuleMethodTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1393D0371B68CD1300E1B601 /* RCTModuleMethodTests.m */; }; 139FDEDB1B0651FB00C62182 /* libRCTWebSocket.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 139FDED91B0651EA00C62182 /* libRCTWebSocket.a */; }; 13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.m */; }; @@ -96,6 +97,13 @@ remoteGlobalIDString = 134814201AA4EA6300B7C361; remoteInfo = RCTGeolocation; }; + 138DEE081B9EDDDB007F4EA5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 138DEE021B9EDDDB007F4EA5 /* RCTCameraRoll.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 58B5115D1A9E6B3D00147676; + remoteInfo = RCTImage; + }; 139FDED81B0651EA00C62182 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 139FDECA1B0651EA00C62182 /* RCTWebSocket.xcodeproj */; @@ -171,6 +179,7 @@ 134A8A201AACED6A00945AAE /* RCTGeolocation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTGeolocation.xcodeproj; path = ../../Libraries/Geolocation/RCTGeolocation.xcodeproj; sourceTree = ""; }; 138D6A151B53CD440074A87E /* RCTCacheTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTCacheTests.m; sourceTree = ""; }; 138D6A161B53CD440074A87E /* RCTShadowViewTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTShadowViewTests.m; sourceTree = ""; }; + 138DEE021B9EDDDB007F4EA5 /* RCTCameraRoll.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTCameraRoll.xcodeproj; path = ../../Libraries/CameraRoll/RCTCameraRoll.xcodeproj; sourceTree = ""; }; 1393D0371B68CD1300E1B601 /* RCTModuleMethodTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTModuleMethodTests.m; sourceTree = ""; }; 139FDECA1B0651EA00C62182 /* RCTWebSocket.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTWebSocket.xcodeproj; path = ../../Libraries/WebSocket/RCTWebSocket.xcodeproj; sourceTree = ""; }; 13B07F961A680F5B00A75B9A /* UIExplorer.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = UIExplorer.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -254,6 +263,7 @@ 14AADF051AC3DBB1002390C9 /* libReact.a in Frameworks */, 147CED4C1AB3532B00DA3E4C /* libRCTActionSheet.a in Frameworks */, 134454601AAFCABD003F0779 /* libRCTAdSupport.a in Frameworks */, + 138DEE241B9EDFB6007F4EA5 /* libRCTCameraRoll.a in Frameworks */, 134A8A2A1AACED7A00945AAE /* libRCTGeolocation.a in Frameworks */, 13417FE91AA91432003F314A /* libRCTImage.a in Frameworks */, 3578590A1B28D2CF00341EDB /* libRCTLinking.a in Frameworks */, @@ -281,13 +291,14 @@ isa = PBXGroup; children = ( 14AADEFF1AC3DB95002390C9 /* React.xcodeproj */, - 14DC67E71AB71876001358AB /* RCTPushNotification.xcodeproj */, 14E0EEC81AB118F7000DECC3 /* RCTActionSheet.xcodeproj */, 134454551AAFCAAE003F0779 /* RCTAdSupport.xcodeproj */, + 138DEE021B9EDDDB007F4EA5 /* RCTCameraRoll.xcodeproj */, 134A8A201AACED6A00945AAE /* RCTGeolocation.xcodeproj */, 13417FE31AA91428003F314A /* RCTImage.xcodeproj */, 357858F81B28D2C400341EDB /* RCTLinking.xcodeproj */, 134180261AA91779003F314A /* RCTNetwork.xcodeproj */, + 14DC67E71AB71876001358AB /* RCTPushNotification.xcodeproj */, 13CC9D481AEED2B90020D1C2 /* RCTSettings.xcodeproj */, 58005BE41ABA80530062E044 /* RCTTest.xcodeproj */, 13417FEA1AA914B8003F314A /* RCTText.xcodeproj */, @@ -337,6 +348,14 @@ name = Products; sourceTree = ""; }; + 138DEE031B9EDDDB007F4EA5 /* Products */ = { + isa = PBXGroup; + children = ( + 138DEE091B9EDDDB007F4EA5 /* libRCTCameraRoll.a */, + ); + name = Products; + sourceTree = ""; + }; 139FDECB1B0651EA00C62182 /* Products */ = { isa = PBXGroup; children = ( @@ -624,6 +643,10 @@ ProductGroup = 134454561AAFCAAE003F0779 /* Products */; ProjectRef = 134454551AAFCAAE003F0779 /* RCTAdSupport.xcodeproj */; }, + { + ProductGroup = 138DEE031B9EDDDB007F4EA5 /* Products */; + ProjectRef = 138DEE021B9EDDDB007F4EA5 /* RCTCameraRoll.xcodeproj */; + }, { ProductGroup = 134A8A211AACED6A00945AAE /* Products */; ProjectRef = 134A8A201AACED6A00945AAE /* RCTGeolocation.xcodeproj */; @@ -714,6 +737,13 @@ remoteRef = 134A8A241AACED6A00945AAE /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; + 138DEE091B9EDDDB007F4EA5 /* libRCTCameraRoll.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libRCTCameraRoll.a; + remoteRef = 138DEE081B9EDDDB007F4EA5 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; 139FDED91B0651EA00C62182 /* libRCTWebSocket.a */ = { isa = PBXReferenceProxy; fileType = archive.ar; diff --git a/Examples/UIExplorer/UIExplorer/AppDelegate.m b/Examples/UIExplorer/UIExplorer/AppDelegate.m index 24ada2b56..1d0d0079c 100644 --- a/Examples/UIExplorer/UIExplorer/AppDelegate.m +++ b/Examples/UIExplorer/UIExplorer/AppDelegate.m @@ -59,7 +59,7 @@ * on the same Wi-Fi network. */ - sourceURL = [NSURL URLWithString:@"http://localhost:8081/Examples/UIExplorer/UIExplorerApp.ios.bundle?dev=true"]; + sourceURL = [NSURL URLWithString:@"http://localhost:8081/Examples/UIExplorer/UIExplorerApp.ios.bundle?platform=ios&dev=true"]; /** * OPTION 2 diff --git a/Examples/UIExplorer/UIExplorerButton.js b/Examples/UIExplorer/UIExplorerButton.js new file mode 100644 index 000000000..082fe86ba --- /dev/null +++ b/Examples/UIExplorer/UIExplorerButton.js @@ -0,0 +1,56 @@ +/** + * The examples provided by Facebook are for non-commercial testing and + * evaluation purposes only. + * + * Facebook reserves all rights not expressly granted. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL + * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * @flow + */ +'use strict'; + +var React = require('react-native'); +var { + StyleSheet, + Text, + TouchableHighlight, +} = React; + +var UIExplorerButton = React.createClass({ + propTypes: { + onPress: React.PropTypes.func, + }, + render: function() { + return ( + + + {this.props.children} + + + ); + }, +}); + +var styles = StyleSheet.create({ + button: { + borderColor: 'dimgray', + borderRadius: 8, + borderWidth: 1, + padding: 10, + margin: 5, + alignItems: 'center', + justifyContent: 'center', + backgroundColor: 'lightgrey', + }, +}); + +module.exports = UIExplorerButton; diff --git a/Examples/UIExplorer/UIExplorerIntegrationTests/ReferenceImages/Examples-UIExplorer-UIExplorerApp.ios/testSliderExample_1@2x.png b/Examples/UIExplorer/UIExplorerIntegrationTests/ReferenceImages/Examples-UIExplorer-UIExplorerApp.ios/testSliderExample_1@2x.png index b08e761b6..239761ed2 100644 Binary files a/Examples/UIExplorer/UIExplorerIntegrationTests/ReferenceImages/Examples-UIExplorer-UIExplorerApp.ios/testSliderExample_1@2x.png and b/Examples/UIExplorer/UIExplorerIntegrationTests/ReferenceImages/Examples-UIExplorer-UIExplorerApp.ios/testSliderExample_1@2x.png differ diff --git a/Examples/UIExplorer/UIExplorerIntegrationTests/ReferenceImages/Examples-UIExplorer-UIExplorerApp.ios/testSwitchExample_1@2x.png b/Examples/UIExplorer/UIExplorerIntegrationTests/ReferenceImages/Examples-UIExplorer-UIExplorerApp.ios/testSwitchExample_1@2x.png index 7297dde2d..efdc8fe05 100644 Binary files a/Examples/UIExplorer/UIExplorerIntegrationTests/ReferenceImages/Examples-UIExplorer-UIExplorerApp.ios/testSwitchExample_1@2x.png and b/Examples/UIExplorer/UIExplorerIntegrationTests/ReferenceImages/Examples-UIExplorer-UIExplorerApp.ios/testSwitchExample_1@2x.png differ diff --git a/Examples/UIExplorer/UIExplorerIntegrationTests/ReferenceImages/Examples-UIExplorer-UIExplorerApp.ios/testTextExample_1@2x.png b/Examples/UIExplorer/UIExplorerIntegrationTests/ReferenceImages/Examples-UIExplorer-UIExplorerApp.ios/testTextExample_1@2x.png index 32449556d..4055e789b 100644 Binary files a/Examples/UIExplorer/UIExplorerIntegrationTests/ReferenceImages/Examples-UIExplorer-UIExplorerApp.ios/testTextExample_1@2x.png and b/Examples/UIExplorer/UIExplorerIntegrationTests/ReferenceImages/Examples-UIExplorer-UIExplorerApp.ios/testTextExample_1@2x.png differ diff --git a/Examples/UIExplorer/UIExplorerIntegrationTests/ReferenceImages/Examples-UIExplorer-UIExplorerApp.ios/testViewExample_1@2x.png b/Examples/UIExplorer/UIExplorerIntegrationTests/ReferenceImages/Examples-UIExplorer-UIExplorerApp.ios/testViewExample_1@2x.png index fb2ab9feb..cc17b0dd2 100644 Binary files a/Examples/UIExplorer/UIExplorerIntegrationTests/ReferenceImages/Examples-UIExplorer-UIExplorerApp.ios/testViewExample_1@2x.png and b/Examples/UIExplorer/UIExplorerIntegrationTests/ReferenceImages/Examples-UIExplorer-UIExplorerApp.ios/testViewExample_1@2x.png differ diff --git a/Examples/UIExplorer/UIExplorerIntegrationTests/IntegrationTests.m b/Examples/UIExplorer/UIExplorerIntegrationTests/UIExplorerIntegrationTests.m similarity index 64% rename from Examples/UIExplorer/UIExplorerIntegrationTests/IntegrationTests.m rename to Examples/UIExplorer/UIExplorerIntegrationTests/UIExplorerIntegrationTests.m index 267ed1409..9bc71ed80 100644 --- a/Examples/UIExplorer/UIExplorerIntegrationTests/IntegrationTests.m +++ b/Examples/UIExplorer/UIExplorerIntegrationTests/UIExplorerIntegrationTests.m @@ -14,11 +14,17 @@ #import "RCTAssert.h" -@interface IntegrationTests : XCTestCase +#define RCT_TEST(name) \ +- (void)test##name \ +{ \ + [_runner runTest:_cmd module:@#name]; \ +} + +@interface UIExplorerIntegrationTests : XCTestCase @end -@implementation IntegrationTests +@implementation UIExplorerIntegrationTests { RCTTestRunner *_runner; } @@ -36,11 +42,6 @@ #pragma mark Logic Tests -- (void)testTheTester -{ - [_runner runTest:_cmd module:@"IntegrationTestHarnessTest"]; -} - - (void)testTheTester_waitOneFrame { [_runner runTest:_cmd @@ -57,38 +58,12 @@ expectErrorRegex:@"because shouldThrow"]; } -- (void)testTimers -{ - [_runner runTest:_cmd module:@"TimersTest"]; -} - -- (void)testAsyncStorage -{ - [_runner runTest:_cmd module:@"AsyncStorageTest"]; -} - -- (void)DISABLED_testLayoutEvents // #7149037 -{ - [_runner runTest:_cmd module:@"LayoutEventsTest"]; -} - -- (void)testAppEvents -{ - [_runner runTest:_cmd module:@"AppEventsTest"]; -} - -- (void)testPromises -{ - [_runner runTest:_cmd module:@"PromiseTest"]; -} - -#pragma mark Snapshot Tests - -- (void)testSimpleSnapshot -{ - // If tests have changes, set recordMode = YES below and re-run - _runner.recordMode = NO; - [_runner runTest:_cmd module:@"SimpleSnapshotTest"]; -} +RCT_TEST(TimersTest) +RCT_TEST(IntegrationTestHarnessTest) +RCT_TEST(AsyncStorageTest) +// RCT_TEST(LayoutEventsTest) -- Disabled: #8153468 +RCT_TEST(AppEventsTest) +RCT_TEST(PromiseTest) +// RCT_TEST(SimpleSnapshotTest) -- Disabled: #8153475 @end diff --git a/Examples/UIExplorer/UIExplorerIntegrationTests/js/AppEventsTest.js b/Examples/UIExplorer/UIExplorerIntegrationTests/js/AppEventsTest.js index bf7931b5a..95370771b 100644 --- a/Examples/UIExplorer/UIExplorerIntegrationTests/js/AppEventsTest.js +++ b/Examples/UIExplorer/UIExplorerIntegrationTests/js/AppEventsTest.js @@ -19,7 +19,7 @@ var { Text, View, } = React; -var TestModule = NativeModules.TestModule || NativeModules.SnapshotTestManager; +var TestModule = NativeModules.TestModule; var deepDiffer = require('deepDiffer'); diff --git a/Examples/UIExplorer/UIExplorerIntegrationTests/js/LayoutEventsTest.js b/Examples/UIExplorer/UIExplorerIntegrationTests/js/LayoutEventsTest.js index 0333baf6c..9149eab4e 100644 --- a/Examples/UIExplorer/UIExplorerIntegrationTests/js/LayoutEventsTest.js +++ b/Examples/UIExplorer/UIExplorerIntegrationTests/js/LayoutEventsTest.js @@ -20,7 +20,7 @@ var { Text, View, } = React; -var TestModule = NativeModules.TestModule || NativeModules.SnapshotTestManager; +var TestModule = NativeModules.TestModule; var deepDiffer = require('deepDiffer'); diff --git a/Examples/UIExplorer/UIExplorerList.ios.js b/Examples/UIExplorer/UIExplorerList.ios.js index d45f4ab70..436982dfe 100644 --- a/Examples/UIExplorer/UIExplorerList.ios.js +++ b/Examples/UIExplorer/UIExplorerList.ios.js @@ -60,7 +60,8 @@ var APIS = [ require('./ActionSheetIOSExample'), require('./AdSupportIOSExample'), require('./AlertIOSExample'), - require('./AnimationExample/AnExApp'), + require('./AnimatedExample'), + require('./AnimatedGratuitousApp/AnExApp'), require('./AppStateIOSExample'), require('./AsyncStorageExample'), require('./BorderExample'), diff --git a/JSCLegacyProfiler/Makefile b/JSCLegacyProfiler/Makefile index 306c6632c..7121d6e27 100644 --- a/JSCLegacyProfiler/Makefile +++ b/JSCLegacyProfiler/Makefile @@ -4,7 +4,7 @@ SDK_PATH = /Applications/Xcode.app/Contents/Developer/Platforms/$1.platform/Deve SDK_VERSION = $(shell plutil -convert json -o - $(call SDK_PATH,iPhoneOS)/SDKSettings.plist | awk -f parseSDKVersion.awk) -CERT ?= "iPhone Developer" +CERT ?= iPhone Developer ARCHS = x86_64 arm64 armv7 i386 @@ -26,13 +26,12 @@ else cp $^ endif -/tmp/JSCProfiler: +/tmp/RCTJSCProfiler: mkdir -p $@ -.PRECIOUS: RCTJSCProfiler.ios8.dylib RCTJSCProfiler.ios8.dylib: RCTJSCProfiler_unsigned.ios8.dylib cp $< $@ - codesign -f -s ${CERT} $@ || rm $@ + codesign -f -s "${CERT}" $@ .PRECIOUS: RCTJSCProfiler_unsigned.ios8.dylib RCTJSCProfiler_unsigned.ios8.dylib: $(patsubst %,RCTJSCProfiler_%.ios8.dylib,$(ARCHS)) @@ -77,7 +76,7 @@ libyajl_%.a: download/yajl-2.1.0 .PRECIOUS: download/yajl-2.1.0 download/yajl-2.1.0: download/yajl-2.1.0.tar.gz - tar -zxvf $< -C download + tar -zxvf $< -C download > /dev/null mkdir -p download/yajl-2.1.0/build && cd download/yajl-2.1.0/build && cmake .. .PRECIOUS: download/yajl-2.1.0.tar.gz @@ -87,7 +86,7 @@ download/yajl-2.1.0.tar.gz: .PRECIOUS: download/% download/%: download/%.tar.gz - tar -zxvf $< -C `dirname $@` + tar -zxvf $< -C `dirname $@` > /dev/null .PRECIOUS: %.tar.gz %.tar.gz: diff --git a/Libraries/Animated/Animated.js b/Libraries/Animated/Animated.js index ec4977f3b..1a357f033 100644 --- a/Libraries/Animated/Animated.js +++ b/Libraries/Animated/Animated.js @@ -503,6 +503,12 @@ type ValueListenerCallback = (state: {value: number}) => void; var _uniqueId = 1; +/** + * Standard value for driving animations. One `Animated.Value` can drive + * multiple properties in a synchronized fashion, but can only be driven by one + * mechanism at a time. Using a new mechanism (e.g. starting a new animation, + * or calling `setValue`) will stop any previous ones. + */ class AnimatedValue extends AnimatedWithChildren { _value: number; _offset: number; @@ -526,6 +532,10 @@ class AnimatedValue extends AnimatedWithChildren { return this._value + this._offset; } + /** + * Directly set the value. This will stop any animations running on the value + * and udpate all the bound properties. + */ setValue(value: number): void { if (this._animation) { this._animation.stop(); @@ -534,15 +544,29 @@ class AnimatedValue extends AnimatedWithChildren { this._updateValue(value); } + /** + * Sets an offset that is applied on top of whatever value is set, whether via + * `setValue`, an animation, or `Animated.event`. Useful for compensating + * things like the start of a pan gesture. + */ setOffset(offset: number): void { this._offset = offset; } + /** + * Merges the offset value into the base value and resets the offset to zero. + * The final output of the value is unchanged. + */ flattenOffset(): void { this._value += this._offset; this._offset = 0; } + /** + * Adds an asynchronous listener to the value so you can observe updates from + * animations or whathaveyou. This is useful because there is no way to + * syncronously read the value because it might be driven natively. + */ addListener(callback: ValueListenerCallback): string { var id = String(_uniqueId++); this._listeners[id] = callback; @@ -557,6 +581,30 @@ class AnimatedValue extends AnimatedWithChildren { this._listeners = {}; } + /** + * Stops any running animation or tracking. `callback` is invoked with the + * final value after stopping the animation, which is useful for updating + * state to match the animation position with layout. + */ + stopAnimation(callback?: ?(value: number) => void): void { + this.stopTracking(); + this._animation && this._animation.stop(); + this._animation = null; + callback && callback(this.__getValue()); + } + + /** + * Interpolates the value before updating the property, e.g. mapping 0-1 to + * 0-10. + */ + interpolate(config: InterpolationConfigType): AnimatedInterpolation { + return new AnimatedInterpolation(this, Interpolation.create(config)); + } + + /** + * Typically only used internally, but could be used by a custom Animation + * class. + */ animate(animation: Animation, callback: ?EndCallback): void { var handle = InteractionManager.createInteractionHandle(); var previousAnimation = this._animation; @@ -576,27 +624,22 @@ class AnimatedValue extends AnimatedWithChildren { ); } - stopAnimation(callback?: ?(value: number) => void): void { - this.stopTracking(); - this._animation && this._animation.stop(); - this._animation = null; - callback && callback(this.__getValue()); - } - + /** + * Typically only used internally. + */ stopTracking(): void { this._tracking && this._tracking.__detach(); this._tracking = null; } + /** + * Typically only used internally. + */ track(tracking: Animated): void { this.stopTracking(); this._tracking = tracking; } - interpolate(config: InterpolationConfigType): AnimatedInterpolation { - return new AnimatedInterpolation(this, Interpolation.create(config)); - } - _updateValue(value: number): void { this._value = value; _flush(this); @@ -607,6 +650,45 @@ class AnimatedValue extends AnimatedWithChildren { } type ValueXYListenerCallback = (value: {x: number; y: number}) => void; + +/** + * 2D Value for driving 2D animations, such as pan gestures. Almost identical + * API to normal `Animated.Value`, but multiplexed. Contains two regular + * `Animated.Value`s under the hood. Example: + * + *```javascript + * class DraggableView extends React.Component { + * constructor(props) { + * super(props); + * this.state = { + * pan: new Animated.ValueXY(), // inits to zero + * }; + * this.state.panResponder = PanResponder.create({ + * onStartShouldSetPanResponder: () => true, + * onPanResponderMove: Animated.event([null, { + * dx: this.state.pan.x, // x,y are Animated.Value + * dy: this.state.pan.y, + * }]), + * onPanResponderRelease: () => { + * Animated.spring( + * this.state.pan, // Auto-multiplexed + * {toValue: {x: 0, y: 0}} // Back to zero + * ).start(); + * }, + * }); + * } + * render() { + * return ( + * + * {this.props.children} + * + * ); + * } + * } + *``` + */ class AnimatedValueXY extends AnimatedWithChildren { x: AnimatedValue; y: AnimatedValue; @@ -677,6 +759,13 @@ class AnimatedValueXY extends AnimatedWithChildren { delete this._listeners[id]; } + /** + * Converts `{x, y}` into `{left, top}` for use in style, e.g. + * + *```javascript + * style={this.state.anim.getLayout()} + *``` + */ getLayout(): {[key: string]: AnimatedValue} { return { left: this.x, @@ -684,6 +773,15 @@ class AnimatedValueXY extends AnimatedWithChildren { }; } + /** + * Converts `{x, y}` into a useable translation transform, e.g. + * + *```javascript + * style={{ + * transform: this.state.anim.getTranslateTransform() + * }} + *``` + */ getTranslateTransform(): Array<{[key: string]: AnimatedValue}> { return [ {translateX: this.x}, @@ -1235,21 +1333,6 @@ var stagger = function( type Mapping = {[key: string]: Mapping} | AnimatedValue; -/** - * Takes an array of mappings and extracts values from each arg accordingly, - * then calls setValue on the mapped outputs. e.g. - * - * onScroll={this.AnimatedEvent( - * [{nativeEvent: {contentOffset: {x: this._scrollX}}}] - * {listener} // optional listener invoked asynchronously - * ) - * ... - * onPanResponderMove: this.AnimatedEvent([ - * null, // raw event arg - * {dx: this._panX}, // gestureState arg - * ]), - * - */ type EventConfig = {listener?: ?Function}; var event = function( argMapping: Array, @@ -1287,23 +1370,179 @@ var event = function( }; }; +/** + * Animations are an important part of modern UX, and the `Animated` + * library is designed to make them fluid, powerful, and easy to build and + * maintain. + * + * The simplest workflow is to create an `Animated.Value`, hook it up to one or + * more style attributes of an animated component, and then drive updates either + * via animations, such as `Animated.timing`, or by hooking into gestures like + * panning or scolling via `Animated.event`. `Animated.Value` can also bind to + * props other than style, and can be interpolated as well. Here is a basic + * example of a container view that will fade in when it's mounted: + * + *```javascript + * class FadeInView extends React.Component { + * constructor(props) { + * super(props); + * this.state = { + * fadeAnim: new Animated.Value(0), // init opacity 0 + * }; + * } + * componentDidMount() { + * Animated.timing( // Uses easing functions + * this.state.fadeAnim, // The value to drive + * {toValue: 1}, // Configuration + * ).start(); // Don't forget start! + * } + * render() { + * return ( + * // Binds + * {this.props.children} + * + * ); + * } + * } + *``` + * + * Note that only animatable components can be animated. `View`, `Text`, and + * `Image` are already provided, and you can create custom ones with + * `createAnimatedComponent`. These special components do the magic of binding + * the animated values to the properties, and do targetted native updates to + * avoid the cost of the react render and reconciliation process on every frame. + * They also handle cleanup on unmount so they are safe by default. + * + * Animations are heavily configurable. Custom and pre-defined easing + * functions, delays, durations, decay factors, spring constants, and more can + * all be tweaked depending on the type of animation. + * + * A single `Animated.Value` can drive any number of properties, and each + * property can be run through an interpolation first. An interpolation maps + * input ranges to output ranges, typically using a linear interpolation but + * also supports easing functions. By default, it will extrapolate the curve + * beyond the ranges given, but you can also have it clamp the output value. + * + * For example, you may want to think about your `Animated.Value` as going from + * 0 to 1, but animate the position from 150px to 0px and the opacity from 0 to + * 1. This can easily be done by modifying `style` in the example above like so: + * + *```javascript + * style={{ + * opacity: this.state.fadeAnim, // Binds directly + * transform: [{ + * translateY: this.state.fadeAnim.interpolate({ + * inputRange: [0, 1], + * outputRange: [150, 0] // 0 : 150, 0.5 : 75, 1 : 0 + * }), + * }], + * }}> + *``` + * + * Animations can also be combined in complex ways using composition functions + * such as `sequence` and `parallel`, and can also be chained together simply + * by setting the `toValue` of one animation to be another `Animated.Value`. + * + * `Animated.ValueXY` is handy for 2D animations, like panning, and there are + * other helpful additions like `setOffset` and `getLayout` to aid with typical + * interaction patterns, like drag-and-drop. + * + * You can see more example usage in `AnimationExample.js`, the Gratuitous + * Animation App, and [Animations documentation guide](http://facebook.github.io/react-native/docs/animations.html). + * + * Note that `Animated` is designed to be fully serializable so that animations + * can be run in a high performace way, independent of the normal JavaScript + * event loop. This does influence the API, so keep that in mind when it seems a + * little trickier to do something compared to a fully synchronous system. + * Checkout `Animated.Value.addListener` as a way to work around some of these + * limitations, but use it sparingly since it might have performance + * implications in the future. + */ module.exports = { - delay, - sequence, - parallel, - stagger, + /** + * Standard value class for driving animations. Typically initialized with + * `new Animated.Value(0);` + */ + Value: AnimatedValue, + /** + * 2D value class for driving 2D animations, such as pan gestures. + */ + ValueXY: AnimatedValueXY, + /** + * An animatable View component. + */ + View: createAnimatedComponent(View), + /** + * An animatable Text component. + */ + Text: createAnimatedComponent(Text), + /** + * An animatable Image component. + */ + Image: createAnimatedComponent(Image), + + /** + * Animates a value from an initial velocity to zero based on a decay + * coefficient. + */ decay, + /** + * Animates a value along a timed easing curve. The `Easing` module has tons + * of pre-defined curves, or you can use your own function. + */ timing, + /** + * Spring animation based on Rebound and Origami. Tracks velocity state to + * create fluid motions as the `toValue` updates, and can be chained together. + */ spring, + /** + * Starts an animation after the given delay. + */ + delay, + /** + * Starts an array of animations in order, waiting for each to complete + * before starting the next. If the current running animation is stopped, no + * following animations will be started. + */ + sequence, + /** + * Starts an array of animations all at the same time. By default, if one + * of the animations is stopped, they will all be stopped. You can override + * this with the `stopTogether` flag. + */ + parallel, + /** + * Array of animations may run in parallel (overlap), but are started in + * sequence with successive delays. Nice for doing trailing effects. + */ + stagger, + + /** + * Takes an array of mappings and extracts values from each arg accordingly, + * then calls `setValue` on the mapped outputs. e.g. + * + *```javascript + * onScroll={this.AnimatedEvent( + * [{nativeEvent: {contentOffset: {x: this._scrollX}}}] + * {listener}, // Optional async listener + * ) + * ... + * onPanResponderMove: this.AnimatedEvent([ + * null, // raw event arg ignored + * {dx: this._panX}, // gestureState arg + * ]), + *``` + */ event, - Value: AnimatedValue, - ValueXY: AnimatedValueXY, - __PropsOnlyForTests: AnimatedProps, - View: createAnimatedComponent(View), - Text: createAnimatedComponent(Text), - Image: createAnimatedComponent(Image), + /** + * Make any React component Animatable. Used to create `Animated.View`, etc. + */ createAnimatedComponent, + + __PropsOnlyForTests: AnimatedProps, }; diff --git a/Libraries/Animated/Easing.js b/Libraries/Animated/Easing.js index fe40b20b2..0b7b9099d 100644 --- a/Libraries/Animated/Easing.js +++ b/Libraries/Animated/Easing.js @@ -123,12 +123,18 @@ class Easing { return easing; } + /** + * Runs an easing function backwards. + */ static out( easing: (t: number) => number, ): (t: number) => number { return (t) => 1 - easing(1 - t); } + /** + * Makes any easing function symmetrical. + */ static inOut( easing: (t: number) => number, ): (t: number) => number { diff --git a/Libraries/Image/ImagePickerIOS.js b/Libraries/CameraRoll/ImagePickerIOS.js similarity index 100% rename from Libraries/Image/ImagePickerIOS.js rename to Libraries/CameraRoll/ImagePickerIOS.js diff --git a/Libraries/Image/RCTAssetsLibraryImageLoader.h b/Libraries/CameraRoll/RCTAssetsLibraryImageLoader.h similarity index 100% rename from Libraries/Image/RCTAssetsLibraryImageLoader.h rename to Libraries/CameraRoll/RCTAssetsLibraryImageLoader.h diff --git a/Libraries/Image/RCTAssetsLibraryImageLoader.m b/Libraries/CameraRoll/RCTAssetsLibraryImageLoader.m similarity index 100% rename from Libraries/Image/RCTAssetsLibraryImageLoader.m rename to Libraries/CameraRoll/RCTAssetsLibraryImageLoader.m diff --git a/Libraries/CameraRoll/RCTCameraRoll.xcodeproj/project.pbxproj b/Libraries/CameraRoll/RCTCameraRoll.xcodeproj/project.pbxproj new file mode 100644 index 000000000..56cced214 --- /dev/null +++ b/Libraries/CameraRoll/RCTCameraRoll.xcodeproj/project.pbxproj @@ -0,0 +1,296 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 137620351B31C53500677FF0 /* RCTImagePickerManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 137620341B31C53500677FF0 /* RCTImagePickerManager.m */; }; + 143879351AAD238D00F088A5 /* RCTCameraRollManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 143879341AAD238D00F088A5 /* RCTCameraRollManager.m */; }; + 8312EAEE1B85EB7C001867A2 /* RCTAssetsLibraryImageLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 8312EAED1B85EB7C001867A2 /* RCTAssetsLibraryImageLoader.m */; }; + 8312EAF11B85F071001867A2 /* RCTPhotoLibraryImageLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 8312EAF01B85F071001867A2 /* RCTPhotoLibraryImageLoader.m */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 58B5115B1A9E6B3D00147676 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = "include/$(PRODUCT_NAME)"; + dstSubfolderSpec = 16; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 137620331B31C53500677FF0 /* RCTImagePickerManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTImagePickerManager.h; sourceTree = ""; }; + 137620341B31C53500677FF0 /* RCTImagePickerManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTImagePickerManager.m; sourceTree = ""; }; + 143879331AAD238D00F088A5 /* RCTCameraRollManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTCameraRollManager.h; sourceTree = ""; }; + 143879341AAD238D00F088A5 /* RCTCameraRollManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTCameraRollManager.m; sourceTree = ""; }; + 58B5115D1A9E6B3D00147676 /* libRCTCameraRoll.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRCTCameraRoll.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 8312EAEC1B85EB7C001867A2 /* RCTAssetsLibraryImageLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTAssetsLibraryImageLoader.h; sourceTree = ""; }; + 8312EAED1B85EB7C001867A2 /* RCTAssetsLibraryImageLoader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTAssetsLibraryImageLoader.m; sourceTree = ""; }; + 8312EAEF1B85F071001867A2 /* RCTPhotoLibraryImageLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTPhotoLibraryImageLoader.h; sourceTree = ""; }; + 8312EAF01B85F071001867A2 /* RCTPhotoLibraryImageLoader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTPhotoLibraryImageLoader.m; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 58B5115A1A9E6B3D00147676 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 58B511541A9E6B3D00147676 = { + isa = PBXGroup; + children = ( + 8312EAEC1B85EB7C001867A2 /* RCTAssetsLibraryImageLoader.h */, + 8312EAED1B85EB7C001867A2 /* RCTAssetsLibraryImageLoader.m */, + 143879331AAD238D00F088A5 /* RCTCameraRollManager.h */, + 143879341AAD238D00F088A5 /* RCTCameraRollManager.m */, + 137620331B31C53500677FF0 /* RCTImagePickerManager.h */, + 137620341B31C53500677FF0 /* RCTImagePickerManager.m */, + 8312EAEF1B85F071001867A2 /* RCTPhotoLibraryImageLoader.h */, + 8312EAF01B85F071001867A2 /* RCTPhotoLibraryImageLoader.m */, + 58B5115E1A9E6B3D00147676 /* Products */, + ); + indentWidth = 2; + sourceTree = ""; + tabWidth = 2; + }; + 58B5115E1A9E6B3D00147676 /* Products */ = { + isa = PBXGroup; + children = ( + 58B5115D1A9E6B3D00147676 /* libRCTCameraRoll.a */, + ); + name = Products; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 58B5115C1A9E6B3D00147676 /* RCTCameraRoll */ = { + isa = PBXNativeTarget; + buildConfigurationList = 58B511711A9E6B3D00147676 /* Build configuration list for PBXNativeTarget "RCTCameraRoll" */; + buildPhases = ( + 58B511591A9E6B3D00147676 /* Sources */, + 58B5115A1A9E6B3D00147676 /* Frameworks */, + 58B5115B1A9E6B3D00147676 /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = RCTCameraRoll; + productName = RCTNetworkImage; + productReference = 58B5115D1A9E6B3D00147676 /* libRCTCameraRoll.a */; + productType = "com.apple.product-type.library.static"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 58B511551A9E6B3D00147676 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0610; + ORGANIZATIONNAME = Facebook; + TargetAttributes = { + 58B5115C1A9E6B3D00147676 = { + CreatedOnToolsVersion = 6.1.1; + }; + }; + }; + buildConfigurationList = 58B511581A9E6B3D00147676 /* Build configuration list for PBXProject "RCTCameraRoll" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 58B511541A9E6B3D00147676; + productRefGroup = 58B5115E1A9E6B3D00147676 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 58B5115C1A9E6B3D00147676 /* RCTCameraRoll */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + 58B511591A9E6B3D00147676 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8312EAEE1B85EB7C001867A2 /* RCTAssetsLibraryImageLoader.m in Sources */, + 8312EAF11B85F071001867A2 /* RCTPhotoLibraryImageLoader.m in Sources */, + 137620351B31C53500677FF0 /* RCTImagePickerManager.m in Sources */, + 143879351AAD238D00F088A5 /* RCTCameraRollManager.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 58B5116F1A9E6B3D00147676 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; + GCC_WARN_SHADOW = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 7.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + WARNING_CFLAGS = ( + "-Werror", + "-Wall", + ); + }; + name = Debug; + }; + 58B511701A9E6B3D00147676 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = YES; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; + GCC_WARN_SHADOW = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 7.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + WARNING_CFLAGS = ( + "-Werror", + "-Wall", + ); + }; + name = Release; + }; + 58B511721A9E6B3D00147676 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_STATIC_ANALYZER_MODE = deep; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../../React/**", + "$(SRCROOT)/../Image/**", + "$(SRCROOT)/../Network/**", + ); + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(USER_LIBRARY_DIR)/Developer/Xcode/DerivedData/UIExplorer-gjaibsjtheitasdxdtcvxxqavkvy/Build/Products/Debug-iphoneos", + ); + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_NAME = RCTCameraRoll; + RUN_CLANG_STATIC_ANALYZER = YES; + SKIP_INSTALL = YES; + }; + name = Debug; + }; + 58B511731A9E6B3D00147676 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_STATIC_ANALYZER_MODE = deep; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../../React/**", + "$(SRCROOT)/../Image/**", + "$(SRCROOT)/../Network/**", + ); + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(USER_LIBRARY_DIR)/Developer/Xcode/DerivedData/UIExplorer-gjaibsjtheitasdxdtcvxxqavkvy/Build/Products/Debug-iphoneos", + ); + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_NAME = RCTCameraRoll; + RUN_CLANG_STATIC_ANALYZER = NO; + SKIP_INSTALL = YES; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 58B511581A9E6B3D00147676 /* Build configuration list for PBXProject "RCTCameraRoll" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 58B5116F1A9E6B3D00147676 /* Debug */, + 58B511701A9E6B3D00147676 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 58B511711A9E6B3D00147676 /* Build configuration list for PBXNativeTarget "RCTCameraRoll" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 58B511721A9E6B3D00147676 /* Debug */, + 58B511731A9E6B3D00147676 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 58B511551A9E6B3D00147676 /* Project object */; +} diff --git a/Libraries/Image/RCTCameraRollManager.h b/Libraries/CameraRoll/RCTCameraRollManager.h similarity index 100% rename from Libraries/Image/RCTCameraRollManager.h rename to Libraries/CameraRoll/RCTCameraRollManager.h diff --git a/Libraries/Image/RCTCameraRollManager.m b/Libraries/CameraRoll/RCTCameraRollManager.m similarity index 100% rename from Libraries/Image/RCTCameraRollManager.m rename to Libraries/CameraRoll/RCTCameraRollManager.m diff --git a/Libraries/Image/RCTImagePickerManager.h b/Libraries/CameraRoll/RCTImagePickerManager.h similarity index 100% rename from Libraries/Image/RCTImagePickerManager.h rename to Libraries/CameraRoll/RCTImagePickerManager.h diff --git a/Libraries/Image/RCTImagePickerManager.m b/Libraries/CameraRoll/RCTImagePickerManager.m similarity index 100% rename from Libraries/Image/RCTImagePickerManager.m rename to Libraries/CameraRoll/RCTImagePickerManager.m diff --git a/Libraries/Image/RCTPhotoLibraryImageLoader.h b/Libraries/CameraRoll/RCTPhotoLibraryImageLoader.h similarity index 100% rename from Libraries/Image/RCTPhotoLibraryImageLoader.h rename to Libraries/CameraRoll/RCTPhotoLibraryImageLoader.h diff --git a/Libraries/Image/RCTPhotoLibraryImageLoader.m b/Libraries/CameraRoll/RCTPhotoLibraryImageLoader.m similarity index 100% rename from Libraries/Image/RCTPhotoLibraryImageLoader.m rename to Libraries/CameraRoll/RCTPhotoLibraryImageLoader.m diff --git a/Libraries/Components/TextInput/TextInput.js b/Libraries/Components/TextInput/TextInput.js index f114ac18f..d7901aed0 100644 --- a/Libraries/Components/TextInput/TextInput.js +++ b/Libraries/Components/TextInput/TextInput.js @@ -49,6 +49,7 @@ var AndroidTextInputAttributes = { keyboardType: true, mostRecentEventCount: true, multiline: true, + numberOfLines: true, password: true, placeholder: true, placeholderTextColor: true, @@ -193,6 +194,12 @@ var TextInput = React.createClass({ * @platform ios */ maxLength: PropTypes.number, + /** + * Sets the number of lines for a TextInput. Use it with multiline set to + * true to be able to fill the lines. + * @platform android + */ + numberOfLines: PropTypes.number, /** * If true, the keyboard disables the return key when there is no text and * automatically enables it when there is text. The default value is false. @@ -484,6 +491,7 @@ var TextInput = React.createClass({ keyboardType={this.props.keyboardType} mostRecentEventCount={this.state.mostRecentEventCount} multiline={this.props.multiline} + numberOfLines={this.props.numberOfLines} onFocus={this._onFocus} onBlur={this._onBlur} onChange={this._onChange} diff --git a/Libraries/Components/Touchable/TouchableHighlight.js b/Libraries/Components/Touchable/TouchableHighlight.js index 27ddcdd4e..1850a278c 100644 --- a/Libraries/Components/Touchable/TouchableHighlight.js +++ b/Libraries/Components/Touchable/TouchableHighlight.js @@ -209,6 +209,8 @@ var TouchableHighlight = React.createClass({ return ( 1) { - const NSTimeInterval kDelayTimeIntervalDefault = 0.1; - NSNumber *delayTime = frameGIFProperties[(id)kCGImagePropertyGIFUnclampedDelayTime] ?: frameGIFProperties[(id)kCGImagePropertyGIFDelayTime]; - if (delayTime == nil) { - if (i == 0) { - delayTime = @(kDelayTimeIntervalDefault); - } else { - delayTime = delays[i - 1]; + NSTimeInterval duration = 0; + NSMutableArray *delays = [NSMutableArray arrayWithCapacity:imageCount]; + NSMutableArray *images = [NSMutableArray arrayWithCapacity:imageCount]; + for (size_t i = 0; i < imageCount; i++) { + + CGImageRef imageRef = CGImageSourceCreateImageAtIndex(imageSource, i, NULL); + if (!image) { + image = [UIImage imageWithCGImage:imageRef]; } + + NSDictionary *frameProperties = (__bridge_transfer NSDictionary *)CGImageSourceCopyPropertiesAtIndex(imageSource, i, NULL); + NSDictionary *frameGIFProperties = frameProperties[(id)kCGImagePropertyGIFDictionary]; + + const NSTimeInterval kDelayTimeIntervalDefault = 0.1; + NSNumber *delayTime = frameGIFProperties[(id)kCGImagePropertyGIFUnclampedDelayTime] ?: frameGIFProperties[(id)kCGImagePropertyGIFDelayTime]; + if (delayTime == nil) { + if (i == 0) { + delayTime = @(kDelayTimeIntervalDefault); + } else { + delayTime = delays[i - 1]; + } + } + + const NSTimeInterval kDelayTimeIntervalMinimum = 0.02; + if (delayTime.floatValue < (float)kDelayTimeIntervalMinimum - FLT_EPSILON) { + delayTime = @(kDelayTimeIntervalDefault); + } + + duration += delayTime.doubleValue; + delays[i] = delayTime; + images[i] = (__bridge_transfer id)imageRef; + } + CFRelease(imageSource); + + NSMutableArray *keyTimes = [NSMutableArray arrayWithCapacity:delays.count]; + NSTimeInterval runningDuration = 0; + for (NSNumber *delayNumber in delays) { + [keyTimes addObject:@(runningDuration / duration)]; + runningDuration += delayNumber.doubleValue; } - const NSTimeInterval kDelayTimeIntervalMinimum = 0.02; - if (delayTime.floatValue < (float)kDelayTimeIntervalMinimum - FLT_EPSILON) { - delayTime = @(kDelayTimeIntervalDefault); + [keyTimes addObject:@1.0]; + + // Create animation + CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"contents"]; + animation.calculationMode = kCAAnimationDiscrete; + animation.repeatCount = loopCount == 0 ? HUGE_VALF : loopCount; + animation.keyTimes = keyTimes; + animation.values = images; + animation.duration = duration; + image.reactKeyframeAnimation = animation; + + } else { + + // Don't bother creating an animation + CGImageRef imageRef = CGImageSourceCreateImageAtIndex(imageSource, 0, NULL); + if (imageRef) { + image = [UIImage imageWithCGImage:imageRef]; + CFRelease(imageRef); } - - duration += delayTime.doubleValue; - delays[i] = delayTime; - images[i] = (__bridge_transfer id)image; - } - CFRelease(imageSource); - - NSMutableArray *keyTimes = [NSMutableArray arrayWithCapacity:delays.count]; - NSTimeInterval runningDuration = 0; - for (NSNumber *delayNumber in delays) { - [keyTimes addObject:@(runningDuration / duration)]; - runningDuration += delayNumber.doubleValue; + CFRelease(imageSource); } - [keyTimes addObject:@1.0]; - - CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"contents"]; - animation.calculationMode = kCAAnimationDiscrete; - animation.repeatCount = loopCount == 0 ? HUGE_VALF : loopCount; - animation.keyTimes = keyTimes; - animation.values = images; - animation.duration = duration; - completionHandler(nil, animation); - - return nil; + completionHandler(nil, image); + return ^{}; } @end diff --git a/Libraries/Image/RCTImage.xcodeproj/project.pbxproj b/Libraries/Image/RCTImage.xcodeproj/project.pbxproj index 06029c731..183cb850e 100644 --- a/Libraries/Image/RCTImage.xcodeproj/project.pbxproj +++ b/Libraries/Image/RCTImage.xcodeproj/project.pbxproj @@ -11,14 +11,10 @@ 1304D5AC1AA8C4A30002E2BE /* RCTImageViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1304D5AA1AA8C4A30002E2BE /* RCTImageViewManager.m */; }; 1304D5B21AA8C50D0002E2BE /* RCTGIFImageDecoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 1304D5B11AA8C50D0002E2BE /* RCTGIFImageDecoder.m */; }; 134B00A21B54232B00EC8DFB /* RCTImageUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 134B00A11B54232B00EC8DFB /* RCTImageUtils.m */; }; - 137620351B31C53500677FF0 /* RCTImagePickerManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 137620341B31C53500677FF0 /* RCTImagePickerManager.m */; }; - 143879351AAD238D00F088A5 /* RCTCameraRollManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 143879341AAD238D00F088A5 /* RCTCameraRollManager.m */; }; 143879381AAD32A300F088A5 /* RCTImageLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 143879371AAD32A300F088A5 /* RCTImageLoader.m */; }; 35123E6B1B59C99D00EBAD80 /* RCTImageStoreManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 35123E6A1B59C99D00EBAD80 /* RCTImageStoreManager.m */; }; 354631681B69857700AA0B86 /* RCTImageEditingManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 354631671B69857700AA0B86 /* RCTImageEditingManager.m */; }; 58B5118F1A9E6BD600147676 /* RCTImageDownloader.m in Sources */ = {isa = PBXBuildFile; fileRef = 58B5118A1A9E6BD600147676 /* RCTImageDownloader.m */; }; - 8312EAEE1B85EB7C001867A2 /* RCTAssetsLibraryImageLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 8312EAED1B85EB7C001867A2 /* RCTAssetsLibraryImageLoader.m */; }; - 8312EAF11B85F071001867A2 /* RCTPhotoLibraryImageLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 8312EAF01B85F071001867A2 /* RCTPhotoLibraryImageLoader.m */; }; 83DDA1571B8DCA5800892A1C /* RCTAssetBundleImageLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 83DDA1561B8DCA5800892A1C /* RCTAssetBundleImageLoader.m */; }; /* End PBXBuildFile section */ @@ -43,10 +39,6 @@ 1304D5B11AA8C50D0002E2BE /* RCTGIFImageDecoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTGIFImageDecoder.m; sourceTree = ""; }; 134B00A01B54232B00EC8DFB /* RCTImageUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTImageUtils.h; sourceTree = ""; }; 134B00A11B54232B00EC8DFB /* RCTImageUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTImageUtils.m; sourceTree = ""; }; - 137620331B31C53500677FF0 /* RCTImagePickerManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTImagePickerManager.h; sourceTree = ""; }; - 137620341B31C53500677FF0 /* RCTImagePickerManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTImagePickerManager.m; sourceTree = ""; }; - 143879331AAD238D00F088A5 /* RCTCameraRollManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTCameraRollManager.h; sourceTree = ""; }; - 143879341AAD238D00F088A5 /* RCTCameraRollManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTCameraRollManager.m; sourceTree = ""; }; 143879361AAD32A300F088A5 /* RCTImageLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTImageLoader.h; sourceTree = ""; }; 143879371AAD32A300F088A5 /* RCTImageLoader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTImageLoader.m; sourceTree = ""; }; 35123E691B59C99D00EBAD80 /* RCTImageStoreManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTImageStoreManager.h; sourceTree = ""; }; @@ -56,10 +48,6 @@ 58B5115D1A9E6B3D00147676 /* libRCTImage.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRCTImage.a; sourceTree = BUILT_PRODUCTS_DIR; }; 58B511891A9E6BD600147676 /* RCTImageDownloader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTImageDownloader.h; sourceTree = ""; }; 58B5118A1A9E6BD600147676 /* RCTImageDownloader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTImageDownloader.m; sourceTree = ""; }; - 8312EAEC1B85EB7C001867A2 /* RCTAssetsLibraryImageLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTAssetsLibraryImageLoader.h; sourceTree = ""; }; - 8312EAED1B85EB7C001867A2 /* RCTAssetsLibraryImageLoader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTAssetsLibraryImageLoader.m; sourceTree = ""; }; - 8312EAEF1B85F071001867A2 /* RCTPhotoLibraryImageLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTPhotoLibraryImageLoader.h; sourceTree = ""; }; - 8312EAF01B85F071001867A2 /* RCTPhotoLibraryImageLoader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTPhotoLibraryImageLoader.m; sourceTree = ""; }; 83DDA1551B8DCA5800892A1C /* RCTAssetBundleImageLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTAssetBundleImageLoader.h; sourceTree = ""; }; 83DDA1561B8DCA5800892A1C /* RCTAssetBundleImageLoader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTAssetBundleImageLoader.m; sourceTree = ""; }; /* End PBXFileReference section */ @@ -80,10 +68,6 @@ children = ( 83DDA1551B8DCA5800892A1C /* RCTAssetBundleImageLoader.h */, 83DDA1561B8DCA5800892A1C /* RCTAssetBundleImageLoader.m */, - 8312EAEC1B85EB7C001867A2 /* RCTAssetsLibraryImageLoader.h */, - 8312EAED1B85EB7C001867A2 /* RCTAssetsLibraryImageLoader.m */, - 143879331AAD238D00F088A5 /* RCTCameraRollManager.h */, - 143879341AAD238D00F088A5 /* RCTCameraRollManager.m */, 1304D5B01AA8C50D0002E2BE /* RCTGIFImageDecoder.h */, 1304D5B11AA8C50D0002E2BE /* RCTGIFImageDecoder.m */, 58B511891A9E6BD600147676 /* RCTImageDownloader.h */, @@ -92,8 +76,6 @@ 354631671B69857700AA0B86 /* RCTImageEditingManager.m */, 143879361AAD32A300F088A5 /* RCTImageLoader.h */, 143879371AAD32A300F088A5 /* RCTImageLoader.m */, - 137620331B31C53500677FF0 /* RCTImagePickerManager.h */, - 137620341B31C53500677FF0 /* RCTImagePickerManager.m */, 1304D5A71AA8C4A30002E2BE /* RCTImageView.h */, 1304D5A81AA8C4A30002E2BE /* RCTImageView.m */, 1304D5A91AA8C4A30002E2BE /* RCTImageViewManager.h */, @@ -102,8 +84,6 @@ 35123E6A1B59C99D00EBAD80 /* RCTImageStoreManager.m */, 134B00A01B54232B00EC8DFB /* RCTImageUtils.h */, 134B00A11B54232B00EC8DFB /* RCTImageUtils.m */, - 8312EAEF1B85F071001867A2 /* RCTPhotoLibraryImageLoader.h */, - 8312EAF01B85F071001867A2 /* RCTPhotoLibraryImageLoader.m */, 58B5115E1A9E6B3D00147676 /* Products */, ); indentWidth = 2; @@ -174,14 +154,10 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 8312EAEE1B85EB7C001867A2 /* RCTAssetsLibraryImageLoader.m in Sources */, 35123E6B1B59C99D00EBAD80 /* RCTImageStoreManager.m in Sources */, - 8312EAF11B85F071001867A2 /* RCTPhotoLibraryImageLoader.m in Sources */, 58B5118F1A9E6BD600147676 /* RCTImageDownloader.m in Sources */, - 137620351B31C53500677FF0 /* RCTImagePickerManager.m in Sources */, 1304D5AC1AA8C4A30002E2BE /* RCTImageViewManager.m in Sources */, 1304D5B21AA8C50D0002E2BE /* RCTGIFImageDecoder.m in Sources */, - 143879351AAD238D00F088A5 /* RCTCameraRollManager.m in Sources */, 143879381AAD32A300F088A5 /* RCTImageLoader.m in Sources */, 354631681B69857700AA0B86 /* RCTImageEditingManager.m in Sources */, 1304D5AB1AA8C4A30002E2BE /* RCTImageView.m in Sources */, diff --git a/Libraries/Image/RCTImageDownloader.m b/Libraries/Image/RCTImageDownloader.m index f110bd628..c2aa89f73 100644 --- a/Libraries/Image/RCTImageDownloader.m +++ b/Libraries/Image/RCTImageDownloader.m @@ -50,7 +50,7 @@ RCT_EXPORT_MODULE() */ - (RCTImageLoaderCancellationBlock)downloadDataForURL:(NSURL *)url progressHandler:(RCTImageLoaderProgressBlock)progressBlock - completionHandler:(RCTImageLoaderCompletionBlock)completionBlock + completionHandler:(void (^)(NSError *error, NSData *data))completionBlock { if (![_bridge respondsToSelector:NSSelectorFromString(@"networking")]) { RCTLogError(@"You need to import the RCTNetworking library in order to download remote images."); diff --git a/Libraries/Image/RCTImageLoader.h b/Libraries/Image/RCTImageLoader.h index bba887602..a55df421b 100644 --- a/Libraries/Image/RCTImageLoader.h +++ b/Libraries/Image/RCTImageLoader.h @@ -15,10 +15,15 @@ @class ALAssetsLibrary; typedef void (^RCTImageLoaderProgressBlock)(int64_t progress, int64_t total); -typedef void (^RCTImageLoaderCompletionBlock)(NSError *error, id image /* UIImage or CAAnimation */); -typedef void (^RCTImageLoaderCompletionBlock)(NSError *error, id image /* NSData, UIImage, CAAnimation */); +typedef void (^RCTImageLoaderCompletionBlock)(NSError *error, UIImage *image); typedef void (^RCTImageLoaderCancellationBlock)(void); +@interface UIImage (React) + +@property (nonatomic, copy) CAKeyframeAnimation *reactKeyframeAnimation; + +@end + @interface RCTImageLoader : NSObject /** diff --git a/Libraries/Image/RCTImageLoader.m b/Libraries/Image/RCTImageLoader.m index 422a189d5..50040c95f 100644 --- a/Libraries/Image/RCTImageLoader.m +++ b/Libraries/Image/RCTImageLoader.m @@ -28,6 +28,20 @@ static void RCTDispatchCallbackOnMainQueue(void (^callback)(NSError *, id), NSEr } } +@implementation UIImage (React) + +- (CAKeyframeAnimation *)reactKeyframeAnimation +{ + return objc_getAssociatedObject(self, _cmd); +} + +- (void)setReactKeyframeAnimation:(CAKeyframeAnimation *)reactKeyframeAnimation +{ + objc_setAssociatedObject(self, @selector(reactKeyframeAnimation), reactKeyframeAnimation, OBJC_ASSOCIATION_COPY_NONATOMIC); +} + +@end + @implementation RCTImageLoader @synthesize bridge = _bridge; @@ -99,7 +113,7 @@ RCT_EXPORT_MODULE() progressBlock(progress, total); }); } - } completionHandler:^(NSError *error, id image) { + } completionHandler:^(NSError *error, UIImage *image) { RCTDispatchCallbackOnMainQueue(completionBlock, error, image); }] ?: ^{}; } @@ -142,7 +156,7 @@ RCT_EXPORT_MODULE() { id imageDecoder = [self imageDecoderForRequest:data]; if (imageDecoder) { - return [imageDecoder decodeImageData:data size:size scale:scale resizeMode:resizeMode completionHandler:^(NSError *error, id image) { + return [imageDecoder decodeImageData:data size:size scale:scale resizeMode:resizeMode completionHandler:^(NSError *error, UIImage *image) { RCTDispatchCallbackOnMainQueue(completionBlock, error, image); }]; } else { diff --git a/Libraries/Image/RCTImageView.m b/Libraries/Image/RCTImageView.m index 01e5b2fbe..75bd62ebe 100644 --- a/Libraries/Image/RCTImageView.m +++ b/Libraries/Image/RCTImageView.m @@ -31,6 +31,7 @@ @implementation RCTImageView { RCTBridge *_bridge; + CGSize _targetSize; } - (instancetype)initWithBridge:(RCTBridge *)bridge @@ -142,10 +143,10 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init) scale:RCTScreenScale() resizeMode:self.contentMode progressBlock:progressHandler - completionBlock:^(NSError *error, id image) { + completionBlock:^(NSError *error, UIImage *image) { - if ([image isKindOfClass:[CAAnimation class]]) { - [self.layer addAnimation:image forKey:@"contents"]; + if (image.reactKeyframeAnimation) { + [self.layer addAnimation:image.reactKeyframeAnimation forKey:@"contents"]; } else { [self.layer removeAnimationForKey:@"contents"]; self.image = image; @@ -173,19 +174,17 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init) { [super reactSetFrame:frame]; if (self.image == nil) { + _targetSize = frame.size; [self reloadImage]; } else if ([RCTImageView srcNeedsReload:_src]) { - - // Get optimal image size - CGSize currentSize = self.image.size; CGSize idealSize = RCTTargetSize(self.image.size, self.image.scale, frame.size, RCTScreenScale(), self.contentMode, YES); - - CGFloat widthChangeFraction = ABS(currentSize.width - idealSize.width) / currentSize.width; - CGFloat heightChangeFraction = ABS(currentSize.height - idealSize.height) / currentSize.height; + CGFloat widthChangeFraction = ABS(_targetSize.width - idealSize.width) / _targetSize.width; + CGFloat heightChangeFraction = ABS(_targetSize.height - idealSize.height) / _targetSize.height; // If the combined change is more than 20%, reload the asset in case there is a better size. if (widthChangeFraction + heightChangeFraction > 0.2) { + _targetSize = idealSize; [self reloadImage]; } } diff --git a/Libraries/Modal/Modal.js b/Libraries/Modal/Modal.js index 2063f0fdd..8e3a88665 100644 --- a/Libraries/Modal/Modal.js +++ b/Libraries/Modal/Modal.js @@ -33,6 +33,7 @@ class Modal extends React.Component { {this.props.children} @@ -45,6 +46,7 @@ class Modal extends React.Component { Modal.propTypes = { animated: PropTypes.bool, transparent: PropTypes.bool, + onDismiss: PropTypes.func, }; var styles = StyleSheet.create({ diff --git a/Libraries/Network/NetInfo.js b/Libraries/Network/NetInfo.js index f51a95529..5c45be617 100644 --- a/Libraries/Network/NetInfo.js +++ b/Libraries/Network/NetInfo.js @@ -138,6 +138,23 @@ type ConnectivityStateAndroid = $Enum<{ var _subscriptions = new Map(); +if (Platform.OS === 'ios') { + var _isConnected = function( + reachability: ReachabilityStateIOS + ): bool { + return reachability !== 'none' && + reachability !== 'unknown'; + }; +} else if (Platform.OS === 'android') { + var _isConnected = function( + connectionType: ConnectivityStateAndroid + ): bool { + return connectionType !== 'NONE' && connectionType !== 'UNKNOWN'; + }; +} + +var _isConnectedSubscriptions = new Map(); + var NetInfo = { addEventListener: function ( eventName: ChangeEventName, @@ -175,60 +192,41 @@ var NetInfo = { }); }, - isConnected: {}, + isConnected: { + addEventListener: function ( + eventName: ChangeEventName, + handler: Function + ): void { + var listener = (connection) => { + handler(_isConnected(connection)); + }; + _isConnectedSubscriptions.set(handler, listener); + NetInfo.addEventListener( + eventName, + listener + ); + }, - isConnectionMetered: {}, -}; + removeEventListener: function( + eventName: ChangeEventName, + handler: Function + ): void { + var listener = _isConnectedSubscriptions.get(handler); + NetInfo.removeEventListener( + eventName, + listener + ); + _isConnectedSubscriptions.delete(handler); + }, -if (Platform.OS === 'ios') { - var _isConnected = function( - reachability: ReachabilityStateIOS - ): bool { - return reachability !== 'none' && - reachability !== 'unknown'; - }; -} else if (Platform.OS === 'android') { - var _isConnected = function( - connectionType: ConnectivityStateAndroid - ): bool { - return connectionType !== 'NONE' && connectionType !== 'UNKNOWN'; - }; -} - -var _isConnectedSubscriptions = new Map(); - -NetInfo.isConnected = { - addEventListener: function ( - eventName: ChangeEventName, - handler: Function - ): void { - var listener = (connection) => { - handler(_isConnected(connection)); - }; - _isConnectedSubscriptions.set(handler, listener); - NetInfo.addEventListener( - eventName, - listener - ); + fetch: function(): Promise { + return NetInfo.fetch().then( + (connection) => _isConnected(connection) + ); + }, }, - removeEventListener: function( - eventName: ChangeEventName, - handler: Function - ): void { - var listener = _isConnectedSubscriptions.get(handler); - NetInfo.removeEventListener( - eventName, - listener - ); - _isConnectedSubscriptions.delete(handler); - }, - - fetch: function(): Promise { - return NetInfo.fetch().then( - (connection) => _isConnected(connection) - ); - }, + isConnectionMetered: ({}: {} | (callback:Function) => void), }; if (Platform.OS === 'android') { diff --git a/Libraries/Network/RCTHTTPRequestHandler.m b/Libraries/Network/RCTHTTPRequestHandler.m index e1ad88ab1..fe83e3f7c 100644 --- a/Libraries/Network/RCTHTTPRequestHandler.m +++ b/Libraries/Network/RCTHTTPRequestHandler.m @@ -56,6 +56,7 @@ RCT_EXPORT_MODULE() // Lazy setup if (!_session && [self isValid]) { NSOperationQueue *callbackQueue = [NSOperationQueue new]; + callbackQueue.maxConcurrentOperationCount = 1; NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration]; _session = [NSURLSession sessionWithConfiguration:configuration delegate:self diff --git a/Libraries/Picker/PickerIOS.ios.js b/Libraries/Picker/PickerIOS.ios.js index 42302fa26..1a965b32f 100644 --- a/Libraries/Picker/PickerIOS.ios.js +++ b/Libraries/Picker/PickerIOS.ios.js @@ -111,6 +111,12 @@ var styles = StyleSheet.create({ }, }); -var RCTPickerIOS = requireNativeComponent('RCTPicker', null); +var RCTPickerIOS = requireNativeComponent('RCTPicker', PickerIOS, { + nativeOnly: { + items: true, + onChange: true, + selectedIndex: true, + }, +}); module.exports = PickerIOS; diff --git a/Libraries/RCTTest/RCTTestRunner.m b/Libraries/RCTTest/RCTTestRunner.m index b0c932bc1..41316360b 100644 --- a/Libraries/RCTTest/RCTTestRunner.m +++ b/Libraries/RCTTest/RCTTestRunner.m @@ -16,13 +16,8 @@ #import "RCTTestModule.h" #import "RCTUtils.h" -#define TIMEOUT_SECONDS 60 - -@interface RCTBridge (RCTTestRunner) - -@property (nonatomic, weak) RCTBridge *batchedBridge; - -@end +static const NSTimeInterval kTestTimeoutSeconds = 60; +static const NSTimeInterval kTestTeardownTimeoutSeconds = 30; @implementation RCTTestRunner { @@ -49,7 +44,7 @@ _scriptURL = [[NSBundle bundleForClass:[RCTBridge class]] URLForResource:@"main" withExtension:@"jsbundle"]; RCTAssert(_scriptURL != nil, @"Could not locate main.jsBundle"); #else - _scriptURL = [NSURL URLWithString:[NSString stringWithFormat:@"http://localhost:8081/%@.bundle?dev=true&platform=ios", app]]; + _scriptURL = [NSURL URLWithString:[NSString stringWithFormat:@"http://localhost:8081/%@.bundle?platform=ios&dev=true", app]]; #endif } return self; @@ -83,52 +78,69 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init) - (void)runTest:(SEL)test module:(NSString *)moduleName initialProps:(NSDictionary *)initialProps expectErrorBlock:(BOOL(^)(NSString *error))expectErrorBlock { - __block NSString *error = nil; - RCTSetLogFunction(^(RCTLogLevel level, NSString *fileName, NSNumber *lineNumber, NSString *message) { - if (level >= RCTLogLevelError) { - error = message; + __weak id weakJSContext; + + @autoreleasepool { + __block NSString *error = nil; + RCTSetLogFunction(^(RCTLogLevel level, NSString *fileName, NSNumber *lineNumber, NSString *message) { + if (level >= RCTLogLevelError) { + error = message; + } + }); + + RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:_scriptURL + moduleProvider:_moduleProvider + launchOptions:nil]; + + RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge moduleName:moduleName initialProperties:initialProps]; + rootView.frame = CGRectMake(0, 0, 320, 2000); // Constant size for testing on multiple devices + + NSString *testModuleName = RCTBridgeModuleNameForClass([RCTTestModule class]); + RCTTestModule *testModule = rootView.bridge.modules[testModuleName]; + RCTAssert(_testController != nil, @"_testController should not be nil"); + testModule.controller = _testController; + testModule.testSelector = test; + testModule.view = rootView; + + UIViewController *vc = [UIApplication sharedApplication].delegate.window.rootViewController; + vc.view = [UIView new]; + [vc.view addSubview:rootView]; // Add as subview so it doesn't get resized + + NSDate *date = [NSDate dateWithTimeIntervalSinceNow:kTestTimeoutSeconds]; + while (date.timeIntervalSinceNow > 0 && testModule.status == RCTTestStatusPending && error == nil) { + [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; + [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; } - }); - RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:_scriptURL - moduleProvider:_moduleProvider - launchOptions:nil]; + // Take a weak reference to the JS context, so we track its deallocation later + // (we can only do this now, since it's been lazily initialized) + weakJSContext = [[[bridge valueForKey:@"batchedBridge"] valueForKey:@"javaScriptExecutor"] valueForKey:@"context"]; + [rootView removeFromSuperview]; - RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge moduleName:moduleName initialProperties:initialProps]; - rootView.frame = CGRectMake(0, 0, 320, 2000); // Constant size for testing on multiple devices + RCTSetLogFunction(RCTDefaultLogFunction); - NSString *testModuleName = RCTBridgeModuleNameForClass([RCTTestModule class]); - RCTTestModule *testModule = rootView.bridge.batchedBridge.modules[testModuleName]; - RCTAssert(_testController != nil, @"_testController should not be nil"); - testModule.controller = _testController; - testModule.testSelector = test; - testModule.view = rootView; + NSArray *nonLayoutSubviews = [vc.view.subviews filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id subview, NSDictionary *bindings) { + return ![NSStringFromClass([subview class]) isEqualToString:@"_UILayoutGuide"]; + }]]; + RCTAssert(nonLayoutSubviews.count == 0, @"There shouldn't be any other views: %@", nonLayoutSubviews); - UIViewController *vc = [UIApplication sharedApplication].delegate.window.rootViewController; - vc.view = [UIView new]; - [vc.view addSubview:rootView]; // Add as subview so it doesn't get resized + if (expectErrorBlock) { + RCTAssert(expectErrorBlock(error), @"Expected an error but nothing matched."); + } else { + RCTAssert(error == nil, @"RedBox error: %@", error); + RCTAssert(testModule.status != RCTTestStatusPending, @"Test didn't finish within %0.f seconds", kTestTimeoutSeconds); + RCTAssert(testModule.status == RCTTestStatusPassed, @"Test failed"); + } + [bridge invalidate]; + } - NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS]; - while (date.timeIntervalSinceNow > 0 && testModule.status == RCTTestStatusPending && error == nil) { + // Wait for the executor to have shut down completely before returning + NSDate *teardownTimeout = [NSDate dateWithTimeIntervalSinceNow:kTestTeardownTimeoutSeconds]; + while (teardownTimeout.timeIntervalSinceNow > 0 && weakJSContext) { [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; } - [rootView removeFromSuperview]; - - RCTSetLogFunction(RCTDefaultLogFunction); - - NSArray *nonLayoutSubviews = [vc.view.subviews filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id subview, NSDictionary *bindings) { - return ![NSStringFromClass([subview class]) isEqualToString:@"_UILayoutGuide"]; - }]]; - RCTAssert(nonLayoutSubviews.count == 0, @"There shouldn't be any other views: %@", nonLayoutSubviews); - - if (expectErrorBlock) { - RCTAssert(expectErrorBlock(error), @"Expected an error but nothing matched."); - } else { - RCTAssert(error == nil, @"RedBox error: %@", error); - RCTAssert(testModule.status != RCTTestStatusPending, @"Test didn't finish within %d seconds", TIMEOUT_SECONDS); - RCTAssert(testModule.status == RCTTestStatusPassed, @"Test failed"); - } + RCTAssert(!weakJSContext, @"JS context was not deallocated after being invalidated"); } @end diff --git a/Libraries/StyleSheet/StyleSheetTypes.js b/Libraries/StyleSheet/StyleSheetTypes.js new file mode 100644 index 000000000..779e64772 --- /dev/null +++ b/Libraries/StyleSheet/StyleSheetTypes.js @@ -0,0 +1,15 @@ +/** + * 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 StyleSheetTypes + * @flow + */ +'use strict'; + +type Atom = number | bool | Object | Array; +export type StyleObj = Atom | Array; diff --git a/Libraries/StyleSheet/flattenStyle.js b/Libraries/StyleSheet/flattenStyle.js index 50e061ede..621c614ff 100644 --- a/Libraries/StyleSheet/flattenStyle.js +++ b/Libraries/StyleSheet/flattenStyle.js @@ -14,8 +14,7 @@ var StyleSheetRegistry = require('StyleSheetRegistry'); var invariant = require('invariant'); -type Atom = number | bool | Object | Array -type StyleObj = Atom | Array +import type { StyleObj } from 'StyleSheetTypes'; function getStyle(style) { if (typeof style === 'number') { diff --git a/React/Base/RCTBatchedBridge.m b/React/Base/RCTBatchedBridge.m index 3151d8005..482e213fc 100644 --- a/React/Base/RCTBatchedBridge.m +++ b/React/Base/RCTBatchedBridge.m @@ -117,8 +117,15 @@ RCT_EXTERN NSArray *RCTGetModuleClasses(void); dispatch_group_t initModulesAndLoadSource = dispatch_group_create(); dispatch_group_enter(initModulesAndLoadSource); + __weak RCTBatchedBridge *weakSelf = self; __block NSString *sourceCode; - [self loadSource:^(__unused NSError *error, NSString *source) { + [self loadSource:^(NSError *error, NSString *source) { + if (error) { + dispatch_async(dispatch_get_main_queue(), ^{ + [weakSelf stopLoadingWithError:error]; + }); + } + sourceCode = source; dispatch_group_leave(initModulesAndLoadSource); }]; @@ -131,7 +138,6 @@ RCT_EXTERN NSArray *RCTGetModuleClasses(void); RCTProfileHookModules(self); } - __weak RCTBatchedBridge *weakSelf = self; __block NSString *config; dispatch_group_enter(initModulesAndLoadSource); dispatch_async(bridgeQueue, ^{ @@ -150,16 +156,24 @@ RCT_EXTERN NSArray *RCTGetModuleClasses(void); // We're not waiting for this complete to leave the dispatch group, since // injectJSONConfiguration and executeSourceCode will schedule operations on the // same queue anyway. - [weakSelf injectJSONConfiguration:config onComplete:^(__unused NSError *error) { + [weakSelf injectJSONConfiguration:config onComplete:^(NSError *error) { RCTPerformanceLoggerEnd(RCTPLNativeModuleInit); + if (error) { + dispatch_async(dispatch_get_main_queue(), ^{ + [weakSelf stopLoadingWithError:error]; + }); + } }]; dispatch_group_leave(initModulesAndLoadSource); }); }); - dispatch_group_notify(initModulesAndLoadSource, bridgeQueue, ^{ - if (sourceCode) { - [weakSelf executeSourceCode:sourceCode]; + dispatch_group_notify(initModulesAndLoadSource, dispatch_get_main_queue(), ^{ + RCTBatchedBridge *strongSelf = weakSelf; + if (sourceCode && strongSelf.loading) { + dispatch_async(bridgeQueue, ^{ + [weakSelf executeSourceCode:sourceCode]; + }); } }); } @@ -172,23 +186,6 @@ RCT_EXTERN NSArray *RCTGetModuleClasses(void); RCTSourceLoadBlock onSourceLoad = ^(NSError *error, NSString *source) { RCTProfileEndAsyncEvent(0, @"init,download", cookie, @"JavaScript download", nil); RCTPerformanceLoggerEnd(RCTPLScriptDownload); - - if (error) { - NSArray *stack = error.userInfo[@"stack"]; - if (stack) { - [self.redBox showErrorMessage:error.localizedDescription - withStack:stack]; - } else { - [self.redBox showErrorMessage:error.localizedDescription - withDetails:error.localizedFailureReason]; - } - - NSDictionary *userInfo = @{@"bridge": self, @"error": error}; - [[NSNotificationCenter defaultCenter] postNotificationName:RCTJavaScriptDidFailToLoadNotification - object:_parentBridge - userInfo:userInfo]; - } - _onSourceLoad(error, source); }; @@ -283,7 +280,6 @@ RCT_EXTERN NSArray *RCTGetModuleClasses(void); object:self]; } - - (void)setupExecutor { [_javaScriptExecutor setUp]; @@ -313,12 +309,7 @@ RCT_EXTERN NSArray *RCTGetModuleClasses(void); [_javaScriptExecutor injectJSONText:configJSON asGlobalObjectNamed:@"__fbBatchedBridgeConfig" - callback:^(NSError *error) { - if (error) { - [self.redBox showError:error]; - } - onComplete(error); - }]; + callback:onComplete]; } - (void)executeSourceCode:(NSString *)sourceCode @@ -333,7 +324,9 @@ RCT_EXTERN NSArray *RCTGetModuleClasses(void); [self enqueueApplicationScript:sourceCode url:self.bundleURL onComplete:^(NSError *loadError) { if (loadError) { - [self.redBox showError:loadError]; + dispatch_async(dispatch_get_main_queue(), ^{ + [self stopLoadingWithError:loadError]; + }); return; } @@ -352,6 +345,28 @@ RCT_EXTERN NSArray *RCTGetModuleClasses(void); }]; } +- (void)stopLoadingWithError:(NSError *)error +{ + RCTAssertMainThread(); + + if (!self.isValid || !self.loading) { + return; + } + + _loading = NO; + + NSArray *stack = error.userInfo[@"stack"]; + if (stack) { + [self.redBox showErrorMessage:error.localizedDescription withStack:stack]; + } else { + [self.redBox showError:error]; + } + + NSDictionary *userInfo = @{@"bridge": self, @"error": error}; + [[NSNotificationCenter defaultCenter] postNotificationName:RCTJavaScriptDidFailToLoadNotification + object:_parentBridge + userInfo:userInfo]; +} RCT_NOT_IMPLEMENTED(- (instancetype)initWithBundleURL:(__unused NSURL *)bundleURL moduleProvider:(__unused RCTBridgeModuleProviderBlock)block diff --git a/React/Base/RCTRootView.m b/React/Base/RCTRootView.m index 930aaa13c..15ed227af 100644 --- a/React/Base/RCTRootView.m +++ b/React/Base/RCTRootView.m @@ -13,7 +13,6 @@ #import "RCTAssert.h" #import "RCTBridge.h" -#import "RCTContextExecutor.h" #import "RCTEventDispatcher.h" #import "RCTKeyCommands.h" #import "RCTLog.h" @@ -246,6 +245,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder) return self; } +RCT_NOT_IMPLEMENTED(-(instancetype)initWithFrame:(CGRect)frame) RCT_NOT_IMPLEMENTED(-(instancetype)initWithCoder:(nonnull NSCoder *)aDecoder) - (void)insertReactSubview:(id)subview atIndex:(NSInteger)atIndex diff --git a/React/Executors/RCTContextExecutor.m b/React/Executors/RCTContextExecutor.m index 2dcf3d7b0..85854bf64 100644 --- a/React/Executors/RCTContextExecutor.m +++ b/React/Executors/RCTContextExecutor.m @@ -23,7 +23,7 @@ #import "RCTUtils.h" #ifndef RCT_JSC_PROFILER -#if RCT_DEV && RCT_DEBUG +#if RCT_DEV #define RCT_JSC_PROFILER 1 #else #define RCT_JSC_PROFILER 0 @@ -34,7 +34,7 @@ #include #ifndef RCT_JSC_PROFILER_DYLIB -#define RCT_JSC_PROFILER_DYLIB [[[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:@"RCTJSCProfiler.ios%zd", [[[UIDevice currentDevice] systemVersion] integerValue]] ofType:@"dylib" inDirectory:@"Frameworks"] UTF8String] +#define RCT_JSC_PROFILER_DYLIB [[[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:@"RCTJSCProfiler.ios%zd", [[[UIDevice currentDevice] systemVersion] integerValue]] ofType:@"dylib" inDirectory:@"RCTJSCProfiler"] UTF8String] #endif #endif diff --git a/React/Modules/RCTDevLoadingView.h b/React/Modules/RCTDevLoadingView.h index 85a43a369..b09315fb6 100644 --- a/React/Modules/RCTDevLoadingView.h +++ b/React/Modules/RCTDevLoadingView.h @@ -11,4 +11,6 @@ @interface RCTDevLoadingView : NSObject ++ (void)setEnabled:(BOOL)enabled; + @end diff --git a/React/Modules/RCTDevLoadingView.m b/React/Modules/RCTDevLoadingView.m index b716b2483..a0266b7ce 100644 --- a/React/Modules/RCTDevLoadingView.m +++ b/React/Modules/RCTDevLoadingView.m @@ -16,6 +16,8 @@ #if RCT_DEV +static BOOL isEnabled = YES; + @implementation RCTDevLoadingView { UIWindow *_window; @@ -27,6 +29,11 @@ RCT_EXPORT_MODULE() ++ (void)setEnabled:(BOOL)enabled +{ + isEnabled = enabled; +} + - (instancetype)init { if ((self = [super init])) { @@ -57,6 +64,10 @@ RCT_EXPORT_MODULE() - (void)showWithURL:(NSURL *)URL { + if (!isEnabled) { + return; + } + dispatch_async(dispatch_get_main_queue(), ^{ _showDate = [NSDate date]; @@ -90,6 +101,10 @@ RCT_EXPORT_MODULE() - (void)hide { + if (!isEnabled) { + return; + } + dispatch_async(dispatch_get_main_queue(), ^{ const NSTimeInterval MIN_PRESENTED_TIME = 0.6; @@ -117,6 +132,7 @@ RCT_EXPORT_MODULE() @implementation RCTDevLoadingView + (NSString *)moduleName { return nil; } ++ (void)setEnabled:(BOOL)enabled { } @end diff --git a/React/Modules/RCTUIManager.m b/React/Modules/RCTUIManager.m index 9acaff806..f6e35dad4 100644 --- a/React/Modules/RCTUIManager.m +++ b/React/Modules/RCTUIManager.m @@ -488,6 +488,11 @@ extern NSString *RCTBridgeModuleNameForClass(Class cls); // Perform layout (possibly animated) return ^(__unused RCTUIManager *uiManager, RCTSparseArray *viewRegistry) { RCTResponseSenderBlock callback = self->_layoutAnimation.callback; + + // It's unsafe to call this callback more than once, so we nil it out here + // to make sure that doesn't happen. + _layoutAnimation.callback = nil; + __block NSUInteger completionsCalled = 0; for (NSUInteger ii = 0; ii < frames.count; ii++) { NSNumber *reactTag = frameReactTags[ii]; diff --git a/React/React.xcodeproj/project.pbxproj b/React/React.xcodeproj/project.pbxproj index ce803446d..276e3943d 100644 --- a/React/React.xcodeproj/project.pbxproj +++ b/React/React.xcodeproj/project.pbxproj @@ -589,7 +589,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "if [[ \"$CONFIGURATION\" == \"Debug\" ]] && [[ -d \"/tmp/RCTJSCProfiler\" ]]; then\n find \"${CONFIGURATION_BUILD_DIR}\" -name '*.app' | xargs -I{} sh -c 'mkdir -p \"$1/Frameworks\" && cp -r /tmp/RCTJSCProfiler/* \"$1/Frameworks\"' -- {}\nfi"; + shellScript = "if [[ \"$CONFIGURATION\" == \"Debug\" ]] && [[ -d \"/tmp/RCTJSCProfiler\" ]]; then\n find \"${CONFIGURATION_BUILD_DIR}\" -name '*.app' | xargs -I{} sh -c 'cp -r /tmp/RCTJSCProfiler \"$1\"' -- {}\nfi"; showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ diff --git a/React/Views/RCTAutoInsetsProtocol.h b/React/Views/RCTAutoInsetsProtocol.h index 8a14fc0bd..8e7c72c80 100644 --- a/React/Views/RCTAutoInsetsProtocol.h +++ b/React/Views/RCTAutoInsetsProtocol.h @@ -17,4 +17,13 @@ @property (nonatomic, assign, readwrite) UIEdgeInsets contentInset; @property (nonatomic, assign, readwrite) BOOL automaticallyAdjustContentInsets; +/** + * Automatically adjusted content inset depends on view controller's top and bottom + * layout guides so if you've changed one of them (e.g. after rotation or manually) you should call this method + * to recalculate and refresh content inset. + * To handle case with changing navigation bar height call this method from viewDidLayoutSubviews: + * of your view controller. + */ +- (void)refreshContentInset; + @end diff --git a/React/Views/RCTPickerManager.m b/React/Views/RCTPickerManager.m index 8d1e18120..d43c58ad9 100644 --- a/React/Views/RCTPickerManager.m +++ b/React/Views/RCTPickerManager.m @@ -24,6 +24,7 @@ RCT_EXPORT_MODULE() RCT_EXPORT_VIEW_PROPERTY(items, NSDictionaryArray) RCT_EXPORT_VIEW_PROPERTY(selectedIndex, NSInteger) +RCT_EXPORT_VIEW_PROPERTY(onChange, RCTBubblingEventBlock) - (NSDictionary *)constantsToExport { diff --git a/React/Views/RCTScrollView.m b/React/Views/RCTScrollView.m index 8c649da56..b502203f0 100644 --- a/React/Views/RCTScrollView.m +++ b/React/Views/RCTScrollView.m @@ -460,10 +460,6 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder) _scrollView.frame = self.bounds; _scrollView.contentOffset = originalOffset; - [RCTView autoAdjustInsetsForView:self - withScrollView:_scrollView - updateOffset:YES]; - [self updateClippedSubviews]; } @@ -523,6 +519,13 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder) [_scrollView zoomToRect:rect animated:animated]; } +- (void)refreshContentInset +{ + [RCTView autoAdjustInsetsForView:self + withScrollView:_scrollView + updateOffset:YES]; +} + #pragma mark - ScrollView delegate #define RCT_SCROLL_EVENT_HANDLER(delegateMethod, eventName) \ diff --git a/React/Views/RCTWebView.m b/React/Views/RCTWebView.m index 4838179a5..46d47c895 100644 --- a/React/Views/RCTWebView.m +++ b/React/Views/RCTWebView.m @@ -95,9 +95,6 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder) { [super layoutSubviews]; _webView.frame = self.bounds; - [RCTView autoAdjustInsetsForView:self - withScrollView:_webView.scrollView - updateOffset:YES]; } - (void)setContentInset:(UIEdgeInsets)contentInset @@ -133,6 +130,13 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder) return event; } +- (void)refreshContentInset +{ + [RCTView autoAdjustInsetsForView:self + withScrollView:_webView.scrollView + updateOffset:YES]; +} + #pragma mark - UIWebViewDelegate methods - (BOOL)webView:(__unused UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request diff --git a/React/Views/RCTWrapperViewController.m b/React/Views/RCTWrapperViewController.m index 92707e683..7959326d5 100644 --- a/React/Views/RCTWrapperViewController.m +++ b/React/Views/RCTWrapperViewController.m @@ -16,13 +16,15 @@ #import "RCTUtils.h" #import "RCTViewControllerProtocol.h" #import "UIView+React.h" +#import "RCTAutoInsetsProtocol.h" @implementation RCTWrapperViewController { UIView *_wrapperView; UIView *_contentView; - CGFloat _previousTopLayout; - CGFloat _previousBottomLayout; + RCTEventDispatcher *_eventDispatcher; + CGFloat _previousTopLayoutLength; + CGFloat _previousBottomLayoutLength; } @synthesize currentTopLayoutGuide = _currentTopLayoutGuide; @@ -58,6 +60,32 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder) _currentBottomLayoutGuide = self.bottomLayoutGuide; } +static BOOL RCTFindScrollViewAndRefreshContentInsetInView(UIView *view) +{ + if ([view conformsToProtocol:@protocol(RCTAutoInsetsProtocol)]) { + [(id ) view refreshContentInset]; + return YES; + } + for (UIView *subview in view.subviews) { + if (RCTFindScrollViewAndRefreshContentInsetInView(subview)) { + return YES; + } + } + return NO; +} + +- (void)viewDidLayoutSubviews +{ + [super viewDidLayoutSubviews]; + + if (_previousTopLayoutLength != _currentTopLayoutGuide.length || + _previousBottomLayoutLength != _currentBottomLayoutGuide.length) { + RCTFindScrollViewAndRefreshContentInsetInView(_contentView); + _previousTopLayoutLength = _currentTopLayoutGuide.length; + _previousBottomLayoutLength = _currentBottomLayoutGuide.length; + } +} + static UIView *RCTFindNavBarShadowViewInView(UIView *view) { if ([view isKindOfClass:[UIImageView class]] && view.bounds.size.height <= 1) { diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 9e5c55c36..aa8bd79a8 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -8,9 +8,9 @@ "resolved": "https://registry.npmjs.org/absolute-path/-/absolute-path-0.0.0.tgz" }, "babel": { - "version": "5.8.21", - "from": "babel@5.8.21", - "resolved": "https://registry.npmjs.org/babel/-/babel-5.8.21.tgz", + "version": "5.8.23", + "from": "babel@5.8.23", + "resolved": "https://registry.npmjs.org/babel/-/babel-5.8.23.tgz", "dependencies": { "chokidar": { "version": "1.0.5", @@ -354,7 +354,7 @@ }, "inherits": { "version": "2.0.1", - "from": "inherits@>=2.0.1 <2.1.0", + "from": "inherits@>=2.0.0 <3.0.0", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz" }, "minimatch": { @@ -434,18 +434,6 @@ "from": "path-is-absolute@>=1.0.0 <2.0.0", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.0.tgz" }, - "source-map": { - "version": "0.4.4", - "from": "source-map@>=0.4.0 <0.5.0", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", - "dependencies": { - "amdefine": { - "version": "1.0.0", - "from": "amdefine@>=0.0.4", - "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.0.tgz" - } - } - }, "slash": { "version": "1.0.0", "from": "slash@>=1.0.0 <2.0.0", @@ -454,9 +442,9 @@ } }, "babel-core": { - "version": "5.8.21", - "from": "babel-core@5.8.21", - "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-5.8.21.tgz", + "version": "5.8.23", + "from": "babel-core@5.8.23", + "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-5.8.23.tgz", "dependencies": { "babel-plugin-constant-folding": { "version": "1.0.1", @@ -542,7 +530,7 @@ }, "babylon": { "version": "5.8.23", - "from": "babylon@>=5.8.21 <6.0.0", + "from": "babylon@>=5.8.23 <6.0.0", "resolved": "https://registry.npmjs.org/babylon/-/babylon-5.8.23.tgz" }, "bluebird": { @@ -560,18 +548,6 @@ "from": "core-js@>=1.0.0 <2.0.0", "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.1.3.tgz" }, - "debug": { - "version": "2.2.0", - "from": "debug@>=2.1.1 <3.0.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", - "dependencies": { - "ms": { - "version": "0.7.1", - "from": "ms@0.7.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz" - } - } - }, "detect-indent": { "version": "3.0.1", "from": "detect-indent@>=3.0.0 <4.0.0", @@ -888,6 +864,11 @@ "version": "0.1.2", "from": "tryor@>=0.1.2 <0.2.0", "resolved": "https://registry.npmjs.org/tryor/-/tryor-0.1.2.tgz" + }, + "yargs": { + "version": "1.3.3", + "from": "yargs@>=1.3.2 <1.4.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-1.3.3.tgz" } } }, @@ -995,18 +976,6 @@ "from": "slash@>=1.0.0 <2.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz" }, - "source-map": { - "version": "0.4.4", - "from": "source-map@>=0.4.0 <0.5.0", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", - "dependencies": { - "amdefine": { - "version": "1.0.0", - "from": "amdefine@>=0.0.4", - "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.0.tgz" - } - } - }, "source-map-support": { "version": "0.2.10", "from": "source-map-support@>=0.2.10 <0.3.0", @@ -1043,10 +1012,153 @@ } } }, + "babel-eslint": { + "version": "4.1.1", + "from": "babel-eslint@4.1.1", + "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-4.1.1.tgz", + "dependencies": { + "lodash.assign": { + "version": "3.2.0", + "from": "lodash.assign@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-3.2.0.tgz", + "dependencies": { + "lodash._baseassign": { + "version": "3.2.0", + "from": "lodash._baseassign@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz", + "dependencies": { + "lodash._basecopy": { + "version": "3.0.1", + "from": "lodash._basecopy@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz" + } + } + }, + "lodash._createassigner": { + "version": "3.1.1", + "from": "lodash._createassigner@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz", + "dependencies": { + "lodash._bindcallback": { + "version": "3.0.1", + "from": "lodash._bindcallback@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz" + }, + "lodash._isiterateecall": { + "version": "3.0.9", + "from": "lodash._isiterateecall@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz" + }, + "lodash.restparam": { + "version": "3.6.1", + "from": "lodash.restparam@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz" + } + } + }, + "lodash.keys": { + "version": "3.1.2", + "from": "lodash.keys@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", + "dependencies": { + "lodash._getnative": { + "version": "3.9.1", + "from": "lodash._getnative@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz" + }, + "lodash.isarguments": { + "version": "3.0.4", + "from": "lodash.isarguments@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.0.4.tgz" + }, + "lodash.isarray": { + "version": "3.0.4", + "from": "lodash.isarray@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz" + } + } + } + } + }, + "lodash.pick": { + "version": "3.1.0", + "from": "lodash.pick@>=3.1.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.pick/-/lodash.pick-3.1.0.tgz", + "dependencies": { + "lodash._baseflatten": { + "version": "3.1.4", + "from": "lodash._baseflatten@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._baseflatten/-/lodash._baseflatten-3.1.4.tgz", + "dependencies": { + "lodash.isarguments": { + "version": "3.0.4", + "from": "lodash.isarguments@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.0.4.tgz" + }, + "lodash.isarray": { + "version": "3.0.4", + "from": "lodash.isarray@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz" + } + } + }, + "lodash._bindcallback": { + "version": "3.0.1", + "from": "lodash._bindcallback@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz" + }, + "lodash._pickbyarray": { + "version": "3.0.2", + "from": "lodash._pickbyarray@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._pickbyarray/-/lodash._pickbyarray-3.0.2.tgz" + }, + "lodash._pickbycallback": { + "version": "3.0.0", + "from": "lodash._pickbycallback@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._pickbycallback/-/lodash._pickbycallback-3.0.0.tgz", + "dependencies": { + "lodash._basefor": { + "version": "3.0.2", + "from": "lodash._basefor@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._basefor/-/lodash._basefor-3.0.2.tgz" + }, + "lodash.keysin": { + "version": "3.0.8", + "from": "lodash.keysin@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.keysin/-/lodash.keysin-3.0.8.tgz", + "dependencies": { + "lodash.isarguments": { + "version": "3.0.4", + "from": "lodash.isarguments@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.0.4.tgz" + }, + "lodash.isarray": { + "version": "3.0.4", + "from": "lodash.isarray@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz" + } + } + } + } + }, + "lodash.restparam": { + "version": "3.6.1", + "from": "lodash.restparam@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz" + } + } + }, + "acorn-to-esprima": { + "version": "1.0.2", + "from": "acorn-to-esprima@>=1.0.2 <2.0.0", + "resolved": "https://registry.npmjs.org/acorn-to-esprima/-/acorn-to-esprima-1.0.2.tgz" + } + } + }, "bser": { - "version": "1.0.0", - "from": "bser@1.0.0", - "resolved": "https://registry.npmjs.org/bser/-/bser-1.0.0.tgz", + "version": "1.0.2", + "from": "bser@1.0.2", + "resolved": "https://registry.npmjs.org/bser/-/bser-1.0.2.tgz", "dependencies": { "node-int64": { "version": "0.4.0", @@ -1056,13 +1168,13 @@ } }, "chalk": { - "version": "1.0.0", - "from": "chalk@1.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.0.0.tgz", + "version": "1.1.1", + "from": "chalk@1.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.1.tgz", "dependencies": { "ansi-styles": { "version": "2.1.0", - "from": "ansi-styles@>=2.0.1 <3.0.0", + "from": "ansi-styles@>=2.1.0 <3.0.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.1.0.tgz" }, "escape-string-regexp": { @@ -1071,38 +1183,33 @@ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.3.tgz" }, "has-ansi": { - "version": "1.0.3", - "from": "has-ansi@>=1.0.3 <2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-1.0.3.tgz", + "version": "2.0.0", + "from": "has-ansi@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", "dependencies": { "ansi-regex": { - "version": "1.1.1", - "from": "ansi-regex@>=1.1.0 <2.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-1.1.1.tgz" - }, - "get-stdin": { - "version": "4.0.1", - "from": "get-stdin@>=4.0.1 <5.0.0", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz" + "version": "2.0.0", + "from": "ansi-regex@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz" } } }, "strip-ansi": { - "version": "2.0.1", - "from": "strip-ansi@>=2.0.1 <3.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-2.0.1.tgz", + "version": "3.0.0", + "from": "strip-ansi@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.0.tgz", "dependencies": { "ansi-regex": { - "version": "1.1.1", - "from": "ansi-regex@>=1.1.0 <2.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-1.1.1.tgz" + "version": "2.0.0", + "from": "ansi-regex@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz" } } }, "supports-color": { - "version": "1.3.1", - "from": "supports-color@>=1.3.0 <2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-1.3.1.tgz" + "version": "2.0.0", + "from": "supports-color@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz" } } }, @@ -1181,17 +1288,789 @@ } }, "debug": { - "version": "2.1.0", - "from": "debug@2.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.1.0.tgz", + "version": "2.2.0", + "from": "debug@2.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", "dependencies": { "ms": { - "version": "0.6.2", - "from": "ms@0.6.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-0.6.2.tgz" + "version": "0.7.1", + "from": "ms@0.7.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz" } } }, + "eslint": { + "version": "1.3.1", + "from": "eslint@1.3.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-1.3.1.tgz", + "dependencies": { + "concat-stream": { + "version": "1.5.0", + "from": "concat-stream@>=1.4.6 <2.0.0", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.5.0.tgz", + "dependencies": { + "inherits": { + "version": "2.0.1", + "from": "inherits@>=2.0.1 <2.1.0", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz" + }, + "typedarray": { + "version": "0.0.6", + "from": "typedarray@>=0.0.5 <0.1.0", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz" + }, + "readable-stream": { + "version": "2.0.2", + "from": "readable-stream@>=2.0.0 <2.1.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.2.tgz", + "dependencies": { + "core-util-is": { + "version": "1.0.1", + "from": "core-util-is@>=1.0.0 <1.1.0", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz" + }, + "isarray": { + "version": "0.0.1", + "from": "isarray@0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz" + }, + "process-nextick-args": { + "version": "1.0.2", + "from": "process-nextick-args@>=1.0.0 <1.1.0", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.2.tgz" + }, + "string_decoder": { + "version": "0.10.31", + "from": "string_decoder@>=0.10.0 <0.11.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz" + }, + "util-deprecate": { + "version": "1.0.1", + "from": "util-deprecate@>=1.0.1 <1.1.0", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.1.tgz" + } + } + } + } + }, + "doctrine": { + "version": "0.6.4", + "from": "doctrine@>=0.6.2 <0.7.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-0.6.4.tgz", + "dependencies": { + "esutils": { + "version": "1.1.6", + "from": "esutils@>=1.1.6 <2.0.0", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-1.1.6.tgz" + }, + "isarray": { + "version": "0.0.1", + "from": "isarray@0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz" + } + } + }, + "escape-string-regexp": { + "version": "1.0.3", + "from": "escape-string-regexp@>=1.0.2 <2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.3.tgz" + }, + "escope": { + "version": "3.2.0", + "from": "escope@>=3.2.0 <4.0.0", + "resolved": "https://registry.npmjs.org/escope/-/escope-3.2.0.tgz", + "dependencies": { + "es6-map": { + "version": "0.1.1", + "from": "es6-map@>=0.1.1 <0.2.0", + "resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.1.tgz", + "dependencies": { + "d": { + "version": "0.1.1", + "from": "d@>=0.1.1 <0.2.0", + "resolved": "https://registry.npmjs.org/d/-/d-0.1.1.tgz" + }, + "es5-ext": { + "version": "0.10.7", + "from": "es5-ext@>=0.10.4 <0.11.0", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.7.tgz", + "dependencies": { + "es6-symbol": { + "version": "2.0.1", + "from": "es6-symbol@>=2.0.1 <2.1.0", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-2.0.1.tgz" + } + } + }, + "es6-iterator": { + "version": "0.1.3", + "from": "es6-iterator@>=0.1.1 <0.2.0", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-0.1.3.tgz", + "dependencies": { + "es6-symbol": { + "version": "2.0.1", + "from": "es6-symbol@>=2.0.1 <2.1.0", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-2.0.1.tgz" + } + } + }, + "es6-set": { + "version": "0.1.1", + "from": "es6-set@>=0.1.1 <0.2.0", + "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.1.tgz" + }, + "es6-symbol": { + "version": "0.1.1", + "from": "es6-symbol@>=0.1.1 <0.2.0", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-0.1.1.tgz" + }, + "event-emitter": { + "version": "0.3.3", + "from": "event-emitter@>=0.3.1 <0.4.0", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.3.tgz" + } + } + }, + "es6-weak-map": { + "version": "0.1.4", + "from": "es6-weak-map@>=0.1.2 <0.2.0", + "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-0.1.4.tgz", + "dependencies": { + "d": { + "version": "0.1.1", + "from": "d@>=0.1.1 <0.2.0", + "resolved": "https://registry.npmjs.org/d/-/d-0.1.1.tgz" + }, + "es5-ext": { + "version": "0.10.7", + "from": "es5-ext@>=0.10.6 <0.11.0", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.7.tgz" + }, + "es6-iterator": { + "version": "0.1.3", + "from": "es6-iterator@>=0.1.3 <0.2.0", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-0.1.3.tgz" + }, + "es6-symbol": { + "version": "2.0.1", + "from": "es6-symbol@>=2.0.1 <2.1.0", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-2.0.1.tgz" + } + } + }, + "esrecurse": { + "version": "3.1.1", + "from": "esrecurse@>=3.1.1 <4.0.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-3.1.1.tgz" + }, + "estraverse": { + "version": "3.1.0", + "from": "estraverse@>=3.1.0 <4.0.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-3.1.0.tgz" + } + } + }, + "espree": { + "version": "2.2.4", + "from": "espree@>=2.2.4 <3.0.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-2.2.4.tgz" + }, + "estraverse": { + "version": "4.1.0", + "from": "estraverse@>=4.1.0 <5.0.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.1.0.tgz" + }, + "estraverse-fb": { + "version": "1.3.1", + "from": "estraverse-fb@>=1.3.1 <2.0.0", + "resolved": "https://registry.npmjs.org/estraverse-fb/-/estraverse-fb-1.3.1.tgz" + }, + "globals": { + "version": "8.7.0", + "from": "globals@>=8.5.0 <9.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-8.7.0.tgz" + }, + "handlebars": { + "version": "3.0.3", + "from": "handlebars@>=3.0.3 <4.0.0", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-3.0.3.tgz", + "dependencies": { + "source-map": { + "version": "0.1.43", + "from": "source-map@>=0.1.40 <0.2.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", + "dependencies": { + "amdefine": { + "version": "1.0.0", + "from": "amdefine@>=0.0.4", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.0.tgz" + } + } + }, + "uglify-js": { + "version": "2.3.6", + "from": "uglify-js@>=2.3.0 <2.4.0", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.3.6.tgz", + "dependencies": { + "async": { + "version": "0.2.10", + "from": "async@>=0.2.6 <0.3.0", + "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz" + }, + "optimist": { + "version": "0.3.7", + "from": "optimist@>=0.3.5 <0.4.0", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.3.7.tgz", + "dependencies": { + "wordwrap": { + "version": "0.0.3", + "from": "wordwrap@>=0.0.2 <0.1.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz" + } + } + } + } + } + } + }, + "inquirer": { + "version": "0.9.0", + "from": "inquirer@>=0.9.0 <0.10.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-0.9.0.tgz", + "dependencies": { + "ansi-regex": { + "version": "2.0.0", + "from": "ansi-regex@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz" + }, + "cli-width": { + "version": "1.0.1", + "from": "cli-width@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-1.0.1.tgz" + }, + "figures": { + "version": "1.3.5", + "from": "figures@>=1.3.5 <2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-1.3.5.tgz" + }, + "lodash": { + "version": "3.10.1", + "from": "lodash@>=3.3.1 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz" + }, + "readline2": { + "version": "0.1.1", + "from": "readline2@>=0.1.1 <0.2.0", + "resolved": "https://registry.npmjs.org/readline2/-/readline2-0.1.1.tgz", + "dependencies": { + "mute-stream": { + "version": "0.0.4", + "from": "mute-stream@0.0.4", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.4.tgz" + }, + "strip-ansi": { + "version": "2.0.1", + "from": "strip-ansi@>=2.0.1 <3.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-2.0.1.tgz", + "dependencies": { + "ansi-regex": { + "version": "1.1.1", + "from": "ansi-regex@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-1.1.1.tgz" + } + } + } + } + }, + "run-async": { + "version": "0.1.0", + "from": "run-async@>=0.1.0 <0.2.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-0.1.0.tgz", + "dependencies": { + "once": { + "version": "1.3.2", + "from": "once@>=1.3.0 <2.0.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.3.2.tgz", + "dependencies": { + "wrappy": { + "version": "1.0.1", + "from": "wrappy@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz" + } + } + } + } + }, + "rx-lite": { + "version": "2.5.2", + "from": "rx-lite@>=2.5.2 <3.0.0", + "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-2.5.2.tgz" + }, + "strip-ansi": { + "version": "3.0.0", + "from": "strip-ansi@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.0.tgz" + }, + "through": { + "version": "2.3.8", + "from": "through@>=2.3.6 <3.0.0", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz" + } + } + }, + "is-my-json-valid": { + "version": "2.12.2", + "from": "is-my-json-valid@>=2.10.0 <3.0.0", + "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.12.2.tgz", + "dependencies": { + "generate-function": { + "version": "2.0.0", + "from": "generate-function@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz" + }, + "generate-object-property": { + "version": "1.2.0", + "from": "generate-object-property@>=1.1.0 <2.0.0", + "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", + "dependencies": { + "is-property": { + "version": "1.0.2", + "from": "is-property@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz" + } + } + }, + "jsonpointer": { + "version": "2.0.0", + "from": "jsonpointer@2.0.0", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-2.0.0.tgz" + }, + "xtend": { + "version": "4.0.0", + "from": "xtend@>=4.0.0 <5.0.0", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.0.tgz" + } + } + }, + "is-resolvable": { + "version": "1.0.0", + "from": "is-resolvable@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.0.0.tgz", + "dependencies": { + "tryit": { + "version": "1.0.1", + "from": "tryit@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/tryit/-/tryit-1.0.1.tgz" + } + } + }, + "js-yaml": { + "version": "3.4.0", + "from": "js-yaml@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.4.0.tgz", + "dependencies": { + "argparse": { + "version": "1.0.2", + "from": "argparse@>=1.0.2 <1.1.0", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.2.tgz", + "dependencies": { + "lodash": { + "version": "3.10.1", + "from": "lodash@>=3.2.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz" + }, + "sprintf-js": { + "version": "1.0.3", + "from": "sprintf-js@>=1.0.2 <1.1.0", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz" + } + } + }, + "esprima": { + "version": "2.2.0", + "from": "esprima@>=2.2.0 <2.3.0", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.2.0.tgz" + } + } + }, + "lodash.clonedeep": { + "version": "3.0.2", + "from": "lodash.clonedeep@>=3.0.1 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-3.0.2.tgz", + "dependencies": { + "lodash._baseclone": { + "version": "3.3.0", + "from": "lodash._baseclone@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._baseclone/-/lodash._baseclone-3.3.0.tgz", + "dependencies": { + "lodash._arraycopy": { + "version": "3.0.0", + "from": "lodash._arraycopy@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._arraycopy/-/lodash._arraycopy-3.0.0.tgz" + }, + "lodash._arrayeach": { + "version": "3.0.0", + "from": "lodash._arrayeach@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._arrayeach/-/lodash._arrayeach-3.0.0.tgz" + }, + "lodash._baseassign": { + "version": "3.2.0", + "from": "lodash._baseassign@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz", + "dependencies": { + "lodash._basecopy": { + "version": "3.0.1", + "from": "lodash._basecopy@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz" + } + } + }, + "lodash._basefor": { + "version": "3.0.2", + "from": "lodash._basefor@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._basefor/-/lodash._basefor-3.0.2.tgz" + }, + "lodash.isarray": { + "version": "3.0.4", + "from": "lodash.isarray@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz" + }, + "lodash.keys": { + "version": "3.1.2", + "from": "lodash.keys@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", + "dependencies": { + "lodash._getnative": { + "version": "3.9.1", + "from": "lodash._getnative@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz" + }, + "lodash.isarguments": { + "version": "3.0.4", + "from": "lodash.isarguments@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.0.4.tgz" + } + } + } + } + }, + "lodash._bindcallback": { + "version": "3.0.1", + "from": "lodash._bindcallback@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz" + } + } + }, + "lodash.merge": { + "version": "3.3.2", + "from": "lodash.merge@>=3.3.2 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-3.3.2.tgz", + "dependencies": { + "lodash._arraycopy": { + "version": "3.0.0", + "from": "lodash._arraycopy@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._arraycopy/-/lodash._arraycopy-3.0.0.tgz" + }, + "lodash._arrayeach": { + "version": "3.0.0", + "from": "lodash._arrayeach@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._arrayeach/-/lodash._arrayeach-3.0.0.tgz" + }, + "lodash._createassigner": { + "version": "3.1.1", + "from": "lodash._createassigner@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz", + "dependencies": { + "lodash._bindcallback": { + "version": "3.0.1", + "from": "lodash._bindcallback@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz" + }, + "lodash._isiterateecall": { + "version": "3.0.9", + "from": "lodash._isiterateecall@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz" + }, + "lodash.restparam": { + "version": "3.6.1", + "from": "lodash.restparam@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz" + } + } + }, + "lodash._getnative": { + "version": "3.9.1", + "from": "lodash._getnative@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz" + }, + "lodash.isarguments": { + "version": "3.0.4", + "from": "lodash.isarguments@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.0.4.tgz" + }, + "lodash.isarray": { + "version": "3.0.4", + "from": "lodash.isarray@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz" + }, + "lodash.isplainobject": { + "version": "3.2.0", + "from": "lodash.isplainobject@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-3.2.0.tgz", + "dependencies": { + "lodash._basefor": { + "version": "3.0.2", + "from": "lodash._basefor@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._basefor/-/lodash._basefor-3.0.2.tgz" + } + } + }, + "lodash.istypedarray": { + "version": "3.0.2", + "from": "lodash.istypedarray@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.istypedarray/-/lodash.istypedarray-3.0.2.tgz" + }, + "lodash.keys": { + "version": "3.1.2", + "from": "lodash.keys@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz" + }, + "lodash.keysin": { + "version": "3.0.8", + "from": "lodash.keysin@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.keysin/-/lodash.keysin-3.0.8.tgz" + }, + "lodash.toplainobject": { + "version": "3.0.0", + "from": "lodash.toplainobject@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.toplainobject/-/lodash.toplainobject-3.0.0.tgz", + "dependencies": { + "lodash._basecopy": { + "version": "3.0.1", + "from": "lodash._basecopy@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz" + } + } + } + } + }, + "lodash.omit": { + "version": "3.1.0", + "from": "lodash.omit@>=3.1.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.omit/-/lodash.omit-3.1.0.tgz", + "dependencies": { + "lodash._arraymap": { + "version": "3.0.0", + "from": "lodash._arraymap@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._arraymap/-/lodash._arraymap-3.0.0.tgz" + }, + "lodash._basedifference": { + "version": "3.0.3", + "from": "lodash._basedifference@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._basedifference/-/lodash._basedifference-3.0.3.tgz", + "dependencies": { + "lodash._baseindexof": { + "version": "3.1.0", + "from": "lodash._baseindexof@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._baseindexof/-/lodash._baseindexof-3.1.0.tgz" + }, + "lodash._cacheindexof": { + "version": "3.0.2", + "from": "lodash._cacheindexof@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._cacheindexof/-/lodash._cacheindexof-3.0.2.tgz" + }, + "lodash._createcache": { + "version": "3.1.2", + "from": "lodash._createcache@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._createcache/-/lodash._createcache-3.1.2.tgz", + "dependencies": { + "lodash._getnative": { + "version": "3.9.1", + "from": "lodash._getnative@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz" + } + } + } + } + }, + "lodash._baseflatten": { + "version": "3.1.4", + "from": "lodash._baseflatten@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._baseflatten/-/lodash._baseflatten-3.1.4.tgz", + "dependencies": { + "lodash.isarguments": { + "version": "3.0.4", + "from": "lodash.isarguments@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.0.4.tgz" + }, + "lodash.isarray": { + "version": "3.0.4", + "from": "lodash.isarray@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz" + } + } + }, + "lodash._bindcallback": { + "version": "3.0.1", + "from": "lodash._bindcallback@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz" + }, + "lodash._pickbyarray": { + "version": "3.0.2", + "from": "lodash._pickbyarray@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._pickbyarray/-/lodash._pickbyarray-3.0.2.tgz" + }, + "lodash._pickbycallback": { + "version": "3.0.0", + "from": "lodash._pickbycallback@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._pickbycallback/-/lodash._pickbycallback-3.0.0.tgz", + "dependencies": { + "lodash._basefor": { + "version": "3.0.2", + "from": "lodash._basefor@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._basefor/-/lodash._basefor-3.0.2.tgz" + } + } + }, + "lodash.keysin": { + "version": "3.0.8", + "from": "lodash.keysin@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.keysin/-/lodash.keysin-3.0.8.tgz", + "dependencies": { + "lodash.isarguments": { + "version": "3.0.4", + "from": "lodash.isarguments@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.0.4.tgz" + }, + "lodash.isarray": { + "version": "3.0.4", + "from": "lodash.isarray@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz" + } + } + }, + "lodash.restparam": { + "version": "3.6.1", + "from": "lodash.restparam@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz" + } + } + }, + "minimatch": { + "version": "2.0.10", + "from": "minimatch@>=2.0.1 <3.0.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz", + "dependencies": { + "brace-expansion": { + "version": "1.1.0", + "from": "brace-expansion@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.0.tgz", + "dependencies": { + "balanced-match": { + "version": "0.2.0", + "from": "balanced-match@>=0.2.0 <0.3.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.2.0.tgz" + }, + "concat-map": { + "version": "0.0.1", + "from": "concat-map@0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" + } + } + } + } + }, + "mkdirp": { + "version": "0.5.1", + "from": "mkdirp@>=0.5.0 <0.6.0", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "dependencies": { + "minimist": { + "version": "0.0.8", + "from": "minimist@0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz" + } + } + }, + "object-assign": { + "version": "2.1.1", + "from": "object-assign@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz" + }, + "optionator": { + "version": "0.5.0", + "from": "optionator@>=0.5.0 <0.6.0", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.5.0.tgz", + "dependencies": { + "prelude-ls": { + "version": "1.1.2", + "from": "prelude-ls@>=1.1.1 <1.2.0", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz" + }, + "deep-is": { + "version": "0.1.3", + "from": "deep-is@>=0.1.2 <0.2.0", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz" + }, + "wordwrap": { + "version": "0.0.3", + "from": "wordwrap@>=0.0.2 <0.1.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz" + }, + "type-check": { + "version": "0.3.1", + "from": "type-check@>=0.3.1 <0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.1.tgz" + }, + "levn": { + "version": "0.2.5", + "from": "levn@>=0.2.5 <0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.2.5.tgz" + }, + "fast-levenshtein": { + "version": "1.0.7", + "from": "fast-levenshtein@>=1.0.0 <1.1.0", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.0.7.tgz" + } + } + }, + "path-is-absolute": { + "version": "1.0.0", + "from": "path-is-absolute@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.0.tgz" + }, + "path-is-inside": { + "version": "1.0.1", + "from": "path-is-inside@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.1.tgz" + }, + "strip-json-comments": { + "version": "1.0.4", + "from": "strip-json-comments@>=1.0.1 <1.1.0", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz" + }, + "text-table": { + "version": "0.2.0", + "from": "text-table@>=0.2.0 <0.3.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz" + }, + "user-home": { + "version": "1.1.1", + "from": "user-home@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/user-home/-/user-home-1.1.1.tgz" + }, + "xml-escape": { + "version": "1.0.0", + "from": "xml-escape@>=1.0.0 <1.1.0", + "resolved": "https://registry.npmjs.org/xml-escape/-/xml-escape-1.0.0.tgz" + } + } + }, + "eslint-plugin-react": { + "version": "3.3.1", + "from": "eslint-plugin-react@3.3.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-3.3.1.tgz" + }, "graceful-fs": { "version": "4.1.2", "from": "graceful-fs@4.1.2", @@ -1207,10 +2086,910 @@ "from": "immutable@>=3.7.4 <4.0.0", "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.7.5.tgz" }, + "jest-cli": { + "version": "0.5.1", + "from": "jest-cli@0.5.1", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-0.5.1.tgz", + "dependencies": { + "coffee-script": { + "version": "1.10.0", + "from": "jashkenas/coffeescript", + "resolved": "git://github.com/jashkenas/coffeescript.git#8711da03a27bac6ec056dc9535e0ac29065d8ea6" + }, + "cover": { + "version": "0.2.9", + "from": "cover@>=0.2.9 <0.3.0", + "resolved": "https://registry.npmjs.org/cover/-/cover-0.2.9.tgz", + "dependencies": { + "cli-table": { + "version": "0.0.2", + "from": "cli-table@>=0.0.0 <0.1.0", + "resolved": "https://registry.npmjs.org/cli-table/-/cli-table-0.0.2.tgz", + "dependencies": { + "colors": { + "version": "0.3.0", + "from": "colors@0.3.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-0.3.0.tgz" + } + } + }, + "underscore": { + "version": "1.2.4", + "from": "underscore@>=1.2.0 <1.3.0", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.2.4.tgz" + }, + "underscore.string": { + "version": "2.0.0", + "from": "underscore.string@>=2.0.0 <2.1.0", + "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.0.0.tgz" + }, + "which": { + "version": "1.0.9", + "from": "which@>=1.0.0 <1.1.0", + "resolved": "https://registry.npmjs.org/which/-/which-1.0.9.tgz" + } + } + }, + "diff": { + "version": "2.1.0", + "from": "diff@>=2.1.0 <3.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-2.1.0.tgz" + }, + "istanbul": { + "version": "0.3.19", + "from": "istanbul@>=0.3.15 <0.4.0", + "resolved": "https://registry.npmjs.org/istanbul/-/istanbul-0.3.19.tgz", + "dependencies": { + "esprima": { + "version": "2.5.0", + "from": "esprima@>=2.5.0 <2.6.0", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.5.0.tgz" + }, + "escodegen": { + "version": "1.6.1", + "from": "escodegen@>=1.6.0 <1.7.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.6.1.tgz", + "dependencies": { + "estraverse": { + "version": "1.9.3", + "from": "estraverse@>=1.9.1 <2.0.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz" + }, + "esutils": { + "version": "1.1.6", + "from": "esutils@>=1.1.6 <2.0.0", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-1.1.6.tgz" + }, + "esprima": { + "version": "1.2.5", + "from": "esprima@>=1.2.2 <2.0.0", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.2.5.tgz" + }, + "optionator": { + "version": "0.5.0", + "from": "optionator@>=0.5.0 <0.6.0", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.5.0.tgz", + "dependencies": { + "prelude-ls": { + "version": "1.1.2", + "from": "prelude-ls@>=1.1.1 <1.2.0", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz" + }, + "deep-is": { + "version": "0.1.3", + "from": "deep-is@>=0.1.2 <0.2.0", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz" + }, + "type-check": { + "version": "0.3.1", + "from": "type-check@>=0.3.1 <0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.1.tgz" + }, + "levn": { + "version": "0.2.5", + "from": "levn@>=0.2.5 <0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.2.5.tgz" + }, + "fast-levenshtein": { + "version": "1.0.7", + "from": "fast-levenshtein@>=1.0.0 <1.1.0", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.0.7.tgz" + } + } + }, + "source-map": { + "version": "0.1.43", + "from": "source-map@>=0.1.40 <0.2.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", + "dependencies": { + "amdefine": { + "version": "1.0.0", + "from": "amdefine@>=0.0.4", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.0.tgz" + } + } + } + } + }, + "handlebars": { + "version": "3.0.0", + "from": "handlebars@3.0.0", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-3.0.0.tgz", + "dependencies": { + "source-map": { + "version": "0.1.43", + "from": "source-map@>=0.1.40 <0.2.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", + "dependencies": { + "amdefine": { + "version": "1.0.0", + "from": "amdefine@>=0.0.4", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.0.tgz" + } + } + }, + "uglify-js": { + "version": "2.3.6", + "from": "uglify-js@>=2.3.0 <2.4.0", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.3.6.tgz", + "dependencies": { + "async": { + "version": "0.2.10", + "from": "async@>=0.2.6 <0.3.0", + "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz" + }, + "optimist": { + "version": "0.3.7", + "from": "optimist@>=0.3.5 <0.4.0", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.3.7.tgz" + } + } + } + } + }, + "mkdirp": { + "version": "0.5.1", + "from": "mkdirp@>=0.5.0 <0.6.0", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "dependencies": { + "minimist": { + "version": "0.0.8", + "from": "minimist@0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz" + } + } + }, + "nopt": { + "version": "3.0.3", + "from": "nopt@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.3.tgz" + }, + "fileset": { + "version": "0.2.1", + "from": "fileset@>=0.2.0 <0.3.0", + "resolved": "https://registry.npmjs.org/fileset/-/fileset-0.2.1.tgz", + "dependencies": { + "minimatch": { + "version": "2.0.10", + "from": "minimatch@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz", + "dependencies": { + "brace-expansion": { + "version": "1.1.0", + "from": "brace-expansion@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.0.tgz", + "dependencies": { + "balanced-match": { + "version": "0.2.0", + "from": "balanced-match@>=0.2.0 <0.3.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.2.0.tgz" + }, + "concat-map": { + "version": "0.0.1", + "from": "concat-map@0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" + } + } + } + } + }, + "glob": { + "version": "5.0.14", + "from": "glob@>=5.0.0 <6.0.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.14.tgz", + "dependencies": { + "inflight": { + "version": "1.0.4", + "from": "inflight@>=1.0.4 <2.0.0", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.4.tgz", + "dependencies": { + "wrappy": { + "version": "1.0.1", + "from": "wrappy@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz" + } + } + }, + "inherits": { + "version": "2.0.1", + "from": "inherits@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz" + }, + "path-is-absolute": { + "version": "1.0.0", + "from": "path-is-absolute@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.0.tgz" + } + } + } + } + }, + "which": { + "version": "1.0.9", + "from": "which@>=1.0.0 <1.1.0", + "resolved": "https://registry.npmjs.org/which/-/which-1.0.9.tgz" + }, + "async": { + "version": "1.4.2", + "from": "async@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/async/-/async-1.4.2.tgz" + }, + "supports-color": { + "version": "1.3.1", + "from": "supports-color@>=1.3.0 <1.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-1.3.1.tgz" + }, + "abbrev": { + "version": "1.0.7", + "from": "abbrev@>=1.0.0 <1.1.0", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.7.tgz" + }, + "wordwrap": { + "version": "0.0.3", + "from": "wordwrap@>=0.0.0 <0.1.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz" + }, + "js-yaml": { + "version": "3.4.0", + "from": "js-yaml@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.4.0.tgz", + "dependencies": { + "argparse": { + "version": "1.0.2", + "from": "argparse@>=1.0.2 <1.1.0", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.2.tgz", + "dependencies": { + "lodash": { + "version": "3.10.1", + "from": "lodash@>=3.2.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz" + }, + "sprintf-js": { + "version": "1.0.3", + "from": "sprintf-js@>=1.0.2 <1.1.0", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz" + } + } + }, + "esprima": { + "version": "2.2.0", + "from": "esprima@>=2.2.0 <2.3.0", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.2.0.tgz" + } + } + }, + "once": { + "version": "1.3.2", + "from": "once@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.3.2.tgz", + "dependencies": { + "wrappy": { + "version": "1.0.1", + "from": "wrappy@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz" + } + } + } + } + }, + "jasmine-only": { + "version": "0.1.1", + "from": "jasmine-only@>=0.1.1 <0.2.0", + "resolved": "https://registry.npmjs.org/jasmine-only/-/jasmine-only-0.1.1.tgz", + "dependencies": { + "coffee-script": { + "version": "1.6.3", + "from": "coffee-script@>=1.6.3 <1.7.0", + "resolved": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.6.3.tgz" + } + } + }, + "jasmine-pit": { + "version": "2.0.2", + "from": "jasmine-pit@>=2.0.2 <3.0.0", + "resolved": "https://registry.npmjs.org/jasmine-pit/-/jasmine-pit-2.0.2.tgz" + }, + "jsdom": { + "version": "6.3.0", + "from": "jsdom@6.3.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-6.3.0.tgz", + "dependencies": { + "acorn": { + "version": "1.2.2", + "from": "acorn@>=1.2.1 <2.0.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-1.2.2.tgz" + }, + "acorn-globals": { + "version": "1.0.5", + "from": "acorn-globals@>=1.0.4 <2.0.0", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-1.0.5.tgz", + "dependencies": { + "acorn": { + "version": "2.4.0", + "from": "acorn@>=2.1.0 <3.0.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-2.4.0.tgz" + } + } + }, + "browser-request": { + "version": "0.3.3", + "from": "browser-request@>=0.3.1 <0.4.0", + "resolved": "https://registry.npmjs.org/browser-request/-/browser-request-0.3.3.tgz" + }, + "cssom": { + "version": "0.3.0", + "from": "cssom@>=0.3.0 <0.4.0", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.0.tgz" + }, + "cssstyle": { + "version": "0.2.29", + "from": "cssstyle@>=0.2.29 <0.3.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-0.2.29.tgz" + }, + "escodegen": { + "version": "1.6.1", + "from": "escodegen@>=1.6.1 <2.0.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.6.1.tgz", + "dependencies": { + "estraverse": { + "version": "1.9.3", + "from": "estraverse@>=1.9.1 <2.0.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz" + }, + "esutils": { + "version": "1.1.6", + "from": "esutils@>=1.1.6 <2.0.0", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-1.1.6.tgz" + }, + "esprima": { + "version": "1.2.5", + "from": "esprima@>=1.2.2 <2.0.0", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.2.5.tgz" + }, + "optionator": { + "version": "0.5.0", + "from": "optionator@>=0.5.0 <0.6.0", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.5.0.tgz", + "dependencies": { + "prelude-ls": { + "version": "1.1.2", + "from": "prelude-ls@>=1.1.1 <1.2.0", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz" + }, + "deep-is": { + "version": "0.1.3", + "from": "deep-is@>=0.1.2 <0.2.0", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz" + }, + "wordwrap": { + "version": "0.0.3", + "from": "wordwrap@>=0.0.2 <0.1.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz" + }, + "type-check": { + "version": "0.3.1", + "from": "type-check@>=0.3.1 <0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.1.tgz" + }, + "levn": { + "version": "0.2.5", + "from": "levn@>=0.2.5 <0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.2.5.tgz" + }, + "fast-levenshtein": { + "version": "1.0.7", + "from": "fast-levenshtein@>=1.0.0 <1.1.0", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.0.7.tgz" + } + } + }, + "source-map": { + "version": "0.1.43", + "from": "source-map@>=0.1.40 <0.2.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", + "dependencies": { + "amdefine": { + "version": "1.0.0", + "from": "amdefine@>=0.0.4", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.0.tgz" + } + } + } + } + }, + "htmlparser2": { + "version": "3.8.3", + "from": "htmlparser2@>=3.7.3 <4.0.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz", + "dependencies": { + "domhandler": { + "version": "2.3.0", + "from": "domhandler@>=2.3.0 <2.4.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.3.0.tgz" + }, + "domutils": { + "version": "1.5.1", + "from": "domutils@>=1.5.0 <1.6.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", + "dependencies": { + "dom-serializer": { + "version": "0.1.0", + "from": "dom-serializer@>=0.0.0 <1.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz", + "dependencies": { + "domelementtype": { + "version": "1.1.3", + "from": "domelementtype@>=1.1.1 <1.2.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz" + }, + "entities": { + "version": "1.1.1", + "from": "entities@>=1.1.1 <1.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz" + } + } + } + } + }, + "domelementtype": { + "version": "1.3.0", + "from": "domelementtype@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz" + }, + "readable-stream": { + "version": "1.1.13", + "from": "readable-stream@>=1.1.0 <1.2.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.13.tgz", + "dependencies": { + "core-util-is": { + "version": "1.0.1", + "from": "core-util-is@>=1.0.0 <1.1.0", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz" + }, + "isarray": { + "version": "0.0.1", + "from": "isarray@0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz" + }, + "string_decoder": { + "version": "0.10.31", + "from": "string_decoder@>=0.10.0 <0.11.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz" + }, + "inherits": { + "version": "2.0.1", + "from": "inherits@>=2.0.1 <2.1.0", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz" + } + } + }, + "entities": { + "version": "1.0.0", + "from": "entities@>=1.0.0 <1.1.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.0.0.tgz" + } + } + }, + "nwmatcher": { + "version": "1.3.6", + "from": "nwmatcher@>=1.3.6 <2.0.0", + "resolved": "https://registry.npmjs.org/nwmatcher/-/nwmatcher-1.3.6.tgz" + }, + "parse5": { + "version": "1.5.0", + "from": "parse5@>=1.4.2 <2.0.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-1.5.0.tgz" + }, + "request": { + "version": "2.61.0", + "from": "request@>=2.55.0 <3.0.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.61.0.tgz", + "dependencies": { + "bl": { + "version": "1.0.0", + "from": "bl@>=1.0.0 <1.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-1.0.0.tgz", + "dependencies": { + "readable-stream": { + "version": "2.0.2", + "from": "readable-stream@>=2.0.0 <2.1.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.2.tgz", + "dependencies": { + "core-util-is": { + "version": "1.0.1", + "from": "core-util-is@>=1.0.0 <1.1.0", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz" + }, + "inherits": { + "version": "2.0.1", + "from": "inherits@>=2.0.1 <2.1.0", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz" + }, + "isarray": { + "version": "0.0.1", + "from": "isarray@0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz" + }, + "process-nextick-args": { + "version": "1.0.2", + "from": "process-nextick-args@>=1.0.0 <1.1.0", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.2.tgz" + }, + "string_decoder": { + "version": "0.10.31", + "from": "string_decoder@>=0.10.0 <0.11.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz" + }, + "util-deprecate": { + "version": "1.0.1", + "from": "util-deprecate@>=1.0.1 <1.1.0", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.1.tgz" + } + } + } + } + }, + "caseless": { + "version": "0.11.0", + "from": "caseless@>=0.11.0 <0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz" + }, + "extend": { + "version": "3.0.0", + "from": "extend@>=3.0.0 <3.1.0", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.0.tgz" + }, + "forever-agent": { + "version": "0.6.1", + "from": "forever-agent@>=0.6.0 <0.7.0", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz" + }, + "form-data": { + "version": "1.0.0-rc3", + "from": "form-data@>=1.0.0-rc1 <1.1.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-1.0.0-rc3.tgz", + "dependencies": { + "async": { + "version": "1.4.2", + "from": "async@>=1.4.0 <2.0.0", + "resolved": "https://registry.npmjs.org/async/-/async-1.4.2.tgz" + } + } + }, + "json-stringify-safe": { + "version": "5.0.1", + "from": "json-stringify-safe@>=5.0.0 <5.1.0", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz" + }, + "mime-types": { + "version": "2.1.6", + "from": "mime-types@>=2.1.2 <2.2.0", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.6.tgz", + "dependencies": { + "mime-db": { + "version": "1.18.0", + "from": "mime-db@>=1.18.0 <1.19.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.18.0.tgz" + } + } + }, + "node-uuid": { + "version": "1.4.3", + "from": "node-uuid@>=1.4.0 <1.5.0", + "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.3.tgz" + }, + "qs": { + "version": "4.0.0", + "from": "qs@>=4.0.0 <4.1.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-4.0.0.tgz" + }, + "tunnel-agent": { + "version": "0.4.1", + "from": "tunnel-agent@>=0.4.0 <0.5.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.1.tgz" + }, + "http-signature": { + "version": "0.11.0", + "from": "http-signature@>=0.11.0 <0.12.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-0.11.0.tgz", + "dependencies": { + "assert-plus": { + "version": "0.1.5", + "from": "assert-plus@>=0.1.5 <0.2.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz" + }, + "asn1": { + "version": "0.1.11", + "from": "asn1@0.1.11", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz" + }, + "ctype": { + "version": "0.5.3", + "from": "ctype@0.5.3", + "resolved": "https://registry.npmjs.org/ctype/-/ctype-0.5.3.tgz" + } + } + }, + "oauth-sign": { + "version": "0.8.0", + "from": "oauth-sign@>=0.8.0 <0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.0.tgz" + }, + "hawk": { + "version": "3.1.0", + "from": "hawk@>=3.1.0 <3.2.0", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.0.tgz", + "dependencies": { + "hoek": { + "version": "2.14.0", + "from": "hoek@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.14.0.tgz" + }, + "boom": { + "version": "2.8.0", + "from": "boom@>=2.8.0 <3.0.0", + "resolved": "https://registry.npmjs.org/boom/-/boom-2.8.0.tgz" + }, + "cryptiles": { + "version": "2.0.4", + "from": "cryptiles@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.4.tgz" + }, + "sntp": { + "version": "1.0.9", + "from": "sntp@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz" + } + } + }, + "aws-sign2": { + "version": "0.5.0", + "from": "aws-sign2@>=0.5.0 <0.6.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.5.0.tgz" + }, + "stringstream": { + "version": "0.0.4", + "from": "stringstream@>=0.0.4 <0.1.0", + "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.4.tgz" + }, + "combined-stream": { + "version": "1.0.5", + "from": "combined-stream@>=1.0.1 <1.1.0", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", + "dependencies": { + "delayed-stream": { + "version": "1.0.0", + "from": "delayed-stream@>=1.0.0 <1.1.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz" + } + } + }, + "isstream": { + "version": "0.1.2", + "from": "isstream@>=0.1.1 <0.2.0", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz" + }, + "har-validator": { + "version": "1.8.0", + "from": "har-validator@>=1.6.1 <2.0.0", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-1.8.0.tgz", + "dependencies": { + "bluebird": { + "version": "2.9.34", + "from": "bluebird@>=2.9.30 <3.0.0", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-2.9.34.tgz" + }, + "commander": { + "version": "2.8.1", + "from": "commander@>=2.8.1 <3.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz", + "dependencies": { + "graceful-readlink": { + "version": "1.0.1", + "from": "graceful-readlink@>=1.0.0", + "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz" + } + } + }, + "is-my-json-valid": { + "version": "2.12.2", + "from": "is-my-json-valid@>=2.12.0 <3.0.0", + "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.12.2.tgz", + "dependencies": { + "generate-function": { + "version": "2.0.0", + "from": "generate-function@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz" + }, + "generate-object-property": { + "version": "1.2.0", + "from": "generate-object-property@>=1.1.0 <2.0.0", + "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", + "dependencies": { + "is-property": { + "version": "1.0.2", + "from": "is-property@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz" + } + } + }, + "jsonpointer": { + "version": "2.0.0", + "from": "jsonpointer@2.0.0", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-2.0.0.tgz" + } + } + } + } + } + } + }, + "symbol-tree": { + "version": "3.1.2", + "from": "symbol-tree@>=3.1.0 <4.0.0", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.1.2.tgz" + }, + "tough-cookie": { + "version": "1.2.0", + "from": "tough-cookie@>=1.1.0 <2.0.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-1.2.0.tgz" + }, + "whatwg-url-compat": { + "version": "0.6.5", + "from": "whatwg-url-compat@>=0.6.5 <0.7.0", + "resolved": "https://registry.npmjs.org/whatwg-url-compat/-/whatwg-url-compat-0.6.5.tgz", + "dependencies": { + "tr46": { + "version": "0.0.2", + "from": "tr46@>=0.0.1 <0.1.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.2.tgz" + } + } + }, + "xml-name-validator": { + "version": "2.0.1", + "from": "xml-name-validator@>=2.0.1 <3.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-2.0.1.tgz" + }, + "xmlhttprequest": { + "version": "1.7.0", + "from": "xmlhttprequest@>=1.6.0 <2.0.0", + "resolved": "https://registry.npmjs.org/xmlhttprequest/-/xmlhttprequest-1.7.0.tgz" + }, + "xtend": { + "version": "4.0.0", + "from": "xtend@>=4.0.0 <5.0.0", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.0.tgz" + } + } + }, + "lodash.template": { + "version": "3.6.2", + "from": "lodash.template@>=3.6.1 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-3.6.2.tgz", + "dependencies": { + "lodash._basecopy": { + "version": "3.0.1", + "from": "lodash._basecopy@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz" + }, + "lodash._basetostring": { + "version": "3.0.1", + "from": "lodash._basetostring@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz" + }, + "lodash._basevalues": { + "version": "3.0.0", + "from": "lodash._basevalues@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz" + }, + "lodash._isiterateecall": { + "version": "3.0.9", + "from": "lodash._isiterateecall@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz" + }, + "lodash._reinterpolate": { + "version": "3.0.0", + "from": "lodash._reinterpolate@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz" + }, + "lodash.escape": { + "version": "3.0.0", + "from": "lodash.escape@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-3.0.0.tgz" + }, + "lodash.keys": { + "version": "3.1.2", + "from": "lodash.keys@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", + "dependencies": { + "lodash._getnative": { + "version": "3.9.1", + "from": "lodash._getnative@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz" + }, + "lodash.isarguments": { + "version": "3.0.4", + "from": "lodash.isarguments@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.0.4.tgz" + }, + "lodash.isarray": { + "version": "3.0.4", + "from": "lodash.isarray@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz" + } + } + }, + "lodash.restparam": { + "version": "3.6.1", + "from": "lodash.restparam@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz" + }, + "lodash.templatesettings": { + "version": "3.1.0", + "from": "lodash.templatesettings@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-3.1.0.tgz" + } + } + }, + "node-haste": { + "version": "1.2.8", + "from": "node-haste@>=1.2.8 <2.0.0", + "resolved": "https://registry.npmjs.org/node-haste/-/node-haste-1.2.8.tgz", + "dependencies": { + "esprima-fb": { + "version": "4001.1001.0-dev-harmony-fb", + "from": "esprima-fb@4001.1001.0-dev-harmony-fb", + "resolved": "https://registry.npmjs.org/esprima-fb/-/esprima-fb-4001.1001.0-dev-harmony-fb.tgz" + } + } + }, + "node-worker-pool": { + "version": "3.0.0", + "from": "node-worker-pool@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/node-worker-pool/-/node-worker-pool-3.0.0.tgz" + }, + "object-assign": { + "version": "4.0.1", + "from": "object-assign@>=4.0.1 <5.0.0", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.0.1.tgz" + }, + "resolve": { + "version": "1.1.6", + "from": "resolve@>=1.1.6 <2.0.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.6.tgz" + }, + "through": { + "version": "2.3.8", + "from": "through@>=2.3.7 <3.0.0", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz" + } + } + }, "joi": { - "version": "5.1.0", - "from": "joi@5.1.0", - "resolved": "https://registry.npmjs.org/joi/-/joi-5.1.0.tgz", + "version": "6.6.1", + "from": "joi@6.6.1", + "resolved": "https://registry.npmjs.org/joi/-/joi-6.6.1.tgz", "dependencies": { "hoek": { "version": "2.14.0", @@ -1235,9 +3014,9 @@ } }, "jstransform": { - "version": "11.0.1", - "from": "jstransform@11.0.1", - "resolved": "https://registry.npmjs.org/jstransform/-/jstransform-11.0.1.tgz", + "version": "11.0.3", + "from": "jstransform@11.0.3", + "resolved": "https://registry.npmjs.org/jstransform/-/jstransform-11.0.3.tgz", "dependencies": { "base62": { "version": "1.1.0", @@ -1372,35 +3151,23 @@ "version": "2.1.1", "from": "object-assign@>=2.0.0 <3.0.0", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz" - }, - "source-map": { - "version": "0.4.4", - "from": "source-map@>=0.4.2 <0.5.0", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", - "dependencies": { - "amdefine": { - "version": "1.0.0", - "from": "amdefine@>=0.0.4", - "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.0.tgz" - } - } } } }, "module-deps": { - "version": "3.5.6", - "from": "module-deps@3.5.6", - "resolved": "https://registry.npmjs.org/module-deps/-/module-deps-3.5.6.tgz", + "version": "3.9.1", + "from": "module-deps@3.9.1", + "resolved": "https://registry.npmjs.org/module-deps/-/module-deps-3.9.1.tgz", "dependencies": { "JSONStream": { - "version": "0.7.4", - "from": "JSONStream@>=0.7.1 <0.8.0", - "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-0.7.4.tgz", + "version": "1.0.4", + "from": "JSONStream@>=1.0.3 <2.0.0", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.0.4.tgz", "dependencies": { "jsonparse": { - "version": "0.0.5", - "from": "jsonparse@0.0.5", - "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-0.0.5.tgz" + "version": "1.0.0", + "from": "jsonparse@>=1.0.0 <1.1.0", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.0.0.tgz" }, "through": { "version": "2.3.8", @@ -1411,15 +3178,8 @@ }, "browser-resolve": { "version": "1.9.1", - "from": "browser-resolve@>=1.3.1 <2.0.0", - "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.9.1.tgz", - "dependencies": { - "resolve": { - "version": "1.1.6", - "from": "resolve@1.1.6", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.6.tgz" - } - } + "from": "browser-resolve@>=1.7.0 <2.0.0", + "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.9.1.tgz" }, "concat-stream": { "version": "1.4.10", @@ -1433,37 +3193,91 @@ } } }, + "defined": { + "version": "1.0.0", + "from": "defined@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz" + }, "detective": { - "version": "3.1.0", - "from": "detective@>=3.1.0 <4.0.0", - "resolved": "https://registry.npmjs.org/detective/-/detective-3.1.0.tgz", + "version": "4.2.0", + "from": "detective@>=4.0.0 <5.0.0", + "resolved": "https://registry.npmjs.org/detective/-/detective-4.2.0.tgz", "dependencies": { + "acorn": { + "version": "1.2.2", + "from": "acorn@>=1.0.3 <2.0.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-1.2.2.tgz" + }, "escodegen": { - "version": "1.1.0", - "from": "escodegen@>=1.1.0 <1.2.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.1.0.tgz", + "version": "1.6.1", + "from": "escodegen@>=1.4.1 <2.0.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.6.1.tgz", "dependencies": { - "esprima": { - "version": "1.0.4", - "from": "esprima@>=1.0.4 <1.1.0", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.0.4.tgz" - }, "estraverse": { - "version": "1.5.1", - "from": "estraverse@>=1.5.0 <1.6.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.5.1.tgz" + "version": "1.9.3", + "from": "estraverse@>=1.9.1 <2.0.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz" }, "esutils": { - "version": "1.0.0", - "from": "esutils@>=1.0.0 <1.1.0", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-1.0.0.tgz" + "version": "1.1.6", + "from": "esutils@>=1.1.6 <2.0.0", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-1.1.6.tgz" + }, + "esprima": { + "version": "1.2.5", + "from": "esprima@>=1.2.2 <2.0.0", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.2.5.tgz" + }, + "optionator": { + "version": "0.5.0", + "from": "optionator@>=0.5.0 <0.6.0", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.5.0.tgz", + "dependencies": { + "prelude-ls": { + "version": "1.1.2", + "from": "prelude-ls@>=1.1.1 <1.2.0", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz" + }, + "deep-is": { + "version": "0.1.3", + "from": "deep-is@>=0.1.2 <0.2.0", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz" + }, + "wordwrap": { + "version": "0.0.3", + "from": "wordwrap@>=0.0.2 <0.1.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz" + }, + "type-check": { + "version": "0.3.1", + "from": "type-check@>=0.3.1 <0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.1.tgz" + }, + "levn": { + "version": "0.2.5", + "from": "levn@>=0.2.5 <0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.2.5.tgz" + }, + "fast-levenshtein": { + "version": "1.0.7", + "from": "fast-levenshtein@>=1.0.0 <1.1.0", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.0.7.tgz" + } + } + }, + "source-map": { + "version": "0.1.43", + "from": "source-map@>=0.1.40 <0.2.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", + "dependencies": { + "amdefine": { + "version": "1.0.0", + "from": "amdefine@>=0.0.4", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.0.tgz" + } + } } } - }, - "esprima-fb": { - "version": "3001.1.0-dev-harmony-fb", - "from": "esprima-fb@3001.1.0-dev-harmony-fb", - "resolved": "https://registry.npmjs.org/esprima-fb/-/esprima-fb-3001.0001.0000-dev-harmony-fb.tgz" } } }, @@ -1477,11 +3291,6 @@ "from": "inherits@>=2.0.1 <3.0.0", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz" }, - "minimist": { - "version": "0.2.0", - "from": "minimist@>=0.2.0 <0.3.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.2.0.tgz" - }, "parents": { "version": "1.0.1", "from": "parents@>=1.0.0 <2.0.0", @@ -1496,7 +3305,7 @@ }, "readable-stream": { "version": "1.1.13", - "from": "readable-stream@>=1.0.27-1 <2.0.0", + "from": "readable-stream@>=1.1.13 <2.0.0", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.13.tgz", "dependencies": { "core-util-is": { @@ -1517,14 +3326,9 @@ } }, "resolve": { - "version": "0.7.4", - "from": "resolve@>=0.7.2 <0.8.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-0.7.4.tgz" - }, - "shallow-copy": { - "version": "0.0.1", - "from": "shallow-copy@0.0.1", - "resolved": "https://registry.npmjs.org/shallow-copy/-/shallow-copy-0.0.1.tgz" + "version": "1.1.6", + "from": "resolve@>=1.1.3 <2.0.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.6.tgz" }, "stream-combiner2": { "version": "1.0.2", @@ -1568,57 +3372,26 @@ } }, "subarg": { - "version": "0.0.1", - "from": "subarg@0.0.1", - "resolved": "https://registry.npmjs.org/subarg/-/subarg-0.0.1.tgz", + "version": "1.0.0", + "from": "subarg@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/subarg/-/subarg-1.0.0.tgz", "dependencies": { "minimist": { - "version": "0.0.10", - "from": "minimist@>=0.0.7 <0.1.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz" + "version": "1.2.0", + "from": "minimist@>=1.1.0 <2.0.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz" } } }, "through2": { - "version": "0.4.2", - "from": "through2@>=0.4.1 <0.5.0", - "resolved": "https://registry.npmjs.org/through2/-/through2-0.4.2.tgz", - "dependencies": { - "readable-stream": { - "version": "1.0.33", - "from": "readable-stream@>=1.0.17 <1.1.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.33.tgz", - "dependencies": { - "core-util-is": { - "version": "1.0.1", - "from": "core-util-is@>=1.0.0 <1.1.0", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz" - }, - "isarray": { - "version": "0.0.1", - "from": "isarray@0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz" - }, - "string_decoder": { - "version": "0.10.31", - "from": "string_decoder@>=0.10.0 <0.11.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz" - } - } - }, - "xtend": { - "version": "2.1.2", - "from": "xtend@>=2.1.1 <2.2.0", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-2.1.2.tgz", - "dependencies": { - "object-keys": { - "version": "0.4.0", - "from": "object-keys@>=0.4.0 <0.5.0", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-0.4.0.tgz" - } - } - } - } + "version": "1.1.1", + "from": "through2@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/through2/-/through2-1.1.1.tgz" + }, + "xtend": { + "version": "4.0.0", + "from": "xtend@>=4.0.0 <5.0.0", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.0.tgz" } } }, @@ -1686,18 +3459,6 @@ "from": "esprima-fb@>=15001.1001.0-dev-harmony-fb <15001.1002.0", "resolved": "https://registry.npmjs.org/esprima-fb/-/esprima-fb-15001.1001.0-dev-harmony-fb.tgz" }, - "source-map": { - "version": "0.4.4", - "from": "source-map@>=0.4.4 <0.5.0", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", - "dependencies": { - "amdefine": { - "version": "1.0.0", - "from": "amdefine@>=0.0.4", - "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.0.tgz" - } - } - }, "ast-types": { "version": "0.8.11", "from": "ast-types@0.8.11", @@ -1800,9 +3561,9 @@ } }, "rebound": { - "version": "0.0.12", - "from": "rebound@>=0.0.12 <0.0.13", - "resolved": "https://registry.npmjs.org/rebound/-/rebound-0.0.12.tgz" + "version": "0.0.13", + "from": "rebound@>=0.0.13 <0.0.14", + "resolved": "https://registry.npmjs.org/rebound/-/rebound-0.0.13.tgz" }, "regenerator": { "version": "0.8.36", @@ -1962,6 +3723,11 @@ "version": "0.1.2", "from": "tryor@>=0.1.2 <0.2.0", "resolved": "https://registry.npmjs.org/tryor/-/tryor-0.1.2.tgz" + }, + "yargs": { + "version": "1.3.3", + "from": "yargs@>=1.3.2 <1.4.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-1.3.3.tgz" } } }, @@ -1980,18 +3746,6 @@ "from": "recast@0.10.25", "resolved": "https://registry.npmjs.org/recast/-/recast-0.10.25.tgz", "dependencies": { - "source-map": { - "version": "0.4.4", - "from": "source-map@>=0.4.1 <0.5.0", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", - "dependencies": { - "amdefine": { - "version": "1.0.0", - "from": "amdefine@>=0.0.4", - "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.0.tgz" - } - } - }, "ast-types": { "version": "0.8.5", "from": "ast-types@0.8.5", @@ -2008,7 +3762,7 @@ }, "sane": { "version": "1.2.0", - "from": "sane@>=1.1.2 <2.0.0", + "from": "sane@>=1.2.0 <1.3.0", "resolved": "https://registry.npmjs.org/sane/-/sane-1.2.0.tgz", "dependencies": { "exec-sh": { @@ -2026,21 +3780,7 @@ "fb-watchman": { "version": "1.6.0", "from": "fb-watchman@>=1.5.0 <2.0.0", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-1.6.0.tgz", - "dependencies": { - "bser": { - "version": "1.0.2", - "from": "bser@>=1.0.2 <2.0.0", - "resolved": "https://registry.npmjs.org/bser/-/bser-1.0.2.tgz", - "dependencies": { - "node-int64": { - "version": "0.4.0", - "from": "node-int64@>=0.4.0 <0.5.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz" - } - } - } - } + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-1.6.0.tgz" }, "minimatch": { "version": "0.2.14", @@ -2091,14 +3831,14 @@ } }, "semver": { - "version": "4.3.6", - "from": "semver@>=4.3.6 <5.0.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz" + "version": "5.0.1", + "from": "semver@>=5.0.1 <6.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.0.1.tgz" }, "source-map": { - "version": "0.1.31", - "from": "source-map@0.1.31", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.31.tgz", + "version": "0.4.4", + "from": "source-map@0.4.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", "dependencies": { "amdefine": { "version": "1.0.0", @@ -2113,9 +3853,9 @@ "resolved": "https://registry.npmjs.org/stacktrace-parser/-/stacktrace-parser-0.1.3.tgz" }, "uglify-js": { - "version": "2.4.16", - "from": "uglify-js@2.4.16", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.4.16.tgz", + "version": "2.4.24", + "from": "uglify-js@2.4.24", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.4.24.tgz", "dependencies": { "async": { "version": "0.2.10", @@ -2134,29 +3874,44 @@ } } }, - "optimist": { - "version": "0.3.7", - "from": "optimist@>=0.3.5 <0.4.0", - "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.3.7.tgz", - "dependencies": { - "wordwrap": { - "version": "0.0.3", - "from": "wordwrap@>=0.0.2 <0.1.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz" - } - } - }, "uglify-to-browserify": { "version": "1.0.2", "from": "uglify-to-browserify@>=1.0.0 <1.1.0", "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz" + }, + "yargs": { + "version": "3.5.4", + "from": "yargs@>=3.5.4 <3.6.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.5.4.tgz", + "dependencies": { + "camelcase": { + "version": "1.2.1", + "from": "camelcase@>=1.0.2 <2.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz" + }, + "decamelize": { + "version": "1.0.0", + "from": "decamelize@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.0.0.tgz" + }, + "window-size": { + "version": "0.1.0", + "from": "window-size@0.1.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz" + }, + "wordwrap": { + "version": "0.0.2", + "from": "wordwrap@0.0.2", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz" + } + } } } }, "underscore": { - "version": "1.7.0", - "from": "underscore@1.7.0", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.7.0.tgz" + "version": "1.8.3", + "from": "underscore@1.8.3", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz" }, "wordwrap": { "version": "1.0.0", @@ -2239,9 +3994,134 @@ } }, "yargs": { - "version": "1.3.2", - "from": "yargs@1.3.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-1.3.2.tgz" + "version": "3.24.0", + "from": "yargs@3.24.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.24.0.tgz", + "dependencies": { + "camelcase": { + "version": "1.2.1", + "from": "camelcase@>=1.2.1 <2.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz" + }, + "cliui": { + "version": "2.1.0", + "from": "cliui@>=2.1.0 <3.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", + "dependencies": { + "center-align": { + "version": "0.1.1", + "from": "center-align@>=0.1.1 <0.2.0", + "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.1.tgz", + "dependencies": { + "align-text": { + "version": "0.1.3", + "from": "align-text@>=0.1.1 <0.2.0", + "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.3.tgz", + "dependencies": { + "kind-of": { + "version": "2.0.1", + "from": "kind-of@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-2.0.1.tgz", + "dependencies": { + "is-buffer": { + "version": "1.0.2", + "from": "is-buffer@>=1.0.2 <2.0.0", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.0.2.tgz" + } + } + }, + "longest": { + "version": "1.0.1", + "from": "longest@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz" + }, + "repeat-string": { + "version": "1.5.2", + "from": "repeat-string@>=1.5.2 <2.0.0", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.5.2.tgz" + } + } + } + } + }, + "right-align": { + "version": "0.1.3", + "from": "right-align@>=0.1.1 <0.2.0", + "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", + "dependencies": { + "align-text": { + "version": "0.1.3", + "from": "align-text@>=0.1.1 <0.2.0", + "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.3.tgz", + "dependencies": { + "kind-of": { + "version": "2.0.1", + "from": "kind-of@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-2.0.1.tgz", + "dependencies": { + "is-buffer": { + "version": "1.0.2", + "from": "is-buffer@>=1.0.2 <2.0.0", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.0.2.tgz" + } + } + }, + "longest": { + "version": "1.0.1", + "from": "longest@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz" + }, + "repeat-string": { + "version": "1.5.2", + "from": "repeat-string@>=1.5.2 <2.0.0", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.5.2.tgz" + } + } + } + } + }, + "wordwrap": { + "version": "0.0.2", + "from": "wordwrap@0.0.2", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz" + } + } + }, + "decamelize": { + "version": "1.0.0", + "from": "decamelize@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.0.0.tgz" + }, + "os-locale": { + "version": "1.3.1", + "from": "os-locale@>=1.3.1 <2.0.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.3.1.tgz", + "dependencies": { + "lcid": { + "version": "1.0.0", + "from": "lcid@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "dependencies": { + "invert-kv": { + "version": "1.0.0", + "from": "invert-kv@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz" + } + } + } + } + }, + "window-size": { + "version": "0.1.2", + "from": "window-size@>=0.1.2 <0.2.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.2.tgz" + }, + "y18n": { + "version": "3.1.0", + "from": "y18n@>=3.1.0 <4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.1.0.tgz" + } + } }, "yeoman-environment": { "version": "1.2.7", @@ -2277,7 +4157,7 @@ }, "async": { "version": "1.4.2", - "from": "async@>=1.2.1 <2.0.0", + "from": "async@>=1.4.2 <2.0.0", "resolved": "https://registry.npmjs.org/async/-/async-1.4.2.tgz" }, "glob": { @@ -2420,7 +4300,7 @@ }, "lodash": { "version": "3.10.1", - "from": "lodash@>=3.5.0 <4.0.0", + "from": "lodash@>=3.1.0 <4.0.0", "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz" }, "log-symbols": { @@ -2440,7 +4320,7 @@ "dependencies": { "readable-stream": { "version": "1.0.33", - "from": "readable-stream@>=1.0.17 <1.1.0", + "from": "readable-stream@>=1.0.33-1 <1.1.0-0", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.33.tgz", "dependencies": { "core-util-is": { @@ -2655,7 +4535,7 @@ }, "readable-stream": { "version": "2.0.2", - "from": "readable-stream@>=2.0.0 <3.0.0", + "from": "readable-stream@>=2.0.0 <2.1.0", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.2.tgz", "dependencies": { "core-util-is": { @@ -3109,7 +4989,7 @@ }, "timed-out": { "version": "2.0.0", - "from": "timed-out@>=2.0.0 <3.0.0", + "from": "timed-out@2.0.0", "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-2.0.0.tgz" } } @@ -3257,7 +5137,7 @@ }, "vinyl": { "version": "0.5.3", - "from": "vinyl@>=0.5.1 <0.6.0", + "from": "vinyl@>=0.5.0 <0.6.0", "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.5.3.tgz", "dependencies": { "clone": { @@ -3823,7 +5703,7 @@ }, "vinyl": { "version": "0.5.3", - "from": "vinyl@>=0.5.1 <0.6.0", + "from": "vinyl@>=0.5.0 <0.6.0", "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.5.3.tgz", "dependencies": { "clone": { @@ -4931,7 +6811,7 @@ }, "timed-out": { "version": "2.0.0", - "from": "timed-out@>=2.0.0 <3.0.0", + "from": "timed-out@2.0.0", "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-2.0.0.tgz" } } @@ -4945,7 +6825,7 @@ }, "meow": { "version": "3.3.0", - "from": "meow@*", + "from": "meow@>=3.1.0 <4.0.0", "resolved": "https://registry.npmjs.org/meow/-/meow-3.3.0.tgz", "dependencies": { "camelcase-keys": { @@ -5534,7 +7414,7 @@ }, "meow": { "version": "3.3.0", - "from": "meow@*", + "from": "meow@>=3.1.0 <4.0.0", "resolved": "https://registry.npmjs.org/meow/-/meow-3.3.0.tgz", "dependencies": { "camelcase-keys": { diff --git a/package.json b/package.json index cebee4dfa..bb21b3e9f 100644 --- a/package.json +++ b/package.json @@ -47,42 +47,42 @@ }, "dependencies": { "absolute-path": "0.0.0", - "babel": "5.8.21", - "babel-core": "5.8.21", - "bser": "1.0.0", - "chalk": "1.0.0", + "babel": "5.8.23", + "babel-core": "5.8.23", + "bser": "1.0.2", + "chalk": "1.1.1", "connect": "2.8.3", - "debug": "2.1.0", + "debug": "2.2.0", "graceful-fs": "4.1.2", "image-size": "0.3.5", - "immutable": "^3.7.4", - "joi": "5.1.0", - "jstransform": "11.0.1", - "module-deps": "3.5.6", + "immutable": "3.7.5", + "joi": "6.6.1", + "jstransform": "11.0.3", + "module-deps": "3.9.1", "optimist": "0.6.1", - "progress": "^1.1.8", - "promise": "^7.0.3", - "react-timer-mixin": "^0.13.1", + "progress": "1.1.8", + "promise": "7.0.4", + "react-timer-mixin": "0.13.2", "react-tools": "git://github.com/facebook/react#b4e74e38e43ac53af8acd62c78c9213be0194245", - "rebound": "^0.0.12", + "rebound": "0.0.13", "regenerator": "0.8.36", - "sane": "^1.1.2", - "semver": "^4.3.6", - "source-map": "0.1.31", + "sane": "^1.2.0", + "semver": "5.0.1", + "source-map": "0.4.4", "stacktrace-parser": "0.1.3", - "uglify-js": "2.4.16", - "underscore": "1.7.0", - "wordwrap": "^1.0.0", - "worker-farm": "^1.3.1", + "uglify-js": "2.4.24", + "underscore": "1.8.3", + "wordwrap": "1.0.0", + "worker-farm": "1.3.1", "ws": "0.8.0", - "yargs": "1.3.2", - "yeoman-environment": "^1.2.7", - "yeoman-generator": "^0.20.2" + "yargs": "3.24.0", + "yeoman-environment": "1.2.7", + "yeoman-generator": "0.20.3" }, "devDependencies": { - "jest-cli": "0.5.0", - "babel-eslint": "3.1.5", - "eslint": "0.21.2", - "eslint-plugin-react": "2.3.0" + "jest-cli": "0.5.1", + "babel-eslint": "4.1.1", + "eslint": "1.3.1", + "eslint-plugin-react": "3.3.1" } } diff --git a/packager/packager.js b/packager/packager.js index 8f0f08007..b5f789699 100644 --- a/packager/packager.js +++ b/packager/packager.js @@ -59,6 +59,14 @@ var options = parseCommandLine([{ type: 'string', default: require.resolve('./transformer.js'), description: 'Specify a custom transformer to be used (absolute path)' +}, { + command: 'resetCache', + description: 'Removes cached files', + default: false, +}, { + command: 'reset-cache', + description: 'Removes cached files', + default: false, }]); if (options.projectRoots) { @@ -229,6 +237,7 @@ function getAppMiddleware(options) { transformModulePath: transformerPath, assetRoots: options.assetRoots, assetExts: ['png', 'jpeg', 'jpg'], + resetCache: options.resetCache || options['reset-cache'], polyfillModuleNames: [ require.resolve( '../Libraries/JavaScriptAppEngine/polyfills/document.js' diff --git a/packager/react-packager/src/AssetServer/__tests__/AssetServer-test.js b/packager/react-packager/src/AssetServer/__tests__/AssetServer-test.js index 54ef70120..d36889149 100644 --- a/packager/react-packager/src/AssetServer/__tests__/AssetServer-test.js +++ b/packager/react-packager/src/AssetServer/__tests__/AssetServer-test.js @@ -1,6 +1,7 @@ 'use strict'; jest + .dontMock('../../lib/getPlatformExtension') .dontMock('../../lib/getAssetDataFromName') .dontMock('../'); @@ -47,6 +48,43 @@ describe('AssetServer', () => { ); }); + pit('should work for the simple case with platform ext', () => { + const server = new AssetServer({ + projectRoots: ['/root'], + assetExts: ['png'], + }); + + fs.__setMockFilesystem({ + 'root': { + imgs: { + 'b.ios.png': 'b ios image', + 'b.android.png': 'b android image', + 'c.png': 'c general image', + 'c.android.png': 'c android image', + } + } + }); + + return Promise.all([ + server.get('imgs/b.png', 'ios').then( + data => expect(data).toBe('b ios image') + ), + server.get('imgs/b.png', 'android').then( + data => expect(data).toBe('b android image') + ), + server.get('imgs/c.png', 'android').then( + data => expect(data).toBe('c android image') + ), + server.get('imgs/c.png', 'ios').then( + data => expect(data).toBe('c general image') + ), + server.get('imgs/c.png').then( + data => expect(data).toBe('c general image') + ), + ]); + }); + + pit('should work for the simple case with jpg', () => { const server = new AssetServer({ projectRoots: ['/root'], @@ -95,6 +133,37 @@ describe('AssetServer', () => { ); }); + pit('should pick the bigger one with platform ext', () => { + const server = new AssetServer({ + projectRoots: ['/root'], + assetExts: ['png'], + }); + + fs.__setMockFilesystem({ + 'root': { + imgs: { + 'b@1x.png': 'b1 image', + 'b@2x.png': 'b2 image', + 'b@4x.png': 'b4 image', + 'b@4.5x.png': 'b4.5 image', + 'b@1x.ios.png': 'b1 ios image', + 'b@2x.ios.png': 'b2 ios image', + 'b@4x.ios.png': 'b4 ios image', + 'b@4.5x.ios.png': 'b4.5 ios image', + } + } + }); + + return Promise.all([ + server.get('imgs/b@3x.png').then(data => + expect(data).toBe('b4 image') + ), + server.get('imgs/b@3x.png', 'ios').then(data => + expect(data).toBe('b4 ios image') + ), + ]); + }); + pit('should support multiple project roots', () => { const server = new AssetServer({ projectRoots: ['/root', '/root2'], diff --git a/packager/react-packager/src/AssetServer/index.js b/packager/react-packager/src/AssetServer/index.js index f442f6b89..5783e9912 100644 --- a/packager/react-packager/src/AssetServer/index.js +++ b/packager/react-packager/src/AssetServer/index.js @@ -20,7 +20,6 @@ const stat = Promise.denodeify(fs.stat); const readDir = Promise.denodeify(fs.readdir); const readFile = Promise.denodeify(fs.readFile); - const validateOpts = declareOpts({ projectRoots: { type: 'array', @@ -39,9 +38,9 @@ class AssetServer { this._assetExts = opts.assetExts; } - get(assetPath) { + get(assetPath, platform = null) { const assetData = getAssetDataFromName(assetPath); - return this._getAssetRecord(assetPath).then(record => { + return this._getAssetRecord(assetPath, platform).then(record => { for (let i = 0; i < record.scales.length; i++) { if (record.scales[i] >= assetData.resolution) { return readFile(record.files[i]); @@ -52,14 +51,14 @@ class AssetServer { }); } - getAssetData(assetPath) { + getAssetData(assetPath, platform = null) { const nameData = getAssetDataFromName(assetPath); const data = { name: nameData.name, type: nameData.type, }; - return this._getAssetRecord(assetPath).then(record => { + return this._getAssetRecord(assetPath, platform).then(record => { data.scales = record.scales; return Promise.all( @@ -85,9 +84,10 @@ class AssetServer { * 1. We first parse the directory of the asset * 2. We check to find a matching directory in one of the project roots * 3. We then build a map of all assets and their scales in this directory - * 4. Then pick the closest resolution (rounding up) to the requested one + * 4. Then try to pick platform-specific asset records + * 5. Then pick the closest resolution (rounding up) to the requested one */ - _getAssetRecord(assetPath) { + _getAssetRecord(assetPath, platform = null) { const filename = path.basename(assetPath); return ( @@ -104,11 +104,20 @@ class AssetServer { const files = res[1]; const assetData = getAssetDataFromName(filename); - const map = this._buildAssetMap(dir, files); - const record = map[assetData.assetName]; + const map = this._buildAssetMap(dir, files, platform); + + let record; + if (platform != null){ + record = map[getAssetKey(assetData.assetName, platform)] || + map[assetData.assetName]; + } else { + record = map[assetData.assetName]; + } if (!record) { - throw new Error('Asset not found'); + throw new Error( + `Asset not found: ${assetPath} for platform: ${platform}` + ); } return record; @@ -141,9 +150,10 @@ class AssetServer { const map = Object.create(null); assets.forEach(function(asset, i) { const file = files[i]; - let record = map[asset.assetName]; + const assetKey = getAssetKey(asset.assetName, asset.platform); + let record = map[assetKey]; if (!record) { - record = map[asset.assetName] = { + record = map[assetKey] = { scales: [], files: [], }; @@ -151,6 +161,7 @@ class AssetServer { let insertIndex; const length = record.scales.length; + for (insertIndex = 0; insertIndex < length; insertIndex++) { if (asset.resolution < record.scales[insertIndex]) { break; @@ -164,4 +175,12 @@ class AssetServer { } } +function getAssetKey(assetName, platform) { + if (platform != null) { + return `${assetName} : ${platform}`; + } else { + return assetName; + } +} + module.exports = AssetServer; diff --git a/packager/react-packager/src/Bundler/Bundle.js b/packager/react-packager/src/Bundler/Bundle.js index b7920ebb8..6f20b49d0 100644 --- a/packager/react-packager/src/Bundler/Bundle.js +++ b/packager/react-packager/src/Bundler/Bundle.js @@ -115,13 +115,18 @@ class Bundle { getMinifiedSourceAndMap() { this._assertFinalized(); + if (this._minifiedSourceAndMap) { + return this._minifiedSourceAndMap; + } + const source = this._getSource(); try { - return UglifyJS.minify(source, { + this._minifiedSourceAndMap = UglifyJS.minify(source, { fromString: true, outSourceMap: 'bundle.js', inSourceMap: this.getSourceMap(), }); + return this._minifiedSourceAndMap; } catch(e) { // Sometimes, when somebody is using a new syntax feature that we // don't yet have transform for, the untransformed line is sent to @@ -186,6 +191,10 @@ class Bundle { options = options || {}; + if (options.minify) { + return this.getMinifiedSourceAndMap().map; + } + if (this._shouldCombineSourceMaps) { return this._getCombinedSourceMaps(options); } diff --git a/packager/react-packager/src/Bundler/index.js b/packager/react-packager/src/Bundler/index.js index 8f76ce103..5f2ead1cf 100644 --- a/packager/react-packager/src/Bundler/index.js +++ b/packager/react-packager/src/Bundler/index.js @@ -154,7 +154,7 @@ class Bundler { bundle.setMainModuleId(result.mainModuleId); return Promise.all( result.dependencies.map( - module => this._transformModule(bundle, module).then(transformed => { + module => this._transformModule(bundle, module, platform).then(transformed => { if (bar) { bar.tick(); } @@ -182,13 +182,13 @@ class Bundler { return this._resolver.getDependencies(main, { dev: isDev, platform }); } - _transformModule(bundle, module) { + _transformModule(bundle, module, platform = null) { let transform; if (module.isAsset_DEPRECATED()) { transform = this.generateAssetModule_DEPRECATED(bundle, module); } else if (module.isAsset()) { - transform = this.generateAssetModule(bundle, module); + transform = this.generateAssetModule(bundle, module, platform); } else if (module.isJSON()) { transform = generateJSONModule(module); } else { @@ -243,12 +243,12 @@ class Bundler { }); } - generateAssetModule(bundle, module) { + generateAssetModule(bundle, module, platform = null) { const relPath = getPathRelativeToRoot(this._projectRoots, module.path); return Promise.all([ sizeOf(module.path), - this._assetServer.getAssetData(relPath), + this._assetServer.getAssetData(relPath, platform), ]).then(function(res) { const dimensions = res[0]; const assetData = res[1]; diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js index eab913839..092a8c05b 100644 --- a/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js +++ b/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js @@ -16,6 +16,7 @@ jest .dontMock('../../crawlers') .dontMock('../../crawlers/node') .dontMock('../../replacePatterns') + .dontMock('../../../lib/getPlatformExtension') .dontMock('../../../lib/getAssetDataFromName') .dontMock('../../fastfs') .dontMock('../../AssetModule_DEPRECATED') @@ -424,6 +425,90 @@ describe('DependencyGraph', function() { }); }); + pit('should respect platform extension in assets', function() { + var root = '/root'; + fs.__setMockFilesystem({ + 'root': { + 'index.js': [ + '/**', + ' * @providesModule index', + ' */', + 'require("./imgs/a.png");', + 'require("./imgs/b.png");', + 'require("./imgs/c.png");', + ].join('\n'), + 'imgs': { + 'a@1.5x.ios.png': '', + 'b@.7x.ios.png': '', + 'c.ios.png': '', + 'c@2x.ios.png': '', + }, + 'package.json': JSON.stringify({ + name: 'rootPackage' + }), + } + }); + + var dgraph = new DependencyGraph({ + roots: [root], + fileWatcher: fileWatcher, + assetExts: ['png', 'jpg'], + cache: cache, + }); + + dgraph.setup({ platform: 'ios' }); + + return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) { + expect(deps) + .toEqual([ + { + id: 'index', + path: '/root/index.js', + dependencies: [ + './imgs/a.png', + './imgs/b.png', + './imgs/c.png', + ], + isAsset: false, + isAsset_DEPRECATED: false, + isJSON: false, + isPolyfill: false, + resolution: undefined, + }, + { + id: 'rootPackage/imgs/a.png', + path: '/root/imgs/a@1.5x.ios.png', + resolution: 1.5, + dependencies: [], + isAsset: true, + isAsset_DEPRECATED: false, + isJSON: false, + isPolyfill: false, + }, + { + id: 'rootPackage/imgs/b.png', + path: '/root/imgs/b@.7x.ios.png', + resolution: 0.7, + dependencies: [], + isAsset: true, + isAsset_DEPRECATED: false, + isJSON: false, + isPolyfill: false, + }, + { + id: 'rootPackage/imgs/c.png', + path: '/root/imgs/c.ios.png', + resolution: 1, + dependencies: [], + isAsset: true, + isAsset_DEPRECATED: false, + isJSON: false, + isPolyfill: false, + }, + ]); + }); + }); + pit('Deprecated and relative assets can live together', function() { var root = '/root'; fs.__setMockFilesystem({ diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js index f2b77f4d5..0820c14a9 100644 --- a/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js +++ b/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js @@ -1,4 +1,4 @@ -/** + /** * Copyright (c) 2015-present, Facebook, Inc. * All rights reserved. * @@ -17,6 +17,7 @@ const crawl = require('../crawlers'); const debug = require('debug')('DependencyGraph'); const declareOpts = require('../../lib/declareOpts'); const getAssetDataFromName = require('../../lib/getAssetDataFromName'); +const getPontentialPlatformExt = require('../../lib/getPlatformExtension'); const isAbsolutePath = require('absolute-path'); const path = require('path'); const util = require('util'); @@ -274,7 +275,7 @@ class DependencyGraph { // `platformExt` could be set in the `setup` method. if (!this._platformExt) { - const platformExt = getPlatformExt(entryPath); + const platformExt = getPontentialPlatformExt(entryPath); if (platformExt && this._opts.platforms.indexOf(platformExt) > -1) { this._platformExt = platformExt; } else { @@ -390,12 +391,18 @@ class DependencyGraph { return Promise.resolve().then(() => { if (this._isAssetFile(potentialModulePath)) { const {name, type} = getAssetDataFromName(potentialModulePath); - const pattern = new RegExp('^' + name + '(@[\\d\\.]+x)?\\.' + type); + + let pattern = '^' + name + '(@[\\d\\.]+x)?'; + if (this._platformExt != null) { + pattern += '(\\.' + this._platformExt + ')?'; + } + pattern += '\\.' + type; + // We arbitrarly grab the first one, because scale selection // will happen somewhere const [assetFile] = this._fastfs.matches( path.dirname(potentialModulePath), - pattern + new RegExp(pattern) ); if (assetFile) { @@ -496,7 +503,7 @@ class DependencyGraph { const modules = this._hasteMap[name]; if (this._platformExt != null) { for (let i = 0; i < modules.length; i++) { - if (getPlatformExt(modules[i].path) === this._platformExt) { + if (getPontentialPlatformExt(modules[i].path) === this._platformExt) { return modules[i]; } } @@ -662,15 +669,6 @@ function normalizePath(modulePath) { return modulePath.replace(/\/$/, ''); } -// Extract platform extension: index.ios.js -> ios -function getPlatformExt(file) { - const parts = path.basename(file).split('.'); - if (parts.length < 3) { - return null; - } - return parts[parts.length - 2]; -} - util.inherits(NotFoundError, Error); module.exports = DependencyGraph; diff --git a/packager/react-packager/src/Server/__tests__/Server-test.js b/packager/react-packager/src/Server/__tests__/Server-test.js index d9ec6dbe6..af7542c7a 100644 --- a/packager/react-packager/src/Server/__tests__/Server-test.js +++ b/packager/react-packager/src/Server/__tests__/Server-test.js @@ -245,8 +245,16 @@ describe('processRequest', () => { expect(res.end).toBeCalledWith('i am image'); }); - it('should return 404', () => { + it('should parse the platform option', () => { + const req = {url: '/assets/imgs/a.png?platform=ios'}; + const res = {end: jest.genMockFn()}; + AssetServer.prototype.get.mockImpl(() => Promise.resolve('i am image')); + + server.processRequest(req, res); + jest.runAllTimers(); + expect(AssetServer.prototype.get).toBeCalledWith('imgs/a.png', 'ios'); + expect(res.end).toBeCalledWith('i am image'); }); }); diff --git a/packager/react-packager/src/Server/index.js b/packager/react-packager/src/Server/index.js index d727fd52a..e889a357e 100644 --- a/packager/react-packager/src/Server/index.js +++ b/packager/react-packager/src/Server/index.js @@ -278,7 +278,8 @@ class Server { _processAssetsRequest(req, res) { const urlObj = url.parse(req.url, true); const assetPath = urlObj.pathname.match(/^\/assets\/(.+)$/); - this._assetServer.get(assetPath[1]) + const assetEvent = Activity.startEvent(`processing asset request ${assetPath[1]}`); + this._assetServer.get(assetPath[1], urlObj.query.platform) .then( data => res.end(data), error => { @@ -286,7 +287,7 @@ class Server { res.writeHead('404'); res.end('Asset not found'); } - ).done(); + ).done(() => Activity.endEvent(assetEvent)); } _processProfile(req, res) { @@ -370,7 +371,9 @@ class Server { res.end(bundleSource); Activity.endEvent(startReqEventId); } else if (requestType === 'map') { - var sourceMap = JSON.stringify(p.getSourceMap()); + var sourceMap = JSON.stringify(p.getSourceMap({ + minify: options.minify, + })); res.setHeader('Content-Type', 'application/json'); res.end(sourceMap); Activity.endEvent(startReqEventId); diff --git a/packager/react-packager/src/SocketInterface/SocketClient.js b/packager/react-packager/src/SocketInterface/SocketClient.js index e20e5b896..32e3b25d7 100644 --- a/packager/react-packager/src/SocketInterface/SocketClient.js +++ b/packager/react-packager/src/SocketInterface/SocketClient.js @@ -12,6 +12,7 @@ const Bundle = require('../Bundler/Bundle'); const Promise = require('promise'); const bser = require('bser'); const debug = require('debug')('ReactPackager:SocketClient'); +const fs = require('fs'); const net = require('net'); const path = require('path'); const tmpdir = require('os').tmpdir(); @@ -29,7 +30,16 @@ class SocketClient { this._sock = net.connect(sockPath); this._ready = new Promise((resolve, reject) => { this._sock.on('connect', () => resolve(this)); - this._sock.on('error', (e) => reject(e)); + this._sock.on('error', (e) => { + e.message = `Error connecting to server on ${sockPath} ` + + `with error: ${e.message}`; + + if (fs.existsSync(LOG_PATH)) { + e.message += '\nServer logs:\n' + fs.readFileSync(LOG_PATH, 'utf8'); + } + + reject(e); + }); }); this._resolvers = Object.create(null); diff --git a/packager/react-packager/src/SocketInterface/SocketServer.js b/packager/react-packager/src/SocketInterface/SocketServer.js index b292b2bfa..888dcf78a 100644 --- a/packager/react-packager/src/SocketInterface/SocketServer.js +++ b/packager/react-packager/src/SocketInterface/SocketServer.js @@ -16,6 +16,7 @@ const fs = require('fs'); const net = require('net'); const MAX_IDLE_TIME = 30 * 1000; +const MAX_STARTUP_TIME = 5 * 60 * 1000; class SocketServer { constructor(sockPath, options) { @@ -35,13 +36,15 @@ class SocketServer { process.on('exit', () => fs.unlinkSync(sockPath)); }); }); + + this._numConnections = 0; this._server.on('connection', (sock) => this._handleConnection(sock)); // Disable the file watcher. options.nonPersistent = true; this._packagerServer = new Server(options); this._jobs = 0; - this._dieEventually(); + this._dieEventually(MAX_STARTUP_TIME); } onReady() { @@ -50,10 +53,13 @@ class SocketServer { _handleConnection(sock) { debug('connection to server', process.pid); + this._numConnections++; + sock.on('close', () => this._numConnections--); const bunser = new bser.BunserBuf(); sock.on('data', (buf) => bunser.append(buf)); bunser.on('value', (m) => this._handleMessage(sock, m)); + bunser.on('error', (e) => console.error(e)); } _handleMessage(sock, m) { @@ -113,15 +119,15 @@ class SocketServer { })); } - _dieEventually() { + _dieEventually(delay = MAX_IDLE_TIME) { clearTimeout(this._deathTimer); this._deathTimer = setTimeout(() => { - if (this._jobs <= 0) { + if (this._jobs <= 0 && this._numConnections <= 0) { debug('server dying', process.pid); process.exit(); } this._dieEventually(); - }, MAX_IDLE_TIME); + }, delay); } static listenOnServerIPCMessages() { diff --git a/packager/react-packager/src/SocketInterface/index.js b/packager/react-packager/src/SocketInterface/index.js index 19b39bf09..eab83fa4f 100644 --- a/packager/react-packager/src/SocketInterface/index.js +++ b/packager/react-packager/src/SocketInterface/index.js @@ -20,7 +20,7 @@ const path = require('path'); const tmpdir = require('os').tmpdir(); const {spawn} = require('child_process'); -const CREATE_SERVER_TIMEOUT = 60000; +const CREATE_SERVER_TIMEOUT = 5 * 60 * 1000; const SocketInterface = { getOrCreateSocketFor(options) { @@ -42,8 +42,16 @@ const SocketInterface = { if (fs.existsSync(sockPath)) { var sock = net.connect(sockPath); sock.on('connect', () => { - sock.end(); - resolve(SocketClient.create(sockPath)); + SocketClient.create(sockPath).then( + client => { + sock.end(); + resolve(client); + }, + error => { + sock.end(); + reject(error); + } + ); }); sock.on('error', (e) => { try { diff --git a/packager/react-packager/src/lib/__tests__/extractAssetResolution-test.js b/packager/react-packager/src/lib/__tests__/extractAssetResolution-test.js deleted file mode 100644 index d0309ca6a..000000000 --- a/packager/react-packager/src/lib/__tests__/extractAssetResolution-test.js +++ /dev/null @@ -1,52 +0,0 @@ -'use strict'; - -jest.autoMockOff(); -var getAssetDataFromName = require('../getAssetDataFromName'); - -describe('getAssetDataFromName', function() { - it('should extract resolution simple case', function() { - var data = getAssetDataFromName('test@2x.png'); - expect(data).toEqual({ - assetName: 'test.png', - resolution: 2, - type: 'png', - name: 'test', - }); - }); - - it('should default resolution to 1', function() { - var data = getAssetDataFromName('test.png'); - expect(data).toEqual({ - assetName: 'test.png', - resolution: 1, - type: 'png', - name: 'test', - }); - }); - - it('should support float', function() { - var data = getAssetDataFromName('test@1.1x.png'); - expect(data).toEqual({ - assetName: 'test.png', - resolution: 1.1, - type: 'png', - name: 'test', - }); - - data = getAssetDataFromName('test@.1x.png'); - expect(data).toEqual({ - assetName: 'test.png', - resolution: 0.1, - type: 'png', - name: 'test', - }); - - data = getAssetDataFromName('test@0.2x.png'); - expect(data).toEqual({ - assetName: 'test.png', - resolution: 0.2, - type: 'png', - name: 'test', - }); - }); -}); diff --git a/packager/react-packager/src/lib/__tests__/getAssetDataFromName-test.js b/packager/react-packager/src/lib/__tests__/getAssetDataFromName-test.js new file mode 100644 index 000000000..d67110015 --- /dev/null +++ b/packager/react-packager/src/lib/__tests__/getAssetDataFromName-test.js @@ -0,0 +1,123 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ +'use strict'; + +jest.dontMock('../getPlatformExtension') + .dontMock('../getAssetDataFromName'); + +describe('getAssetDataFromName', () => { + let getAssetDataFromName; + + beforeEach(() => { + getAssetDataFromName = require('../getAssetDataFromName'); + }); + + it('should get data from name', () => { + expect(getAssetDataFromName('a/b/c.png')).toEqual({ + resolution: 1, + assetName: 'a/b/c.png', + type: 'png', + name: 'c', + platform: null, + }); + + expect(getAssetDataFromName('a/b/c@1x.png')).toEqual({ + resolution: 1, + assetName: 'a/b/c.png', + type: 'png', + name: 'c', + platform: null, + }); + + expect(getAssetDataFromName('a/b/c@2.5x.png')).toEqual({ + resolution: 2.5, + assetName: 'a/b/c.png', + type: 'png', + name: 'c', + platform: null, + }); + + expect(getAssetDataFromName('a/b/c.ios.png')).toEqual({ + resolution: 1, + assetName: 'a/b/c.png', + type: 'png', + name: 'c', + platform: 'ios', + }); + + expect(getAssetDataFromName('a/b/c@1x.ios.png')).toEqual({ + resolution: 1, + assetName: 'a/b/c.png', + type: 'png', + name: 'c', + platform: 'ios', + }); + + expect(getAssetDataFromName('a/b/c@2.5x.ios.png')).toEqual({ + resolution: 2.5, + assetName: 'a/b/c.png', + type: 'png', + name: 'c', + platform: 'ios', + }); + }); + + describe('resolution extraction', () => { + it('should extract resolution simple case', () => { + var data = getAssetDataFromName('test@2x.png'); + expect(data).toEqual({ + assetName: 'test.png', + resolution: 2, + type: 'png', + name: 'test', + platform: null, + }); + }); + + it('should default resolution to 1', () => { + var data = getAssetDataFromName('test.png'); + expect(data).toEqual({ + assetName: 'test.png', + resolution: 1, + type: 'png', + name: 'test', + platform: null, + }); + }); + + it('should support float', () => { + var data = getAssetDataFromName('test@1.1x.png'); + expect(data).toEqual({ + assetName: 'test.png', + resolution: 1.1, + type: 'png', + name: 'test', + platform: null, + }); + + data = getAssetDataFromName('test@.1x.png'); + expect(data).toEqual({ + assetName: 'test.png', + resolution: 0.1, + type: 'png', + name: 'test', + platform: null, + }); + + data = getAssetDataFromName('test@0.2x.png'); + expect(data).toEqual({ + assetName: 'test.png', + resolution: 0.2, + type: 'png', + name: 'test', + platform: null, + }); + }); + }); +}); diff --git a/packager/react-packager/src/lib/__tests__/getPotentialPlatformExt-test.js b/packager/react-packager/src/lib/__tests__/getPotentialPlatformExt-test.js new file mode 100644 index 000000000..5f734880e --- /dev/null +++ b/packager/react-packager/src/lib/__tests__/getPotentialPlatformExt-test.js @@ -0,0 +1,24 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ +'use strict'; + +jest.dontMock('../getPlatformExtension'); + +describe('getPlatformExtension', function() { + it('should get platform ext', function() { + var getPlatformExtension = require('../getPlatformExtension'); + expect(getPlatformExtension('a.ios.js')).toBe('ios'); + expect(getPlatformExtension('a.android.js')).toBe('android'); + expect(getPlatformExtension('/b/c/a.ios.js')).toBe('ios'); + expect(getPlatformExtension('/b/c.android/a.ios.js')).toBe('ios'); + expect(getPlatformExtension('/b/c/a@1.5x.ios.png')).toBe('ios'); + expect(getPlatformExtension('/b/c/a@1.5x.lol.png')).toBe(null); + expect(getPlatformExtension('/b/c/a.lol.png')).toBe(null); + }); +}); diff --git a/packager/react-packager/src/lib/getAssetDataFromName.js b/packager/react-packager/src/lib/getAssetDataFromName.js index c4848fd17..33fa13cea 100644 --- a/packager/react-packager/src/lib/getAssetDataFromName.js +++ b/packager/react-packager/src/lib/getAssetDataFromName.js @@ -1,14 +1,29 @@ + /** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ 'use strict'; -var path = require('path'); +const path = require('path'); +const getPlatformExtension = require('./getPlatformExtension'); function getAssetDataFromName(filename) { - var ext = path.extname(filename); + const ext = path.extname(filename); + const platformExt = getPlatformExtension(filename); - var re = new RegExp('@([\\d\\.]+)x\\' + ext + '$'); + let pattern = '@([\\d\\.]+)x'; + if (platformExt != null) { + pattern += '(\\.' + platformExt + ')?'; + } + pattern += '\\' + ext + '$'; + const re = new RegExp(pattern); - var match = filename.match(re); - var resolution; + const match = filename.match(re); + let resolution; if (!(match && match[1])) { resolution = 1; @@ -19,12 +34,21 @@ function getAssetDataFromName(filename) { } } - var assetName = match ? filename.replace(re, ext) : filename; + let assetName; + if (match) { + assetName = filename.replace(re, ext); + } else if (platformExt != null) { + assetName = filename.replace(new RegExp(`\\.${platformExt}\\${ext}`), ext); + } else { + assetName = filename; + } + return { resolution: resolution, assetName: assetName, type: ext.slice(1), - name: path.basename(assetName, ext) + name: path.basename(assetName, ext), + platform: platformExt, }; } diff --git a/packager/react-packager/src/lib/getPlatformExtension.js b/packager/react-packager/src/lib/getPlatformExtension.js new file mode 100644 index 000000000..3f34da421 --- /dev/null +++ b/packager/react-packager/src/lib/getPlatformExtension.js @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ +'use strict'; + +const path = require('path'); + +const SUPPORTED_PLATFORM_EXTS = ['android', 'ios']; + +const re = new RegExp( + '[^\\.]+\\.(' + SUPPORTED_PLATFORM_EXTS.join('|') + ')\\.\\w+$' +); + +// Extract platform extension: index.ios.js -> ios +function getPlatformExtension(file) { + const match = file.match(re); + if (match && match[1]) { + return match[1]; + } + return null; +} + +module.exports = getPlatformExtension; diff --git a/packager/transformer.js b/packager/transformer.js index 8f7a48c29..b3ab96d08 100644 --- a/packager/transformer.js +++ b/packager/transformer.js @@ -39,6 +39,7 @@ function transform(srcTxt, filename, options) { 'es7.objectRestSpread', 'flow', 'react', + 'react.displayName', 'regenerator', ], plugins: plugins,