mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Compare commits
20
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
af89654699 | ||
|
|
776bd34eb3 | ||
|
|
ac4a214eeb | ||
|
|
1f85e21464 | ||
|
|
a41995ff5c | ||
|
|
6d64892c8a | ||
|
|
5d95e9950c | ||
|
|
6b39d644ea | ||
|
|
dff572c174 | ||
|
|
af3e1d4a86 | ||
|
|
897a3a5d5e | ||
|
|
0fea3515a1 | ||
|
|
80e8efe8e7 | ||
|
|
d1888650c5 | ||
|
|
f65b9e883a | ||
|
|
aa0b2ad1cd | ||
|
|
0a319978ff | ||
|
|
29e5deb85f | ||
|
|
031feb6942 | ||
|
|
d82138ff91 |
@@ -44,7 +44,10 @@ RCT_EXPORT_MODULE()
|
||||
// form of an, NSURL which is what assets-library uses.
|
||||
NSString *assetID = @"";
|
||||
PHFetchResult *results;
|
||||
if ([imageURL.scheme caseInsensitiveCompare:@"assets-library"] == NSOrderedSame) {
|
||||
if (!imageURL) {
|
||||
completionHandler(RCTErrorWithMessage(@"Cannot load a photo library asset with no URL"), nil);
|
||||
return ^{};
|
||||
} else if ([imageURL.scheme caseInsensitiveCompare:@"assets-library"] == NSOrderedSame) {
|
||||
assetID = [imageURL absoluteString];
|
||||
results = [PHAsset fetchAssetsWithALAssetURLs:@[imageURL] options:nil];
|
||||
} else {
|
||||
|
||||
@@ -116,6 +116,23 @@ if (!global.__fbDisableExceptionsManager) {
|
||||
ErrorUtils.setGlobalHandler(handleError);
|
||||
}
|
||||
|
||||
const formatVersion = version =>
|
||||
`${version.major}.${version.minor}.${version.patch}` +
|
||||
(version.prerelease !== null ? `-${version.prerelease}` : '');
|
||||
|
||||
const ReactNativeVersion = require('ReactNativeVersion');
|
||||
const nativeVersion = require('NativeModules').PlatformConstants.reactNativeVersion;
|
||||
if (ReactNativeVersion.version.major !== nativeVersion.major ||
|
||||
ReactNativeVersion.version.minor !== nativeVersion.minor) {
|
||||
throw new Error(
|
||||
`React Native version mismatch.\n\nJavaScript version: ${formatVersion(ReactNativeVersion.version)}\n` +
|
||||
`Native version: ${formatVersion(nativeVersion)}\n\n` +
|
||||
'Make sure that you have rebuilt the native code. If the problem persists ' +
|
||||
'try clearing the watchman and packager caches with `watchman watch-del-all ' +
|
||||
'&& react-native start --reset-cache`.'
|
||||
);
|
||||
}
|
||||
|
||||
// Set up collections
|
||||
const _shouldPolyfillCollection = require('_shouldPolyfillES6Collection');
|
||||
if (_shouldPolyfillCollection('Map')) {
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* @generated by scripts/bump-oss-version.js
|
||||
*
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @flow
|
||||
* @providesModule ReactNativeVersion
|
||||
*/
|
||||
|
||||
exports.version = {
|
||||
major: 0,
|
||||
minor: 49,
|
||||
patch: 0,
|
||||
prerelease: 'rc.6',
|
||||
};
|
||||
@@ -927,6 +927,10 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithBundleURL:(__unused NSURL *)bundleUR
|
||||
{
|
||||
RCTAssertJSThread();
|
||||
|
||||
if (!self.valid) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (buffer != nil && buffer != (id)kCFNull) {
|
||||
_wasBatchActive = YES;
|
||||
[self handleBuffer:buffer];
|
||||
|
||||
@@ -373,6 +373,8 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init);
|
||||
- (dispatch_queue_t)methodQueue
|
||||
{
|
||||
(void)[self instance];
|
||||
RCTAssert(_methodQueue != nullptr, @"Module %@ has no methodQueue (instance: %@, bridge.valid: %d)",
|
||||
self, _instance, _bridge.valid);
|
||||
return _methodQueue;
|
||||
}
|
||||
|
||||
|
||||
@@ -76,7 +76,7 @@
|
||||
// Throttle progress events so we don't send more that around 60 per second.
|
||||
CFTimeInterval currentTime = CACurrentMediaTime();
|
||||
|
||||
NSUInteger headersContentLength = headers[@"Content-Length"] != nil ? [headers[@"Content-Length"] unsignedIntValue] : 0;
|
||||
NSInteger headersContentLength = headers[@"Content-Length"] != nil ? [headers[@"Content-Length"] integerValue] : 0;
|
||||
if (callback && (currentTime - _lastDownloadProgress > 0.016 || final)) {
|
||||
_lastDownloadProgress = currentTime;
|
||||
callback(headers, @(headersContentLength), @(contentLength));
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "RCTUtils.h"
|
||||
#import "RCTVersion.h"
|
||||
|
||||
static NSString *interfaceIdiom(UIUserInterfaceIdiom idiom) {
|
||||
switch(idiom) {
|
||||
@@ -46,6 +47,7 @@ RCT_EXPORT_MODULE(PlatformConstants)
|
||||
@"systemName": [device systemName],
|
||||
@"interfaceIdiom": interfaceIdiom([device userInterfaceIdiom]),
|
||||
@"isTesting": @(RCTRunningInTestEnvironment()),
|
||||
@"reactNativeVersion": REACT_NATIVE_VERSION,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* @generated by scripts/bump-oss-version.js
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#define REACT_NATIVE_VERSION @{ \
|
||||
@"major": @(0), \
|
||||
@"minor": @(49), \
|
||||
@"patch": @(0), \
|
||||
@"prerelease": @"rc.6", \
|
||||
}
|
||||
@@ -125,13 +125,12 @@ struct RCTInstanceCallback : public InstanceCallback {
|
||||
[bridge_ partialBatchDidFlush];
|
||||
[bridge_ batchDidComplete];
|
||||
}
|
||||
void incrementPendingJSCalls() override {}
|
||||
void decrementPendingJSCalls() override {}
|
||||
};
|
||||
|
||||
@implementation RCTCxxBridge
|
||||
{
|
||||
BOOL _wasBatchActive;
|
||||
BOOL _didInvalidate;
|
||||
|
||||
NSMutableArray<dispatch_block_t> *_pendingCalls;
|
||||
std::atomic<NSInteger> _pendingCount;
|
||||
@@ -169,7 +168,7 @@ struct RCTInstanceCallback : public InstanceCallback {
|
||||
|
||||
- (JSGlobalContextRef)jsContextRef
|
||||
{
|
||||
return (JSGlobalContextRef)self->_reactInstance->getJavaScriptContext();
|
||||
return (JSGlobalContextRef)(self->_reactInstance ? self->_reactInstance->getJavaScriptContext() : nullptr);
|
||||
}
|
||||
|
||||
- (instancetype)initWithParentBridge:(RCTBridge *)bridge
|
||||
@@ -204,7 +203,7 @@ struct RCTInstanceCallback : public InstanceCallback {
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)runJSRunLoop
|
||||
+ (void)runRunLoop
|
||||
{
|
||||
@autoreleasepool {
|
||||
RCT_PROFILE_BEGIN_EVENT(RCTProfileTagAlways, @"-[RCTCxxBridge runJSRunLoop] setup", nil);
|
||||
@@ -267,8 +266,8 @@ struct RCTInstanceCallback : public InstanceCallback {
|
||||
object:_parentBridge userInfo:@{@"bridge": self}];
|
||||
|
||||
// Set up the JS thread early
|
||||
_jsThread = [[NSThread alloc] initWithTarget:self
|
||||
selector:@selector(runJSRunLoop)
|
||||
_jsThread = [[NSThread alloc] initWithTarget:[self class]
|
||||
selector:@selector(runRunLoop)
|
||||
object:nil];
|
||||
_jsThread.name = RCTJSThreadName;
|
||||
_jsThread.qualityOfService = NSOperationQualityOfServiceUserInteractive;
|
||||
@@ -493,7 +492,7 @@ struct RCTInstanceCallback : public InstanceCallback {
|
||||
if (_reactInstance) {
|
||||
// This is async, but any calls into JS are blocked by the m_syncReady CV in Instance
|
||||
_reactInstance->initializeBridge(
|
||||
std::unique_ptr<RCTInstanceCallback>(new RCTInstanceCallback(self)),
|
||||
std::make_unique<RCTInstanceCallback>(self),
|
||||
executorFactory,
|
||||
_jsMessageThread,
|
||||
[self _buildModuleRegistry]);
|
||||
@@ -816,6 +815,7 @@ struct RCTInstanceCallback : public InstanceCallback {
|
||||
}
|
||||
|
||||
RCTFatal(error);
|
||||
|
||||
// RN will stop, but let the rest of the app keep going.
|
||||
return;
|
||||
}
|
||||
@@ -826,27 +826,27 @@ struct RCTInstanceCallback : public InstanceCallback {
|
||||
|
||||
// Hack: once the bridge is invalidated below, it won't initialize any new native
|
||||
// modules. Initialize the redbox module now so we can still report this error.
|
||||
[self redBox];
|
||||
RCTRedBox *redBox = [self redBox];
|
||||
|
||||
_loading = NO;
|
||||
_valid = NO;
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (self->_jsMessageThread) {
|
||||
auto thread = self->_jsMessageThread;
|
||||
self->_jsMessageThread->runOnQueue([thread] {
|
||||
thread->quitSynchronous();
|
||||
});
|
||||
self->_jsMessageThread.reset();
|
||||
// Make sure initializeBridge completed
|
||||
self->_jsMessageThread->runOnQueueSync([] {});
|
||||
}
|
||||
|
||||
self->_reactInstance.reset();
|
||||
self->_jsMessageThread.reset();
|
||||
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
postNotificationName:RCTJavaScriptDidFailToLoadNotification
|
||||
object:self->_parentBridge userInfo:@{@"bridge": self, @"error": error}];
|
||||
|
||||
if ([error userInfo][RCTJSRawStackTraceKey]) {
|
||||
[self.redBox showErrorMessage:[error localizedDescription]
|
||||
withRawStack:[error userInfo][RCTJSRawStackTraceKey]];
|
||||
[redBox showErrorMessage:[error localizedDescription]
|
||||
withRawStack:[error userInfo][RCTJSRawStackTraceKey]];
|
||||
}
|
||||
|
||||
RCTFatal(error);
|
||||
@@ -913,63 +913,68 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithBundleURL:(__unused NSURL *)bundleUR
|
||||
|
||||
- (void)invalidate
|
||||
{
|
||||
if (!_valid) {
|
||||
if (_didInvalidate) {
|
||||
return;
|
||||
}
|
||||
|
||||
RCTAssertMainQueue();
|
||||
RCTAssert(_reactInstance != nil, @"Can't complete invalidation without a react instance");
|
||||
RCTLogInfo(@"Invalidating %@ (parent: %@, executor: %@)", self, _parentBridge, [self executorClass]);
|
||||
|
||||
_loading = NO;
|
||||
_valid = NO;
|
||||
_didInvalidate = YES;
|
||||
|
||||
if ([RCTBridge currentBridge] == self) {
|
||||
[RCTBridge setCurrentBridge:nil];
|
||||
}
|
||||
|
||||
// Invalidate modules
|
||||
dispatch_group_t group = dispatch_group_create();
|
||||
for (RCTModuleData *moduleData in _moduleDataByID) {
|
||||
// Be careful when grabbing an instance here, we don't want to instantiate
|
||||
// any modules just to invalidate them.
|
||||
if (![moduleData hasInstance]) {
|
||||
continue;
|
||||
// Stop JS instance and message thread
|
||||
[self ensureOnJavaScriptThread:^{
|
||||
[self->_displayLink invalidate];
|
||||
self->_displayLink = nil;
|
||||
|
||||
if (RCTProfileIsProfiling()) {
|
||||
RCTProfileUnhookModules(self);
|
||||
}
|
||||
|
||||
if ([moduleData.instance respondsToSelector:@selector(invalidate)]) {
|
||||
dispatch_group_enter(group);
|
||||
[self dispatchBlock:^{
|
||||
[(id<RCTInvalidating>)moduleData.instance invalidate];
|
||||
dispatch_group_leave(group);
|
||||
} queue:moduleData.methodQueue];
|
||||
// Invalidate modules
|
||||
// We're on the JS thread (which we'll be suspending soon), so no new calls will be made to native modules after
|
||||
// this completes. We must ensure all previous calls were dispatched before deallocating the instance (and module
|
||||
// wrappers) or we may have invalid pointers still in flight.
|
||||
dispatch_group_t moduleInvalidation = dispatch_group_create();
|
||||
for (RCTModuleData *moduleData in self->_moduleDataByID) {
|
||||
// Be careful when grabbing an instance here, we don't want to instantiate
|
||||
// any modules just to invalidate them.
|
||||
if (![moduleData hasInstance]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ([moduleData.instance respondsToSelector:@selector(invalidate)]) {
|
||||
dispatch_group_enter(moduleInvalidation);
|
||||
[self dispatchBlock:^{
|
||||
[(id<RCTInvalidating>)moduleData.instance invalidate];
|
||||
dispatch_group_leave(moduleInvalidation);
|
||||
} queue:moduleData.methodQueue];
|
||||
}
|
||||
[moduleData invalidate];
|
||||
}
|
||||
[moduleData invalidate];
|
||||
}
|
||||
|
||||
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
|
||||
[self ensureOnJavaScriptThread:^{
|
||||
[self->_displayLink invalidate];
|
||||
self->_displayLink = nil;
|
||||
if (dispatch_group_wait(moduleInvalidation, dispatch_time(DISPATCH_TIME_NOW, 10 * NSEC_PER_SEC))) {
|
||||
RCTLogError(@"Timed out waiting for modules to be invalidated");
|
||||
}
|
||||
|
||||
self->_reactInstance.reset();
|
||||
if (self->_jsMessageThread) {
|
||||
self->_jsMessageThread->quitSynchronous();
|
||||
self->_jsMessageThread.reset();
|
||||
}
|
||||
self->_reactInstance.reset();
|
||||
self->_jsMessageThread.reset();
|
||||
|
||||
if (RCTProfileIsProfiling()) {
|
||||
RCTProfileUnhookModules(self);
|
||||
}
|
||||
self->_moduleDataByName = nil;
|
||||
self->_moduleDataByID = nil;
|
||||
self->_moduleClassesByID = nil;
|
||||
self->_pendingCalls = nil;
|
||||
|
||||
self->_moduleDataByName = nil;
|
||||
self->_moduleDataByID = nil;
|
||||
self->_moduleClassesByID = nil;
|
||||
self->_pendingCalls = nil;
|
||||
|
||||
[self->_jsThread cancel];
|
||||
self->_jsThread = nil;
|
||||
CFRunLoopStop(CFRunLoopGetCurrent());
|
||||
}];
|
||||
});
|
||||
[self->_jsThread cancel];
|
||||
self->_jsThread = nil;
|
||||
CFRunLoopStop(CFRunLoopGetCurrent());
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)logMessage:(NSString *)message level:(NSString *)level
|
||||
@@ -1098,7 +1103,6 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithBundleURL:(__unused NSURL *)bundleUR
|
||||
*/
|
||||
|
||||
RCTProfileBeginFlowEvent();
|
||||
|
||||
[self _runAfterLoad:^{
|
||||
RCTProfileEndFlowEvent();
|
||||
|
||||
@@ -1189,25 +1193,25 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithBundleURL:(__unused NSURL *)bundleUR
|
||||
if (!_reactInstance) {
|
||||
if (error) {
|
||||
*error = RCTErrorWithMessage(
|
||||
@"Attempt to call sync callFunctionOnModule: on uninitialized bridge");
|
||||
@"callFunctionOnModule was called on uninitialized bridge");
|
||||
}
|
||||
return nil;
|
||||
} else if (self.executorClass) {
|
||||
if (error) {
|
||||
*error = RCTErrorWithMessage(
|
||||
@"sync callFunctionOnModule: can only be used with JSC executor");
|
||||
@"callFunctionOnModule can only be used with JSC executor");
|
||||
}
|
||||
return nil;
|
||||
} else if (!self.valid) {
|
||||
if (error) {
|
||||
*error = RCTErrorWithMessage(
|
||||
@"sync callFunctionOnModule: bridge is no longer valid");
|
||||
@"Bridge is no longer valid");
|
||||
}
|
||||
return nil;
|
||||
} else if (self.loading) {
|
||||
if (error) {
|
||||
*error = RCTErrorWithMessage(
|
||||
@"sync callFunctionOnModule: bridge is still loading");
|
||||
@"Bridge is still loading");
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@ public:
|
||||
|
||||
void runOnQueue(std::function<void()>&& func) override {
|
||||
dispatch_queue_t queue = moduleData_.methodQueue;
|
||||
RCTAssert(queue != nullptr, @"Module %@ provided invalid queue", moduleData_);
|
||||
dispatch_block_t block = [func=std::move(func)] { func(); };
|
||||
RCTAssert(block != nullptr, @"Invalid block generated in call to %@", moduleData_);
|
||||
if (queue && block) {
|
||||
|
||||
@@ -203,6 +203,8 @@
|
||||
14F7A0F01BDA714B003C6C10 /* RCTFPSGraph.m in Sources */ = {isa = PBXBuildFile; fileRef = 14F7A0EF1BDA714B003C6C10 /* RCTFPSGraph.m */; };
|
||||
191E3EBE1C29D9AF00C180A6 /* RCTRefreshControlManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 191E3EBD1C29D9AF00C180A6 /* RCTRefreshControlManager.m */; };
|
||||
191E3EC11C29DC3800C180A6 /* RCTRefreshControl.m in Sources */ = {isa = PBXBuildFile; fileRef = 191E3EC01C29DC3800C180A6 /* RCTRefreshControl.m */; };
|
||||
199B8A6F1F44DB16005DEF67 /* RCTVersion.h in Headers */ = {isa = PBXBuildFile; fileRef = 199B8A6E1F44DB16005DEF67 /* RCTVersion.h */; };
|
||||
199B8A761F44DEDA005DEF67 /* RCTVersion.h in Headers */ = {isa = PBXBuildFile; fileRef = 199B8A6E1F44DB16005DEF67 /* RCTVersion.h */; };
|
||||
19F61BFA1E8495CD00571D81 /* bignum-dtoa.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 139D7E3A1E25C5A300323FB7 /* bignum-dtoa.h */; };
|
||||
19F61BFB1E8495CD00571D81 /* bignum.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 139D7E3C1E25C5A300323FB7 /* bignum.h */; };
|
||||
19F61BFC1E8495CD00571D81 /* cached-powers.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 139D7E3E1E25C5A300323FB7 /* cached-powers.h */; };
|
||||
@@ -1842,6 +1844,7 @@
|
||||
191E3EBD1C29D9AF00C180A6 /* RCTRefreshControlManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTRefreshControlManager.m; sourceTree = "<group>"; };
|
||||
191E3EBF1C29DC3800C180A6 /* RCTRefreshControl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTRefreshControl.h; sourceTree = "<group>"; };
|
||||
191E3EC01C29DC3800C180A6 /* RCTRefreshControl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTRefreshControl.m; sourceTree = "<group>"; };
|
||||
199B8A6E1F44DB16005DEF67 /* RCTVersion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTVersion.h; sourceTree = "<group>"; };
|
||||
19DED2281E77E29200F089BB /* systemJSCWrapper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = systemJSCWrapper.cpp; sourceTree = "<group>"; };
|
||||
27B958731E57587D0096647A /* JSBigString.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSBigString.cpp; sourceTree = "<group>"; };
|
||||
2D2A28131D9B038B00D4039D /* libReact.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libReact.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
@@ -2652,6 +2655,7 @@
|
||||
1345A83B1B265A0E00583190 /* RCTURLRequestHandler.h */,
|
||||
83CBBA4F1A601E3B00E9B192 /* RCTUtils.h */,
|
||||
83CBBA501A601E3B00E9B192 /* RCTUtils.m */,
|
||||
199B8A6E1F44DB16005DEF67 /* RCTVersion.h */,
|
||||
);
|
||||
path = Base;
|
||||
sourceTree = "<group>";
|
||||
@@ -2792,6 +2796,7 @@
|
||||
3D302F411DF828F800D6DDAE /* RCTModuleMethod.h in Headers */,
|
||||
3D302F421DF828F800D6DDAE /* RCTMultipartDataTask.h in Headers */,
|
||||
3D302F431DF828F800D6DDAE /* RCTMultipartStreamReader.h in Headers */,
|
||||
199B8A761F44DEDA005DEF67 /* RCTVersion.h in Headers */,
|
||||
3D302F441DF828F800D6DDAE /* RCTNullability.h in Headers */,
|
||||
3D302F451DF828F800D6DDAE /* RCTParserUtils.h in Headers */,
|
||||
3D302F461DF828F800D6DDAE /* RCTPerformanceLogger.h in Headers */,
|
||||
@@ -3029,6 +3034,7 @@
|
||||
3D80DA191DF820620028D040 /* RCTImageLoader.h in Headers */,
|
||||
C654505E1F3BD9280090799B /* RCTManagedPointer.h in Headers */,
|
||||
13134C941E296B2A00B9F3CB /* RCTObjcExecutor.h in Headers */,
|
||||
199B8A6F1F44DB16005DEF67 /* RCTVersion.h in Headers */,
|
||||
3D80DA1A1DF820620028D040 /* RCTImageStoreManager.h in Headers */,
|
||||
130443A11E3FEAA900D93A67 /* RCTFollyConvert.h in Headers */,
|
||||
59FBEFB41E46D91C0095D885 /* RCTScrollContentViewManager.h in Headers */,
|
||||
|
||||
+32
-19
@@ -36,33 +36,46 @@
|
||||
typedef CGFloat RCTFontWeight;
|
||||
static RCTFontWeight weightOfFont(UIFont *font)
|
||||
{
|
||||
static NSDictionary *nameToWeight;
|
||||
static NSArray *fontNames;
|
||||
static NSArray *fontWeights;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
nameToWeight = @{
|
||||
@"normal": @(UIFontWeightRegular),
|
||||
@"bold": @(UIFontWeightBold),
|
||||
@"ultralight": @(UIFontWeightUltraLight),
|
||||
@"thin": @(UIFontWeightThin),
|
||||
@"light": @(UIFontWeightLight),
|
||||
@"regular": @(UIFontWeightRegular),
|
||||
@"medium": @(UIFontWeightMedium),
|
||||
@"semibold": @(UIFontWeightSemibold),
|
||||
@"bold": @(UIFontWeightBold),
|
||||
@"heavy": @(UIFontWeightHeavy),
|
||||
@"black": @(UIFontWeightBlack),
|
||||
};
|
||||
// We use two arrays instead of one map because
|
||||
// the order is important for suffix matching.
|
||||
fontNames = @[
|
||||
@"normal",
|
||||
@"ultralight",
|
||||
@"thin",
|
||||
@"light",
|
||||
@"regular",
|
||||
@"medium",
|
||||
@"semibold",
|
||||
@"bold",
|
||||
@"heavy",
|
||||
@"black"
|
||||
];
|
||||
fontWeights = @[
|
||||
@(UIFontWeightRegular),
|
||||
@(UIFontWeightUltraLight),
|
||||
@(UIFontWeightThin),
|
||||
@(UIFontWeightLight),
|
||||
@(UIFontWeightRegular),
|
||||
@(UIFontWeightMedium),
|
||||
@(UIFontWeightSemibold),
|
||||
@(UIFontWeightBold),
|
||||
@(UIFontWeightHeavy),
|
||||
@(UIFontWeightBlack)
|
||||
];
|
||||
});
|
||||
|
||||
for (NSString *name in nameToWeight) {
|
||||
if ([font.fontName.lowercaseString hasSuffix:name]) {
|
||||
return [nameToWeight[name] doubleValue];
|
||||
for (NSInteger i = 0; i < fontNames.count; i++) {
|
||||
if ([font.fontName.lowercaseString hasSuffix:fontNames[i]]) {
|
||||
return (RCTFontWeight)[fontWeights[i] doubleValue];
|
||||
}
|
||||
}
|
||||
|
||||
NSDictionary *traits = [font.fontDescriptor objectForKey:UIFontDescriptorTraitsAttribute];
|
||||
RCTFontWeight weight = [traits[UIFontWeightTrait] doubleValue];
|
||||
return weight;
|
||||
return (RCTFontWeight)[traits[UIFontWeightTrait] doubleValue];
|
||||
}
|
||||
|
||||
static BOOL isItalicFont(UIFont *font)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
VERSION_NAME=1000.0.0-master
|
||||
VERSION_NAME=0.49.0-rc.6
|
||||
GROUP=com.facebook.react
|
||||
|
||||
POM_NAME=ReactNative
|
||||
|
||||
+1
-1
@@ -40,7 +40,7 @@ import com.facebook.react.bridge.ReactContext;
|
||||
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
|
||||
WindowManager.LayoutParams.MATCH_PARENT,
|
||||
WindowManager.LayoutParams.MATCH_PARENT,
|
||||
WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
|
||||
WindowOverlayCompat.TYPE_SYSTEM_OVERLAY,
|
||||
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
|
||||
| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
|
||||
PixelFormat.TRANSLUCENT);
|
||||
|
||||
+1
-1
@@ -143,7 +143,7 @@ public class DevLoadingViewController {
|
||||
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
|
||||
WindowManager.LayoutParams.MATCH_PARENT,
|
||||
WindowManager.LayoutParams.WRAP_CONTENT,
|
||||
WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
|
||||
WindowOverlayCompat.TYPE_SYSTEM_OVERLAY,
|
||||
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
|
||||
PixelFormat.TRANSLUCENT);
|
||||
params.gravity = Gravity.TOP;
|
||||
|
||||
@@ -36,7 +36,6 @@ import android.content.pm.PackageManager;
|
||||
import android.hardware.SensorManager;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.facebook.common.logging.FLog;
|
||||
@@ -337,7 +336,7 @@ public class DevSupportManagerImpl implements
|
||||
public void run() {
|
||||
if (mRedBoxDialog == null) {
|
||||
mRedBoxDialog = new RedBoxDialog(mApplicationContext, DevSupportManagerImpl.this, mRedBoxHandler);
|
||||
mRedBoxDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
|
||||
mRedBoxDialog.getWindow().setType(WindowOverlayCompat.TYPE_SYSTEM_ALERT);
|
||||
}
|
||||
if (mRedBoxDialog.isShowing()) {
|
||||
// Sometimes errors cause multiple errors to be thrown in JS in quick succession. Only
|
||||
@@ -466,7 +465,7 @@ public class DevSupportManagerImpl implements
|
||||
}
|
||||
})
|
||||
.create();
|
||||
mDevOptionsDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
|
||||
mDevOptionsDialog.getWindow().setType(WindowOverlayCompat.TYPE_SYSTEM_ALERT);
|
||||
mDevOptionsDialog.show();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.facebook.react.devsupport;
|
||||
|
||||
import android.os.Build;
|
||||
import android.view.WindowManager;
|
||||
|
||||
/**
|
||||
* Compatibility wrapper for apps targeting API level 26 or later.
|
||||
* See https://developer.android.com/about/versions/oreo/android-8.0-changes.html#cwt
|
||||
*/
|
||||
/* package */ class WindowOverlayCompat {
|
||||
|
||||
private static final int ANDROID_OREO = 26;
|
||||
private static final int TYPE_APPLICATION_OVERLAY = 2038;
|
||||
|
||||
static final int TYPE_SYSTEM_ALERT = Build.VERSION.SDK_INT < ANDROID_OREO ? WindowManager.LayoutParams.TYPE_SYSTEM_ALERT : TYPE_APPLICATION_OVERLAY;
|
||||
static final int TYPE_SYSTEM_OVERLAY = Build.VERSION.SDK_INT < ANDROID_OREO ? WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY : TYPE_APPLICATION_OVERLAY;
|
||||
|
||||
}
|
||||
+1
@@ -38,6 +38,7 @@ public class AndroidInfoModule extends BaseJavaModule {
|
||||
constants.put("Version", Build.VERSION.SDK_INT);
|
||||
constants.put("ServerHost", AndroidInfoHelpers.getServerHost());
|
||||
constants.put("isTesting", "true".equals(System.getProperty(IS_TESTING)));
|
||||
constants.put("reactNativeVersion", ReactNativeVersion.VERSION);
|
||||
return constants;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ android_library(
|
||||
name = "systeminfo",
|
||||
srcs = [
|
||||
"AndroidInfoModule.java",
|
||||
"ReactNativeVersion.java",
|
||||
],
|
||||
exported_deps = [
|
||||
":systeminfo-moduleless",
|
||||
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* @generated by scripts/bump-oss-version.js
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.facebook.react.modules.systeminfo;
|
||||
|
||||
import com.facebook.react.common.MapBuilder;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class ReactNativeVersion {
|
||||
public static final Map<String, Object> VERSION = MapBuilder.<String, Object>of(
|
||||
"major", 0,
|
||||
"minor", 49,
|
||||
"patch", 0,
|
||||
"prerelease", "rc.6");
|
||||
}
|
||||
@@ -27,8 +27,6 @@ public class OnScrollDispatchHelper {
|
||||
|
||||
private long mLastScrollEventTimeMs = -(MIN_EVENT_SEPARATION_MS + 1);
|
||||
|
||||
private static final float THRESHOLD = 0.1f; // Threshold for end fling
|
||||
|
||||
/**
|
||||
* Call from a ScrollView in onScrollChanged, returns true if this onScrollChanged is legit (not a
|
||||
* duplicate) and should be dispatched.
|
||||
@@ -40,11 +38,6 @@ public class OnScrollDispatchHelper {
|
||||
mPrevX != x ||
|
||||
mPrevY != y;
|
||||
|
||||
// Skip the first calculation in each scroll
|
||||
if (Math.abs(mXFlingVelocity) < THRESHOLD && Math.abs(mYFlingVelocity) < THRESHOLD) {
|
||||
shouldDispatch = false;
|
||||
}
|
||||
|
||||
if (eventTime - mLastScrollEventTimeMs != 0) {
|
||||
mXFlingVelocity = (float) (x - mPrevX) / (eventTime - mLastScrollEventTimeMs);
|
||||
mYFlingVelocity = (float) (y - mPrevY) / (eventTime - mLastScrollEventTimeMs);
|
||||
|
||||
@@ -27,9 +27,9 @@ class ModuleRegistry;
|
||||
|
||||
struct InstanceCallback {
|
||||
virtual ~InstanceCallback() {}
|
||||
virtual void onBatchComplete() = 0;
|
||||
virtual void incrementPendingJSCalls() = 0;
|
||||
virtual void decrementPendingJSCalls() = 0;
|
||||
virtual void onBatchComplete() {}
|
||||
virtual void incrementPendingJSCalls() {}
|
||||
virtual void decrementPendingJSCalls() {}
|
||||
};
|
||||
|
||||
class RN_EXPORT Instance {
|
||||
|
||||
+6
-2
@@ -58,7 +58,8 @@ test:
|
||||
- cat <(echo eslint; npm run lint --silent -- --format=json; echo flow; npm run flow --silent -- check --json) | GITHUB_TOKEN="af6ef0d15709bc91d""06a6217a5a826a226fb57b7" CI_USER=$CIRCLE_PROJECT_USERNAME CI_REPO=$CIRCLE_PROJECT_REPONAME PULL_REQUEST_NUMBER=$CIRCLE_PR_NUMBER node bots/code-analysis-bot.js
|
||||
- npm run lint
|
||||
# JS tests for dependencies installed with npm3
|
||||
- npm run flow -- check
|
||||
# Commenting out Flow tests
|
||||
# - npm run flow -- check
|
||||
- npm test -- --maxWorkers=1
|
||||
|
||||
# build app
|
||||
@@ -76,8 +77,11 @@ test:
|
||||
# integration tests
|
||||
# build JS bundle for instrumentation tests
|
||||
- node local-cli/cli.js bundle --max-workers 1 --platform android --dev true --entry-file ReactAndroid/src/androidTest/js/TestBundle.js --bundle-output ReactAndroid/src/androidTest/assets/AndroidTestBundle.js
|
||||
|
||||
# build test APK
|
||||
- buck install ReactAndroid/src/androidTest/buck-runner:instrumentation-tests --config build.threads=1
|
||||
# Commented out due to test failures. Please uncomment the next line once these have been fixed. See Issue #15726.
|
||||
# - buck install ReactAndroid/src/androidTest/buck-runner:instrumentation-tests --config build.threads=1
|
||||
|
||||
# run installed apk with tests
|
||||
# - node ./scripts/run-android-ci-instrumentation-tests.js --retries 3 --path ./ReactAndroid/src/androidTest/java/com/facebook/react/tests --package com.facebook.react.tests
|
||||
|
||||
|
||||
@@ -157,9 +157,11 @@ Go to the root directory for your project and create a new `package.json` file w
|
||||
Next, you will install the `react` and `react-native` packages. Open a terminal or command prompt, then navigate to the root directory for your project and type the following commands:
|
||||
|
||||
```
|
||||
$ npm install --save react react-native
|
||||
$ npm install --save react@16.0.0-beta.5 react-native
|
||||
```
|
||||
|
||||
> Make sure you use the same React version as specified in the [React Native `package.json` file](https://github.com/facebook/react-native/blob/0.49-stable/package.json). This will only be necessary as long as React Native depends on a pre-release version of React.
|
||||
|
||||
This will create a new `/node_modules` folder in your project's root directory. This folder stores all the JavaScript dependencies required to build your project.
|
||||
|
||||
<block class="objc swift" />
|
||||
|
||||
+10
-1
@@ -34,7 +34,7 @@ jest
|
||||
jest.setMock('ErrorUtils', require('ErrorUtils'));
|
||||
|
||||
jest
|
||||
.mock('InitializeCore')
|
||||
.mock('InitializeCore', () => {})
|
||||
.mock('Image', () => mockComponent('Image'))
|
||||
.mock('Text', () => mockComponent('Text'))
|
||||
.mock('TextInput', () => mockComponent('TextInput'))
|
||||
@@ -275,6 +275,15 @@ const mockNativeModules = {
|
||||
Constants: {},
|
||||
},
|
||||
},
|
||||
BlobModule: {
|
||||
BLOB_URI_SCHEME: 'content',
|
||||
BLOB_URI_HOST: null,
|
||||
enableBlobSupport: jest.fn(),
|
||||
disableBlobSupport: jest.fn(),
|
||||
createFromParts: jest.fn(),
|
||||
sendBlob: jest.fn(),
|
||||
release: jest.fn(),
|
||||
},
|
||||
WebSocketModule: {
|
||||
connect: jest.fn(),
|
||||
send: jest.fn(),
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
'use strict';
|
||||
|
||||
const blacklist = require('metro-bundler/src/blacklist');
|
||||
const findSymlinksPaths = require('./findSymlinksPaths');
|
||||
const findSymlinkedModules = require('./findSymlinkedModules');
|
||||
const fs = require('fs');
|
||||
const getPolyfills = require('../../rn-get-polyfills');
|
||||
const invariant = require('fbjs/lib/invariant');
|
||||
@@ -150,14 +150,15 @@ function getProjectPath() {
|
||||
return path.resolve(__dirname, '../..');
|
||||
}
|
||||
|
||||
const resolveSymlink = (roots) =>
|
||||
roots.concat(
|
||||
findSymlinksPaths(
|
||||
path.join(getProjectPath(), 'node_modules'),
|
||||
roots
|
||||
)
|
||||
const resolveSymlinksForRoots = roots =>
|
||||
roots.reduce(
|
||||
(arr, rootPath) => arr.concat(
|
||||
findSymlinkedModules(rootPath, roots)
|
||||
),
|
||||
[...roots]
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
* Module capable of getting the configuration out of a given file.
|
||||
*
|
||||
@@ -177,9 +178,9 @@ const Config = {
|
||||
getProjectRoots: () => {
|
||||
const root = process.env.REACT_NATIVE_APP_ROOT;
|
||||
if (root) {
|
||||
return resolveSymlink([path.resolve(root)]);
|
||||
return resolveSymlinksForRoots([path.resolve(root)]);
|
||||
}
|
||||
return resolveSymlink([getProjectPath()]);
|
||||
return resolveSymlinksForRoots([getProjectPath()]);
|
||||
},
|
||||
getProvidesModuleNodeModules: () => providesModuleNodeModules.slice(),
|
||||
getSourceExts: () => [],
|
||||
|
||||
@@ -0,0 +1,368 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const {EventEmitter} = require('events');
|
||||
const {dirname} = require.requireActual('path');
|
||||
const fs = jest.genMockFromModule('fs');
|
||||
const path = require('path');
|
||||
const stream = require.requireActual('stream');
|
||||
|
||||
const noop = () => {};
|
||||
|
||||
function asyncCallback(cb) {
|
||||
return function() {
|
||||
setImmediate(() => cb.apply(this, arguments));
|
||||
};
|
||||
}
|
||||
|
||||
const mtime = {
|
||||
getTime: () => Math.ceil(Math.random() * 10000000),
|
||||
};
|
||||
|
||||
fs.realpath.mockImplementation((filepath, callback) => {
|
||||
callback = asyncCallback(callback);
|
||||
let node;
|
||||
try {
|
||||
node = getToNode(filepath);
|
||||
} catch (e) {
|
||||
return callback(e);
|
||||
}
|
||||
if (node && typeof node === 'object' && node.SYMLINK != null) {
|
||||
return callback(null, node.SYMLINK);
|
||||
}
|
||||
return callback(null, filepath);
|
||||
});
|
||||
|
||||
fs.readdirSync.mockImplementation(filepath => Object.keys(getToNode(filepath)));
|
||||
|
||||
fs.readdir.mockImplementation((filepath, callback) => {
|
||||
callback = asyncCallback(callback);
|
||||
let node;
|
||||
try {
|
||||
node = getToNode(filepath);
|
||||
if (node && typeof node === 'object' && node.SYMLINK != null) {
|
||||
node = getToNode(node.SYMLINK);
|
||||
}
|
||||
} catch (e) {
|
||||
return callback(e);
|
||||
}
|
||||
|
||||
if (!(node && typeof node === 'object' && node.SYMLINK == null)) {
|
||||
return callback(new Error(filepath + ' is not a directory.'));
|
||||
}
|
||||
|
||||
return callback(null, Object.keys(node));
|
||||
});
|
||||
|
||||
fs.readFile.mockImplementation(function(filepath, encoding, callback) {
|
||||
callback = asyncCallback(callback);
|
||||
if (arguments.length === 2) {
|
||||
callback = encoding;
|
||||
encoding = null;
|
||||
}
|
||||
|
||||
let node;
|
||||
try {
|
||||
node = getToNode(filepath);
|
||||
// dir check
|
||||
if (node && typeof node === 'object' && node.SYMLINK == null) {
|
||||
callback(new Error('Error readFile a dir: ' + filepath));
|
||||
}
|
||||
if (node == null) {
|
||||
return callback(Error('No such file: ' + filepath));
|
||||
} else {
|
||||
return callback(null, node);
|
||||
}
|
||||
} catch (e) {
|
||||
return callback(e);
|
||||
}
|
||||
});
|
||||
|
||||
fs.readFileSync.mockImplementation(function(filepath, encoding) {
|
||||
const node = getToNode(filepath);
|
||||
// dir check
|
||||
if (node && typeof node === 'object' && node.SYMLINK == null) {
|
||||
throw new Error('Error readFileSync a dir: ' + filepath);
|
||||
}
|
||||
return node;
|
||||
});
|
||||
|
||||
function readlinkSync(filepath) {
|
||||
const node = getToNode(filepath);
|
||||
if (node !== null && typeof node === 'object' && !!node.SYMLINK) {
|
||||
return node.SYMLINK;
|
||||
} else {
|
||||
throw new Error(`EINVAL: invalid argument, readlink '${filepath}'`);
|
||||
}
|
||||
}
|
||||
|
||||
fs.readlink.mockImplementation((filepath, callback) => {
|
||||
callback = asyncCallback(callback);
|
||||
let result;
|
||||
try {
|
||||
result = readlinkSync(filepath);
|
||||
} catch (e) {
|
||||
callback(e);
|
||||
return;
|
||||
}
|
||||
callback(null, result);
|
||||
});
|
||||
|
||||
fs.readlinkSync.mockImplementation(readlinkSync);
|
||||
|
||||
function existsSync(filepath) {
|
||||
try {
|
||||
const node = getToNode(filepath);
|
||||
return node !== null;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
fs.exists.mockImplementation((filepath, callback) => {
|
||||
callback = asyncCallback(callback);
|
||||
let result;
|
||||
try {
|
||||
result = existsSync(filepath);
|
||||
} catch (e) {
|
||||
callback(e);
|
||||
return;
|
||||
}
|
||||
callback(null, result);
|
||||
});
|
||||
|
||||
fs.existsSync.mockImplementation(existsSync);
|
||||
|
||||
function makeStatResult(node) {
|
||||
const isSymlink = node != null && node.SYMLINK != null;
|
||||
return {
|
||||
isBlockDevice: () => false,
|
||||
isCharacterDevice: () => false,
|
||||
isDirectory: () => node != null && typeof node === 'object' && !isSymlink,
|
||||
isFIFO: () => false,
|
||||
isFile: () => node != null && typeof node === 'string',
|
||||
isSocket: () => false,
|
||||
isSymbolicLink: () => isSymlink,
|
||||
mtime,
|
||||
};
|
||||
}
|
||||
|
||||
function statSync(filepath) {
|
||||
const node = getToNode(filepath);
|
||||
if (node != null && node.SYMLINK) {
|
||||
return statSync(node.SYMLINK);
|
||||
}
|
||||
return makeStatResult(node);
|
||||
}
|
||||
|
||||
fs.stat.mockImplementation((filepath, callback) => {
|
||||
callback = asyncCallback(callback);
|
||||
let result;
|
||||
try {
|
||||
result = statSync(filepath);
|
||||
} catch (e) {
|
||||
callback(e);
|
||||
return;
|
||||
}
|
||||
callback(null, result);
|
||||
});
|
||||
|
||||
fs.statSync.mockImplementation(statSync);
|
||||
|
||||
function lstatSync(filepath) {
|
||||
const node = getToNode(filepath);
|
||||
return makeStatResult(node);
|
||||
}
|
||||
|
||||
fs.lstat.mockImplementation((filepath, callback) => {
|
||||
callback = asyncCallback(callback);
|
||||
let result;
|
||||
try {
|
||||
result = lstatSync(filepath);
|
||||
} catch (e) {
|
||||
callback(e);
|
||||
return;
|
||||
}
|
||||
callback(null, result);
|
||||
});
|
||||
|
||||
fs.lstatSync.mockImplementation(lstatSync);
|
||||
|
||||
fs.open.mockImplementation(function(filepath) {
|
||||
const callback = arguments[arguments.length - 1] || noop;
|
||||
let data, error, fd;
|
||||
try {
|
||||
data = getToNode(filepath);
|
||||
} catch (e) {
|
||||
error = e;
|
||||
}
|
||||
|
||||
if (error || data == null) {
|
||||
error = Error(`ENOENT: no such file or directory, open ${filepath}`);
|
||||
}
|
||||
if (data != null) {
|
||||
/* global Buffer: true */
|
||||
fd = {buffer: new Buffer(data, 'utf8'), position: 0};
|
||||
}
|
||||
|
||||
callback(error, fd);
|
||||
});
|
||||
|
||||
fs.read.mockImplementation(
|
||||
(fd, buffer, writeOffset, length, position, callback = noop) => {
|
||||
let bytesWritten;
|
||||
try {
|
||||
if (position == null || position < 0) {
|
||||
({position} = fd);
|
||||
}
|
||||
bytesWritten = fd.buffer.copy(
|
||||
buffer,
|
||||
writeOffset,
|
||||
position,
|
||||
position + length,
|
||||
);
|
||||
fd.position = position + bytesWritten;
|
||||
} catch (e) {
|
||||
callback(Error('invalid argument'));
|
||||
return;
|
||||
}
|
||||
callback(null, bytesWritten, buffer);
|
||||
},
|
||||
);
|
||||
|
||||
fs.close.mockImplementation((fd, callback = noop) => {
|
||||
try {
|
||||
fd.buffer = fs.position = undefined;
|
||||
} catch (e) {
|
||||
callback(Error('invalid argument'));
|
||||
return;
|
||||
}
|
||||
callback(null);
|
||||
});
|
||||
|
||||
let filesystem;
|
||||
|
||||
fs.createReadStream.mockImplementation(filepath => {
|
||||
if (!filepath.startsWith('/')) {
|
||||
throw Error('Cannot open file ' + filepath);
|
||||
}
|
||||
|
||||
const parts = filepath.split('/').slice(1);
|
||||
let file = filesystem;
|
||||
|
||||
for (const part of parts) {
|
||||
file = file[part];
|
||||
if (!file) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof file !== 'string') {
|
||||
throw Error('Cannot open file ' + filepath);
|
||||
}
|
||||
|
||||
return new stream.Readable({
|
||||
read() {
|
||||
this.push(file, 'utf8');
|
||||
this.push(null);
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
fs.createWriteStream.mockImplementation(file => {
|
||||
let node;
|
||||
try {
|
||||
node = getToNode(dirname(file));
|
||||
} finally {
|
||||
if (typeof node === 'object') {
|
||||
const writeStream = new stream.Writable({
|
||||
write(chunk) {
|
||||
this.__chunks.push(chunk);
|
||||
},
|
||||
});
|
||||
writeStream.__file = file;
|
||||
writeStream.__chunks = [];
|
||||
writeStream.end = jest.fn(writeStream.end);
|
||||
fs.createWriteStream.mock.returned.push(writeStream);
|
||||
return writeStream;
|
||||
} else {
|
||||
throw new Error('Cannot open file ' + file);
|
||||
}
|
||||
}
|
||||
});
|
||||
fs.createWriteStream.mock.returned = [];
|
||||
|
||||
fs.__setMockFilesystem = object => (filesystem = object);
|
||||
|
||||
const watcherListByPath = new Map();
|
||||
|
||||
fs.watch.mockImplementation((filename, options, listener) => {
|
||||
if (options.recursive) {
|
||||
throw new Error('recursive watch not implemented');
|
||||
}
|
||||
let watcherList = watcherListByPath.get(filename);
|
||||
if (watcherList == null) {
|
||||
watcherList = [];
|
||||
watcherListByPath.set(filename, watcherList);
|
||||
}
|
||||
const fsWatcher = new EventEmitter();
|
||||
fsWatcher.on('change', listener);
|
||||
fsWatcher.close = () => {
|
||||
watcherList.splice(watcherList.indexOf(fsWatcher), 1);
|
||||
fsWatcher.close = () => {
|
||||
throw new Error('FSWatcher is already closed');
|
||||
};
|
||||
};
|
||||
watcherList.push(fsWatcher);
|
||||
});
|
||||
|
||||
fs.__triggerWatchEvent = (eventType, filename) => {
|
||||
const directWatchers = watcherListByPath.get(filename) || [];
|
||||
directWatchers.forEach(wtc => wtc.emit('change', eventType));
|
||||
const dirPath = path.dirname(filename);
|
||||
const dirWatchers = watcherListByPath.get(dirPath) || [];
|
||||
dirWatchers.forEach(wtc =>
|
||||
wtc.emit('change', eventType, path.relative(dirPath, filename)),
|
||||
);
|
||||
};
|
||||
|
||||
function getToNode(filepath) {
|
||||
// Ignore the drive for Windows paths.
|
||||
if (filepath.match(/^[a-zA-Z]:\\/)) {
|
||||
filepath = filepath.substring(2);
|
||||
}
|
||||
|
||||
if (filepath.endsWith(path.sep)) {
|
||||
filepath = filepath.slice(0, -1);
|
||||
}
|
||||
const parts = filepath.split(/[\/\\]/);
|
||||
if (parts[0] !== '') {
|
||||
throw new Error('Make sure all paths are absolute.');
|
||||
}
|
||||
let node = filesystem;
|
||||
parts.slice(1).forEach(part => {
|
||||
if (node && node.SYMLINK) {
|
||||
node = getToNode(node.SYMLINK);
|
||||
}
|
||||
node = node[part];
|
||||
if (node == null) {
|
||||
const err = new Error('ENOENT: no such file or directory');
|
||||
err.code = 'ENOENT';
|
||||
throw err;
|
||||
}
|
||||
});
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
module.exports = fs;
|
||||
@@ -0,0 +1,354 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @format
|
||||
* @emails oncall+javascript_foundation
|
||||
*/
|
||||
|
||||
jest.mock('fs');
|
||||
|
||||
const fs = require('fs');
|
||||
const findSymlinkedModules = require('../findSymlinkedModules');
|
||||
|
||||
describe('findSymlinksForProjectRoot', () => {
|
||||
it('correctly finds normal module symlinks', () => {
|
||||
fs.__setMockFilesystem({
|
||||
root: {
|
||||
projectA: {
|
||||
'package.json': JSON.stringify({
|
||||
name: 'projectA',
|
||||
main: 'main.js',
|
||||
}),
|
||||
node_modules: {
|
||||
depFoo: {
|
||||
'package.json': JSON.stringify({
|
||||
name: 'depFoo',
|
||||
main: 'main.js',
|
||||
}),
|
||||
},
|
||||
projectB: {
|
||||
SYMLINK: '/root/projectB',
|
||||
},
|
||||
},
|
||||
},
|
||||
projectB: {
|
||||
'package.json': JSON.stringify({
|
||||
name: 'projectB',
|
||||
main: 'main.js',
|
||||
}),
|
||||
node_modules: {
|
||||
depBar: {
|
||||
'package.json': JSON.stringify({
|
||||
name: 'depBar',
|
||||
main: 'main.js',
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const symlinkedModules = findSymlinkedModules('/root/projectA', []);
|
||||
expect(symlinkedModules).toEqual(['/root/projectB']);
|
||||
});
|
||||
|
||||
it('correctly finds scoped module symlinks', () => {
|
||||
fs.__setMockFilesystem({
|
||||
root: {
|
||||
projectA: {
|
||||
'package.json': JSON.stringify({
|
||||
name: 'projectA',
|
||||
main: 'main.js',
|
||||
}),
|
||||
node_modules: {
|
||||
depFoo: {
|
||||
'package.json': JSON.stringify({
|
||||
name: 'depFoo',
|
||||
main: 'main.js',
|
||||
}),
|
||||
},
|
||||
'@scoped': {
|
||||
projectC: {
|
||||
SYMLINK: '/root/@scoped/projectC',
|
||||
},
|
||||
},
|
||||
projectB: {
|
||||
SYMLINK: '/root/projectB',
|
||||
},
|
||||
},
|
||||
},
|
||||
projectB: {
|
||||
'package.json': JSON.stringify({
|
||||
name: 'projectB',
|
||||
main: 'main.js',
|
||||
}),
|
||||
node_modules: {
|
||||
depBar: {
|
||||
'package.json': JSON.stringify({
|
||||
name: 'depBar',
|
||||
main: 'main.js',
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
'@scoped': {
|
||||
projectC: {
|
||||
'package.json': JSON.stringify({
|
||||
name: '@scoped/projectC',
|
||||
main: 'main.js',
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const symlinkedModules = findSymlinkedModules('/root/projectA', []);
|
||||
expect(symlinkedModules).toEqual([
|
||||
'/root/@scoped/projectC',
|
||||
'/root/projectB',
|
||||
]);
|
||||
});
|
||||
|
||||
it('correctly finds module symlinks within other module symlinks', () => {
|
||||
fs.__setMockFilesystem({
|
||||
root: {
|
||||
projectA: {
|
||||
'package.json': JSON.stringify({
|
||||
name: 'projectA',
|
||||
main: 'main.js',
|
||||
}),
|
||||
node_modules: {
|
||||
depFoo: {
|
||||
'package.json': JSON.stringify({
|
||||
name: 'depFoo',
|
||||
main: 'main.js',
|
||||
}),
|
||||
},
|
||||
'@scoped': {
|
||||
projectC: {
|
||||
SYMLINK: '/root/@scoped/projectC',
|
||||
},
|
||||
},
|
||||
projectB: {
|
||||
SYMLINK: '/root/projectB',
|
||||
},
|
||||
},
|
||||
},
|
||||
projectB: {
|
||||
'package.json': JSON.stringify({
|
||||
name: 'projectB',
|
||||
main: 'main.js',
|
||||
}),
|
||||
node_modules: {
|
||||
depBar: {
|
||||
'package.json': JSON.stringify({
|
||||
name: 'depBar',
|
||||
main: 'main.js',
|
||||
}),
|
||||
},
|
||||
projectD: {
|
||||
SYMLINK: '/root/projectD',
|
||||
},
|
||||
},
|
||||
},
|
||||
'@scoped': {
|
||||
projectC: {
|
||||
'package.json': JSON.stringify({
|
||||
name: '@scoped/projectC',
|
||||
main: 'main.js',
|
||||
}),
|
||||
},
|
||||
},
|
||||
projectD: {
|
||||
'package.json': JSON.stringify({
|
||||
name: 'projectD',
|
||||
main: 'main.js',
|
||||
}),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const symlinkedModules = findSymlinkedModules('/root/projectA', []);
|
||||
expect(symlinkedModules).toEqual([
|
||||
'/root/@scoped/projectC',
|
||||
'/root/projectB',
|
||||
'/root/projectD',
|
||||
]);
|
||||
});
|
||||
|
||||
it('correctly handles duplicate symlink paths', () => {
|
||||
// projectA ->
|
||||
// -> projectC
|
||||
// -> projectB -> projectC
|
||||
// Final list should only contain projectC once
|
||||
fs.__setMockFilesystem({
|
||||
root: {
|
||||
projectA: {
|
||||
'package.json': JSON.stringify({
|
||||
name: 'projectA',
|
||||
main: 'main.js',
|
||||
}),
|
||||
node_modules: {
|
||||
depFoo: {
|
||||
'package.json': JSON.stringify({
|
||||
name: 'depFoo',
|
||||
main: 'main.js',
|
||||
}),
|
||||
},
|
||||
'@scoped': {
|
||||
projectC: {
|
||||
SYMLINK: '/root/@scoped/projectC',
|
||||
},
|
||||
},
|
||||
projectB: {
|
||||
SYMLINK: '/root/projectB',
|
||||
},
|
||||
},
|
||||
},
|
||||
projectB: {
|
||||
'package.json': JSON.stringify({
|
||||
name: 'projectB',
|
||||
main: 'main.js',
|
||||
}),
|
||||
node_modules: {
|
||||
depBar: {
|
||||
'package.json': JSON.stringify({
|
||||
name: 'depBar',
|
||||
main: 'main.js',
|
||||
}),
|
||||
},
|
||||
'@scoped': {
|
||||
projectC: {
|
||||
SYMLINK: '/root/@scoped/projectC',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
'@scoped': {
|
||||
projectC: {
|
||||
'package.json': JSON.stringify({
|
||||
name: '@scoped/projectC',
|
||||
main: 'main.js',
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const symlinkedModules = findSymlinkedModules('/root/projectA', []);
|
||||
expect(symlinkedModules).toEqual([
|
||||
'/root/@scoped/projectC',
|
||||
'/root/projectB',
|
||||
]);
|
||||
});
|
||||
|
||||
it('correctly handles symlink recursion', () => {
|
||||
// projectA ->
|
||||
// -> projectC -> projectD -> projectA
|
||||
// -> projectB -> projectC -> projectA
|
||||
// -> projectD -> projectC -> projectA
|
||||
// Should not infinite loop, should not contain projectA
|
||||
fs.__setMockFilesystem({
|
||||
root: {
|
||||
projectA: {
|
||||
'package.json': JSON.stringify({
|
||||
name: 'projectA',
|
||||
main: 'main.js',
|
||||
}),
|
||||
node_modules: {
|
||||
depFoo: {
|
||||
'package.json': JSON.stringify({
|
||||
name: 'depFoo',
|
||||
main: 'main.js',
|
||||
}),
|
||||
},
|
||||
'@scoped': {
|
||||
projectC: {
|
||||
SYMLINK: '/root/@scoped/projectC',
|
||||
},
|
||||
},
|
||||
projectB: {
|
||||
SYMLINK: '/root/projectB',
|
||||
},
|
||||
},
|
||||
},
|
||||
projectB: {
|
||||
'package.json': JSON.stringify({
|
||||
name: 'projectB',
|
||||
main: 'main.js',
|
||||
}),
|
||||
node_modules: {
|
||||
depBar: {
|
||||
'package.json': JSON.stringify({
|
||||
name: 'depBar',
|
||||
main: 'main.js',
|
||||
}),
|
||||
},
|
||||
projectD: {
|
||||
SYMLINK: '/root/projectD',
|
||||
},
|
||||
'@scoped': {
|
||||
projectC: {
|
||||
SYMLINK: '/root/@scoped/projectC',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
'@scoped': {
|
||||
projectC: {
|
||||
'package.json': JSON.stringify({
|
||||
name: '@scoped/projectC',
|
||||
main: 'main.js',
|
||||
}),
|
||||
node_modules: {
|
||||
projectA: {
|
||||
SYMLINK: '/root/projectA',
|
||||
},
|
||||
projectD: {
|
||||
SYMLINK: '/root/projectD',
|
||||
},
|
||||
projectE: {
|
||||
SYMLINK: '/root/projectE',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
projectD: {
|
||||
'package.json': JSON.stringify({
|
||||
name: 'projectD',
|
||||
main: 'main.js',
|
||||
}),
|
||||
node_modules: {
|
||||
'@scoped': {
|
||||
projectC: {
|
||||
SYMLINK: '/root/@scoped/projectC',
|
||||
},
|
||||
},
|
||||
projectE: {
|
||||
SYMLINK: '/root/projectE',
|
||||
},
|
||||
},
|
||||
},
|
||||
projectE: {
|
||||
'package.json': JSON.stringify({
|
||||
name: 'projectD',
|
||||
main: 'main.js',
|
||||
}),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const symlinkedModules = findSymlinkedModules('/root/projectA');
|
||||
expect(symlinkedModules).toEqual([
|
||||
'/root/@scoped/projectC',
|
||||
'/root/projectB',
|
||||
'/root/projectD',
|
||||
'/root/projectE',
|
||||
]);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,110 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @format
|
||||
* @flow
|
||||
*/
|
||||
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
|
||||
/**
|
||||
* Find symlinked modules inside "node_modules."
|
||||
*
|
||||
* Naively, we could just perform a depth-first search of all folders in
|
||||
* node_modules, recursing when we find a symlink.
|
||||
*
|
||||
* We can be smarter than this due to our knowledge of how npm/Yarn lays out
|
||||
* "node_modules" / how tools that build on top of npm/Yarn (such as Lerna)
|
||||
* install dependencies.
|
||||
*
|
||||
* Starting from a given root node_modules folder, this algorithm will look at
|
||||
* both the top level descendants of the node_modules folder or second level
|
||||
* descendants of folders that start with "@" (which indicates a scoped
|
||||
* package). If any of those folders is a symlink, it will recurse into the
|
||||
* link, and perform the same search in the linked folder.
|
||||
*
|
||||
* The end result should be a list of all resolved module symlinks for a given
|
||||
* root.
|
||||
*/
|
||||
module.exports = function findSymlinkedModules(
|
||||
projectRoot: string,
|
||||
ignoredRoots?: Array<string> = [],
|
||||
) {
|
||||
const timeStart = Date.now();
|
||||
const nodeModuleRoot = path.join(projectRoot, 'node_modules');
|
||||
const resolvedSymlinks = findModuleSymlinks(nodeModuleRoot, [
|
||||
...ignoredRoots,
|
||||
projectRoot,
|
||||
]);
|
||||
const timeEnd = Date.now();
|
||||
|
||||
console.log(
|
||||
`Scanning folders for symlinks in ${nodeModuleRoot} (${timeEnd -
|
||||
timeStart}ms)`,
|
||||
);
|
||||
|
||||
return resolvedSymlinks;
|
||||
};
|
||||
|
||||
function findModuleSymlinks(
|
||||
modulesPath: string,
|
||||
ignoredPaths: Array<string> = [],
|
||||
): Array<string> {
|
||||
if (!fs.existsSync(modulesPath)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// Find module symlinks
|
||||
const moduleFolders = fs.readdirSync(modulesPath);
|
||||
const symlinks = moduleFolders.reduce((links, folderName) => {
|
||||
const folderPath = path.join(modulesPath, folderName);
|
||||
const maybeSymlinkPaths = [];
|
||||
if (folderName.startsWith('@')) {
|
||||
const scopedModuleFolders = fs.readdirSync(folderPath);
|
||||
maybeSymlinkPaths.push(
|
||||
...scopedModuleFolders.map(name => path.join(folderPath, name)),
|
||||
);
|
||||
} else {
|
||||
maybeSymlinkPaths.push(folderPath);
|
||||
}
|
||||
return links.concat(resolveSymlinkPaths(maybeSymlinkPaths, ignoredPaths));
|
||||
}, []);
|
||||
|
||||
// For any symlinks found, look in _that_ modules node_modules directory
|
||||
// and find any symlinked modules
|
||||
const nestedSymlinks = symlinks.reduce(
|
||||
(links, symlinkPath) =>
|
||||
links.concat(
|
||||
// We ignore any found symlinks or anything from the ignored list,
|
||||
// to prevent infinite recursion
|
||||
findModuleSymlinks(path.join(symlinkPath, 'node_modules'), [
|
||||
...ignoredPaths,
|
||||
...symlinks,
|
||||
]),
|
||||
),
|
||||
[],
|
||||
);
|
||||
|
||||
return [...new Set([...symlinks, ...nestedSymlinks])];
|
||||
}
|
||||
|
||||
function resolveSymlinkPaths(maybeSymlinkPaths, ignoredPaths) {
|
||||
return maybeSymlinkPaths.reduce((links, maybeSymlinkPath) => {
|
||||
if (fs.lstatSync(maybeSymlinkPath).isSymbolicLink()) {
|
||||
const resolved = path.resolve(
|
||||
path.dirname(maybeSymlinkPath),
|
||||
fs.readlinkSync(maybeSymlinkPath),
|
||||
);
|
||||
if (ignoredPaths.indexOf(resolved) === -1 && fs.existsSync(resolved)) {
|
||||
links.push(resolved);
|
||||
}
|
||||
}
|
||||
return links;
|
||||
}, []);
|
||||
}
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "react-native",
|
||||
"version": "1000.0.0",
|
||||
"version": "0.49.0-rc.6",
|
||||
"description": "A framework for building native apps using React",
|
||||
"license": "BSD-3-Clause",
|
||||
"repository": {
|
||||
@@ -205,4 +205,4 @@
|
||||
"shelljs": "0.6.0",
|
||||
"sinon": "^2.2.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -46,10 +46,39 @@ let versionMajor = branch.slice(0, branch.indexOf(`-stable`));
|
||||
// e.g. 0.33.1 or 0.33.0-rc4
|
||||
let version = argv._[0];
|
||||
if (!version || version.indexOf(versionMajor) !== 0) {
|
||||
echo(`You must pass a tag like ${versionMajor}.[X]-rc[Y] to bump a version`);
|
||||
echo(`You must pass a tag like 0.${versionMajor}.[X]-rc[Y] to bump a version`);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Generate version files to detect mismatches between JS and native.
|
||||
let match = version.match(/^(\d+)\.(\d+)\.(\d+)(?:-(.+))?$/);
|
||||
if (!match) {
|
||||
echo(`You must pass a correctly formatted version; couldn't parse ${version}`);
|
||||
exit(1);
|
||||
}
|
||||
let [, major, minor, patch, prerelease] = match;
|
||||
|
||||
cat('scripts/versiontemplates/ReactNativeVersion.java.template')
|
||||
.replace('${major}', major)
|
||||
.replace('${minor}', minor)
|
||||
.replace('${patch}', patch)
|
||||
.replace('${prerelease}', prerelease !== undefined ? `"${prerelease}"` : 'null')
|
||||
.to('ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/ReactNativeVersion.java');
|
||||
|
||||
cat('scripts/versiontemplates/RCTVersion.h.template')
|
||||
.replace('${major}', `@(${major})`)
|
||||
.replace('${minor}', `@(${minor})`)
|
||||
.replace('${patch}', `@(${patch})`)
|
||||
.replace('${prerelease}', prerelease !== undefined ? `@"${prerelease}"` : '[NSNull null]')
|
||||
.to('React/Base/RCTVersion.h');
|
||||
|
||||
cat('scripts/versiontemplates/ReactNativeVersion.js.template')
|
||||
.replace('${major}', major)
|
||||
.replace('${minor}', minor)
|
||||
.replace('${patch}', patch)
|
||||
.replace('${prerelease}', prerelease !== undefined ? `'${prerelease}'` : 'null')
|
||||
.to('Libraries/Core/ReactNativeVersion.js');
|
||||
|
||||
let packageJson = JSON.parse(cat(`package.json`));
|
||||
packageJson.version = version;
|
||||
JSON.stringify(packageJson, null, 2).to(`package.json`);
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* @generated by scripts/bump-oss-version.js
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#define REACT_NATIVE_VERSION @{ \
|
||||
@"major": ${major}, \
|
||||
@"minor": ${minor}, \
|
||||
@"patch": ${patch}, \
|
||||
@"prerelease": ${prerelease}, \
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* @generated by scripts/bump-oss-version.js
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.facebook.react.modules.systeminfo;
|
||||
|
||||
import com.facebook.react.common.MapBuilder;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class ReactNativeVersion {
|
||||
public static final Map<String, Object> VERSION = MapBuilder.<String, Object>of(
|
||||
"major", ${major},
|
||||
"minor", ${minor},
|
||||
"patch", ${patch},
|
||||
"prerelease", ${prerelease});
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* @generated by scripts/bump-oss-version.js
|
||||
*
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @flow
|
||||
* @providesModule ReactNativeVersion
|
||||
*/
|
||||
|
||||
exports.version = {
|
||||
major: ${major},
|
||||
minor: ${minor},
|
||||
patch: ${patch},
|
||||
prerelease: ${prerelease},
|
||||
};
|
||||
Reference in New Issue
Block a user