react-native 0.85.2 → 0.85.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Libraries/Core/ReactNativeVersion.js +1 -1
- package/Libraries/Utilities/HMRClient.js +28 -1
- package/React/Base/RCTVersion.m +1 -1
- package/React/CoreModules/RCTJscSafeUrl+Internal.h +23 -0
- package/React/CoreModules/RCTJscSafeUrl.mm +38 -0
- package/React/CoreModules/RCTRedBox+Internal.h +42 -0
- package/React/CoreModules/RCTRedBox.mm +30 -454
- package/React/CoreModules/RCTRedBox2AnsiParser+Internal.h +22 -0
- package/React/CoreModules/RCTRedBox2AnsiParser.mm +55 -0
- package/React/CoreModules/RCTRedBox2Controller+Internal.h +34 -0
- package/React/CoreModules/RCTRedBox2Controller.mm +764 -0
- package/React/CoreModules/RCTRedBox2ErrorParser+Internal.h +46 -0
- package/React/CoreModules/RCTRedBox2ErrorParser.mm +57 -0
- package/React/CoreModules/RCTRedBoxController+Internal.h +31 -0
- package/React/CoreModules/RCTRedBoxController.mm +447 -0
- package/React/CoreModules/RCTRedBoxHMRClient+Internal.h +26 -0
- package/React/CoreModules/RCTRedBoxHMRClient.mm +125 -0
- package/React/CoreModules/React-CoreModules.podspec +1 -0
- package/React/DevSupport/RCTFrameTimingsObserver.h +24 -0
- package/React/DevSupport/RCTFrameTimingsObserver.mm +298 -0
- package/React/FBReactNativeSpec/FBReactNativeSpecJSI.h +40 -0
- package/ReactAndroid/gradle.properties +1 -1
- package/ReactAndroid/src/main/java/com/facebook/react/devsupport/InspectorFlags.kt +4 -0
- package/ReactAndroid/src/main/java/com/facebook/react/devsupport/inspector/FrameTimingSequence.kt +1 -1
- package/ReactAndroid/src/main/java/com/facebook/react/devsupport/inspector/FrameTimingsObserver.kt +127 -26
- package/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlags.kt +31 -1
- package/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxAccessor.kt +51 -1
- package/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxInterop.kt +11 -1
- package/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.kt +11 -1
- package/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsLocalAccessor.kt +56 -1
- package/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsProvider.kt +11 -1
- package/ReactAndroid/src/main/java/com/facebook/react/internal/tracing/PerformanceTracer.kt +39 -0
- package/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/ReactNativeVersion.kt +1 -1
- package/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactHostImpl.kt +50 -10
- package/ReactAndroid/src/main/jni/CMakeLists.txt +7 -0
- package/ReactAndroid/src/main/jni/react/devsupport/JInspectorFlags.cpp +22 -0
- package/ReactAndroid/src/main/jni/react/devsupport/JInspectorFlags.h +2 -0
- package/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.cpp +71 -1
- package/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.h +16 -1
- package/ReactAndroid/src/main/jni/react/runtime/jni/JReactHostInspectorTarget.cpp +14 -0
- package/ReactAndroid/src/main/jni/react/runtime/jni/JReactHostInspectorTarget.h +18 -4
- package/ReactCommon/React-Fabric.podspec +6 -0
- package/ReactCommon/cxxreact/ReactNativeVersion.h +2 -2
- package/ReactCommon/jsinspector-modern/HostAgent.cpp +36 -0
- package/ReactCommon/jsinspector-modern/HostTarget.cpp +7 -1
- package/ReactCommon/jsinspector-modern/HostTarget.h +25 -0
- package/ReactCommon/jsinspector-modern/HostTargetTracing.cpp +1 -1
- package/ReactCommon/jsinspector-modern/HostTargetTracing.h +4 -4
- package/ReactCommon/jsinspector-modern/InspectorFlags.cpp +12 -0
- package/ReactCommon/jsinspector-modern/InspectorFlags.h +12 -0
- package/ReactCommon/jsinspector-modern/NetworkIOAgent.cpp +1 -1
- package/ReactCommon/jsinspector-modern/RuntimeAgent.cpp +19 -0
- package/ReactCommon/jsinspector-modern/RuntimeAgent.h +7 -0
- package/ReactCommon/jsinspector-modern/RuntimeTarget.cpp +33 -0
- package/ReactCommon/jsinspector-modern/RuntimeTarget.h +6 -0
- package/ReactCommon/jsinspector-modern/tests/HostTargetTest.cpp +12 -0
- package/ReactCommon/jsinspector-modern/tests/InspectorMocks.h +3 -2
- package/ReactCommon/jsinspector-modern/tests/JsiIntegrationTest.cpp +1 -0
- package/ReactCommon/jsinspector-modern/tests/NetworkReporterTest.cpp +1 -1
- package/ReactCommon/jsinspector-modern/tests/TracingTest.cpp +1 -1
- package/ReactCommon/jsinspector-modern/tests/utils/InspectorFlagOverridesGuard.cpp +10 -0
- package/ReactCommon/jsinspector-modern/tests/utils/InspectorFlagOverridesGuard.h +3 -1
- package/ReactCommon/jsinspector-modern/tracing/CMakeLists.txt +1 -0
- package/ReactCommon/jsinspector-modern/tracing/FrameTimingSequence.h +7 -3
- package/ReactCommon/jsinspector-modern/tracing/HostTracingProfileSerializer.cpp +52 -29
- package/ReactCommon/jsinspector-modern/tracing/HostTracingProfileSerializer.h +6 -6
- package/ReactCommon/jsinspector-modern/tracing/PerformanceTracerSection.h +113 -0
- package/ReactCommon/jsinspector-modern/tracing/React-jsinspectortracing.podspec +1 -0
- package/ReactCommon/jsinspector-modern/tracing/TraceEventGenerator.cpp +12 -5
- package/ReactCommon/jsinspector-modern/tracing/TraceEventGenerator.h +3 -1
- package/ReactCommon/jsinspector-modern/tracing/TraceEventSerializer.cpp +42 -0
- package/ReactCommon/jsinspector-modern/tracing/TraceEventSerializer.h +7 -0
- package/ReactCommon/react/debug/CMakeLists.txt +2 -1
- package/ReactCommon/react/debug/React-debug.podspec +7 -1
- package/ReactCommon/react/debug/redbox/AnsiParser.cpp +139 -0
- package/ReactCommon/react/debug/redbox/AnsiParser.h +35 -0
- package/ReactCommon/react/debug/redbox/JscSafeUrl.cpp +179 -0
- package/ReactCommon/react/debug/redbox/JscSafeUrl.h +27 -0
- package/ReactCommon/react/debug/redbox/RedBoxErrorParser.cpp +171 -0
- package/ReactCommon/react/debug/redbox/RedBoxErrorParser.h +40 -0
- package/ReactCommon/react/debug/redbox/tests/AnsiParserTest.cpp +97 -0
- package/ReactCommon/react/debug/redbox/tests/JscSafeUrlTest.cpp +173 -0
- package/ReactCommon/react/debug/redbox/tests/RedBoxErrorParserTest.cpp +107 -0
- package/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp +21 -1
- package/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h +26 -1
- package/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp +135 -45
- package/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h +12 -2
- package/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h +21 -1
- package/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDynamicProvider.h +46 -1
- package/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h +6 -1
- package/ReactCommon/react/nativemodule/defaults/CMakeLists.txt +1 -0
- package/ReactCommon/react/nativemodule/defaults/DefaultTurboModules.cpp +7 -0
- package/ReactCommon/react/nativemodule/defaults/React-defaultsnativemodule.podspec +1 -0
- package/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp +26 -1
- package/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h +11 -1
- package/ReactCommon/react/nativemodule/mutationobserver/NativeMutationObserver.h +4 -0
- package/ReactCommon/react/nativemodule/mutationobserver/React-mutationobservernativemodule.podspec +66 -0
- package/ReactCommon/react/performance/timeline/PerformanceObserver.cpp +18 -6
- package/ReactCommon/react/performance/timeline/PerformanceObserver.h +2 -0
- package/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTHost.mm +115 -0
- package/ReactCommon/{jsinspector-modern → react/utils}/Base64.h +2 -2
- package/package.json +11 -11
- package/scripts/cocoapods/utils.rb +1 -0
- package/scripts/react_native_pods.rb +1 -0
- package/scripts/replace-rncore-version.js +72 -15
- package/src/private/featureflags/ReactNativeFeatureFlags.js +26 -1
- package/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js +6 -1
- package/src/private/setup/setUpDefaultReactNativeEnvironment.js +6 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
#import <Foundation/Foundation.h>
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Structured error data extracted from a raw error message.
|
|
12
|
+
* Mirrors LogBoxLog.js / parseLogBoxLog.js data model.
|
|
13
|
+
*/
|
|
14
|
+
@interface RCTRedBox2ErrorData : NSObject
|
|
15
|
+
|
|
16
|
+
/// Display title, e.g. "Syntax Error", "Render Error", "Uncaught Error"
|
|
17
|
+
@property (nonatomic, copy) NSString *title;
|
|
18
|
+
/// The error message body (code frame stripped out)
|
|
19
|
+
@property (nonatomic, copy) NSString *message;
|
|
20
|
+
/// Raw code frame text with ANSI escape codes preserved (nil if not a syntax/transform error)
|
|
21
|
+
@property (nonatomic, copy, nullable) NSString *codeFrame;
|
|
22
|
+
/// Source file path for the code frame
|
|
23
|
+
@property (nonatomic, copy, nullable) NSString *codeFrameFileName;
|
|
24
|
+
/// Line number in the source file
|
|
25
|
+
@property (nonatomic, assign) NSInteger codeFrameRow;
|
|
26
|
+
/// Column number in the source file
|
|
27
|
+
@property (nonatomic, assign) NSInteger codeFrameColumn;
|
|
28
|
+
/// Whether this is a compile-time error (syntax, transform, resolution) vs a runtime error
|
|
29
|
+
@property (nonatomic, assign) BOOL isCompileError;
|
|
30
|
+
/// Whether auto-retry is appropriate (compile errors, connectivity failures, etc.)
|
|
31
|
+
@property (nonatomic, assign) BOOL isRetryable;
|
|
32
|
+
|
|
33
|
+
@end
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Parses raw error messages into structured RCTRedBox2ErrorData.
|
|
37
|
+
* ObjC port of parseLogBoxLog.js / parseLogBoxException.
|
|
38
|
+
*/
|
|
39
|
+
@interface RCTRedBox2ErrorParser : NSObject
|
|
40
|
+
|
|
41
|
+
+ (RCTRedBox2ErrorData *)parseErrorMessage:(NSString *)message
|
|
42
|
+
name:(nullable NSString *)name
|
|
43
|
+
componentStack:(nullable NSString *)componentStack
|
|
44
|
+
isFatal:(BOOL)isFatal;
|
|
45
|
+
|
|
46
|
+
@end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
#import "RCTRedBox2ErrorParser+Internal.h"
|
|
9
|
+
|
|
10
|
+
#import <React/RCTDefines.h>
|
|
11
|
+
#import <react/debug/redbox/RedBoxErrorParser.h>
|
|
12
|
+
|
|
13
|
+
#if RCT_DEV_MENU
|
|
14
|
+
|
|
15
|
+
using facebook::react::unstable_redbox::ParsedError;
|
|
16
|
+
using facebook::react::unstable_redbox::parseErrorMessage;
|
|
17
|
+
|
|
18
|
+
static RCTRedBox2ErrorData *RCTRedBox2ErrorDataFromParsedError(const ParsedError &parsed)
|
|
19
|
+
{
|
|
20
|
+
RCTRedBox2ErrorData *data = [[RCTRedBox2ErrorData alloc] init];
|
|
21
|
+
data.title = [NSString stringWithUTF8String:parsed.title.c_str()];
|
|
22
|
+
data.message = [NSString stringWithUTF8String:parsed.message.c_str()];
|
|
23
|
+
data.isCompileError = parsed.isCompileError;
|
|
24
|
+
data.isRetryable = parsed.isRetryable;
|
|
25
|
+
|
|
26
|
+
if (parsed.codeFrame.has_value()) {
|
|
27
|
+
const auto &cf = *parsed.codeFrame;
|
|
28
|
+
data.codeFrame = [NSString stringWithUTF8String:cf.content.c_str()];
|
|
29
|
+
data.codeFrameFileName = [NSString stringWithUTF8String:cf.fileName.c_str()];
|
|
30
|
+
data.codeFrameRow = cf.row;
|
|
31
|
+
data.codeFrameColumn = cf.column;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return data;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
@implementation RCTRedBox2ErrorData
|
|
38
|
+
@end
|
|
39
|
+
|
|
40
|
+
@implementation RCTRedBox2ErrorParser
|
|
41
|
+
|
|
42
|
+
+ (RCTRedBox2ErrorData *)parseErrorMessage:(NSString *)message
|
|
43
|
+
name:(nullable NSString *)name
|
|
44
|
+
componentStack:(nullable NSString *)componentStack
|
|
45
|
+
isFatal:(BOOL)isFatal
|
|
46
|
+
{
|
|
47
|
+
auto parsed = parseErrorMessage(
|
|
48
|
+
(message != nullptr) ? std::string(message.UTF8String) : std::string(),
|
|
49
|
+
(name != nullptr) ? std::string(name.UTF8String) : std::string(),
|
|
50
|
+
(componentStack != nullptr) ? std::string(componentStack.UTF8String) : std::string(),
|
|
51
|
+
isFatal);
|
|
52
|
+
return RCTRedBox2ErrorDataFromParsedError(parsed);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
@end
|
|
56
|
+
|
|
57
|
+
#endif
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
#import <React/RCTDefines.h>
|
|
9
|
+
|
|
10
|
+
#import "RCTRedBox+Internal.h"
|
|
11
|
+
#import "RCTRedBox.h"
|
|
12
|
+
|
|
13
|
+
#if RCT_DEV_MENU
|
|
14
|
+
|
|
15
|
+
@interface RCTRedBoxController : UIViewController <RCTRedBoxControlling, UITableViewDelegate, UITableViewDataSource>
|
|
16
|
+
|
|
17
|
+
@property (nonatomic, weak) id<RCTRedBoxControllerActionDelegate> actionDelegate;
|
|
18
|
+
|
|
19
|
+
- (instancetype)initWithCustomButtonTitles:(NSArray<NSString *> *)customButtonTitles
|
|
20
|
+
customButtonHandlers:(NSArray<RCTRedBoxButtonPressHandler> *)customButtonHandlers;
|
|
21
|
+
|
|
22
|
+
- (void)showErrorMessage:(NSString *)message
|
|
23
|
+
withStack:(NSArray<RCTJSStackFrame *> *)stack
|
|
24
|
+
isUpdate:(BOOL)isUpdate
|
|
25
|
+
errorCookie:(int)errorCookie;
|
|
26
|
+
|
|
27
|
+
- (void)dismiss;
|
|
28
|
+
|
|
29
|
+
@end
|
|
30
|
+
|
|
31
|
+
#endif
|
|
@@ -0,0 +1,447 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
#import "RCTRedBoxController+Internal.h"
|
|
9
|
+
|
|
10
|
+
#import <React/RCTDefines.h>
|
|
11
|
+
#import <React/RCTJSStackFrame.h>
|
|
12
|
+
#import <React/RCTReloadCommand.h>
|
|
13
|
+
#import <React/RCTUtils.h>
|
|
14
|
+
|
|
15
|
+
#import <objc/runtime.h>
|
|
16
|
+
|
|
17
|
+
#if RCT_DEV_MENU
|
|
18
|
+
|
|
19
|
+
@interface UIButton (RCTRedBox)
|
|
20
|
+
|
|
21
|
+
@property (nonatomic) RCTRedBoxButtonPressHandler rct_handler;
|
|
22
|
+
|
|
23
|
+
- (void)rct_addBlock:(RCTRedBoxButtonPressHandler)handler forControlEvents:(UIControlEvents)controlEvents;
|
|
24
|
+
|
|
25
|
+
@end
|
|
26
|
+
|
|
27
|
+
@implementation UIButton (RCTRedBox)
|
|
28
|
+
|
|
29
|
+
- (RCTRedBoxButtonPressHandler)rct_handler
|
|
30
|
+
{
|
|
31
|
+
return objc_getAssociatedObject(self, @selector(rct_handler));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
- (void)setRct_handler:(RCTRedBoxButtonPressHandler)rct_handler
|
|
35
|
+
{
|
|
36
|
+
objc_setAssociatedObject(self, @selector(rct_handler), rct_handler, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
- (void)rct_callBlock
|
|
40
|
+
{
|
|
41
|
+
if (self.rct_handler) {
|
|
42
|
+
self.rct_handler();
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
- (void)rct_addBlock:(RCTRedBoxButtonPressHandler)handler forControlEvents:(UIControlEvents)controlEvents
|
|
47
|
+
{
|
|
48
|
+
self.rct_handler = handler;
|
|
49
|
+
[self addTarget:self action:@selector(rct_callBlock) forControlEvents:controlEvents];
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
@end
|
|
53
|
+
|
|
54
|
+
@implementation RCTRedBoxController {
|
|
55
|
+
UITableView *_stackTraceTableView;
|
|
56
|
+
NSString *_lastErrorMessage;
|
|
57
|
+
NSArray<RCTJSStackFrame *> *_lastStackTrace;
|
|
58
|
+
NSArray<NSString *> *_customButtonTitles;
|
|
59
|
+
NSArray<RCTRedBoxButtonPressHandler> *_customButtonHandlers;
|
|
60
|
+
int _lastErrorCookie;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
- (instancetype)initWithCustomButtonTitles:(NSArray<NSString *> *)customButtonTitles
|
|
64
|
+
customButtonHandlers:(NSArray<RCTRedBoxButtonPressHandler> *)customButtonHandlers
|
|
65
|
+
{
|
|
66
|
+
if (self = [super init]) {
|
|
67
|
+
_lastErrorCookie = -1;
|
|
68
|
+
_customButtonTitles = customButtonTitles;
|
|
69
|
+
_customButtonHandlers = customButtonHandlers;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return self;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
- (void)viewDidLoad
|
|
76
|
+
{
|
|
77
|
+
[super viewDidLoad];
|
|
78
|
+
self.view.backgroundColor = [UIColor blackColor];
|
|
79
|
+
|
|
80
|
+
const CGFloat buttonHeight = 60;
|
|
81
|
+
|
|
82
|
+
CGRect detailsFrame = self.view.bounds;
|
|
83
|
+
detailsFrame.size.height -= buttonHeight + (double)[self bottomSafeViewHeight];
|
|
84
|
+
|
|
85
|
+
_stackTraceTableView = [[UITableView alloc] initWithFrame:detailsFrame style:UITableViewStylePlain];
|
|
86
|
+
_stackTraceTableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
|
87
|
+
_stackTraceTableView.delegate = self;
|
|
88
|
+
_stackTraceTableView.dataSource = self;
|
|
89
|
+
_stackTraceTableView.backgroundColor = [UIColor clearColor];
|
|
90
|
+
#if !TARGET_OS_TV
|
|
91
|
+
_stackTraceTableView.separatorColor = [UIColor colorWithWhite:1 alpha:0.3];
|
|
92
|
+
_stackTraceTableView.separatorStyle = UITableViewCellSeparatorStyleNone;
|
|
93
|
+
#endif
|
|
94
|
+
_stackTraceTableView.indicatorStyle = UIScrollViewIndicatorStyleWhite;
|
|
95
|
+
[self.view addSubview:_stackTraceTableView];
|
|
96
|
+
|
|
97
|
+
#if TARGET_OS_SIMULATOR || TARGET_OS_MACCATALYST
|
|
98
|
+
NSString *reloadText = @"Reload\n(\u2318R)";
|
|
99
|
+
NSString *dismissText = @"Dismiss\n(ESC)";
|
|
100
|
+
NSString *copyText = @"Copy\n(\u2325\u2318C)";
|
|
101
|
+
NSString *extraText = @"Extra Info\n(\u2318E)";
|
|
102
|
+
#else
|
|
103
|
+
NSString *reloadText = @"Reload JS";
|
|
104
|
+
NSString *dismissText = @"Dismiss";
|
|
105
|
+
NSString *copyText = @"Copy";
|
|
106
|
+
NSString *extraText = @"Extra Info";
|
|
107
|
+
#endif
|
|
108
|
+
|
|
109
|
+
UIButton *dismissButton = [self redBoxButton:dismissText
|
|
110
|
+
accessibilityIdentifier:@"redbox-dismiss"
|
|
111
|
+
selector:@selector(dismiss)
|
|
112
|
+
block:nil];
|
|
113
|
+
UIButton *reloadButton = [self redBoxButton:reloadText
|
|
114
|
+
accessibilityIdentifier:@"redbox-reload"
|
|
115
|
+
selector:@selector(reload)
|
|
116
|
+
block:nil];
|
|
117
|
+
UIButton *copyButton = [self redBoxButton:copyText
|
|
118
|
+
accessibilityIdentifier:@"redbox-copy"
|
|
119
|
+
selector:@selector(copyStack)
|
|
120
|
+
block:nil];
|
|
121
|
+
UIButton *extraButton = [self redBoxButton:extraText
|
|
122
|
+
accessibilityIdentifier:@"redbox-extra"
|
|
123
|
+
selector:@selector(showExtraDataViewController)
|
|
124
|
+
block:nil];
|
|
125
|
+
|
|
126
|
+
[NSLayoutConstraint activateConstraints:@[
|
|
127
|
+
[dismissButton.heightAnchor constraintEqualToConstant:buttonHeight],
|
|
128
|
+
[reloadButton.heightAnchor constraintEqualToConstant:buttonHeight],
|
|
129
|
+
[copyButton.heightAnchor constraintEqualToConstant:buttonHeight],
|
|
130
|
+
[extraButton.heightAnchor constraintEqualToConstant:buttonHeight]
|
|
131
|
+
]];
|
|
132
|
+
|
|
133
|
+
UIStackView *buttonStackView = [[UIStackView alloc] init];
|
|
134
|
+
buttonStackView.translatesAutoresizingMaskIntoConstraints = NO;
|
|
135
|
+
buttonStackView.axis = UILayoutConstraintAxisHorizontal;
|
|
136
|
+
buttonStackView.distribution = UIStackViewDistributionFillEqually;
|
|
137
|
+
buttonStackView.alignment = UIStackViewAlignmentTop;
|
|
138
|
+
buttonStackView.backgroundColor = [UIColor colorWithRed:0.1 green:0.1 blue:0.1 alpha:1];
|
|
139
|
+
|
|
140
|
+
[buttonStackView addArrangedSubview:dismissButton];
|
|
141
|
+
[buttonStackView addArrangedSubview:reloadButton];
|
|
142
|
+
[buttonStackView addArrangedSubview:copyButton];
|
|
143
|
+
[buttonStackView addArrangedSubview:extraButton];
|
|
144
|
+
|
|
145
|
+
[self.view addSubview:buttonStackView];
|
|
146
|
+
|
|
147
|
+
[NSLayoutConstraint activateConstraints:@[
|
|
148
|
+
[buttonStackView.heightAnchor constraintEqualToConstant:buttonHeight + [self bottomSafeViewHeight]],
|
|
149
|
+
[buttonStackView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
|
|
150
|
+
[buttonStackView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
|
|
151
|
+
[buttonStackView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor]
|
|
152
|
+
]];
|
|
153
|
+
|
|
154
|
+
for (NSUInteger i = 0; i < [_customButtonTitles count]; i++) {
|
|
155
|
+
UIButton *button = [self redBoxButton:_customButtonTitles[i]
|
|
156
|
+
accessibilityIdentifier:@""
|
|
157
|
+
selector:nil
|
|
158
|
+
block:_customButtonHandlers[i]];
|
|
159
|
+
[button.heightAnchor constraintEqualToConstant:buttonHeight].active = YES;
|
|
160
|
+
[buttonStackView addArrangedSubview:button];
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
UIView *topBorder = [[UIView alloc] init];
|
|
164
|
+
topBorder.translatesAutoresizingMaskIntoConstraints = NO;
|
|
165
|
+
topBorder.backgroundColor = [UIColor colorWithRed:0.70 green:0.70 blue:0.70 alpha:1.0];
|
|
166
|
+
[topBorder.heightAnchor constraintEqualToConstant:1].active = YES;
|
|
167
|
+
|
|
168
|
+
[self.view addSubview:topBorder];
|
|
169
|
+
|
|
170
|
+
[NSLayoutConstraint activateConstraints:@[
|
|
171
|
+
[topBorder.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
|
|
172
|
+
[topBorder.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
|
|
173
|
+
[topBorder.bottomAnchor constraintEqualToAnchor:buttonStackView.topAnchor],
|
|
174
|
+
]];
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
- (UIButton *)redBoxButton:(NSString *)title
|
|
178
|
+
accessibilityIdentifier:(NSString *)accessibilityIdentifier
|
|
179
|
+
selector:(SEL)selector
|
|
180
|
+
block:(RCTRedBoxButtonPressHandler)block
|
|
181
|
+
{
|
|
182
|
+
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
|
|
183
|
+
button.autoresizingMask =
|
|
184
|
+
UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleRightMargin;
|
|
185
|
+
button.accessibilityIdentifier = accessibilityIdentifier;
|
|
186
|
+
button.titleLabel.font = [UIFont systemFontOfSize:13];
|
|
187
|
+
button.titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
|
|
188
|
+
button.titleLabel.textAlignment = NSTextAlignmentCenter;
|
|
189
|
+
button.backgroundColor = [UIColor colorWithRed:0.1 green:0.1 blue:0.1 alpha:1];
|
|
190
|
+
[button setTitle:title forState:UIControlStateNormal];
|
|
191
|
+
[button setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
|
|
192
|
+
[button setTitleColor:[UIColor colorWithWhite:1 alpha:0.5] forState:UIControlStateHighlighted];
|
|
193
|
+
if (selector) {
|
|
194
|
+
[button addTarget:self action:selector forControlEvents:UIControlEventTouchUpInside];
|
|
195
|
+
} else if (block) {
|
|
196
|
+
[button rct_addBlock:block forControlEvents:UIControlEventTouchUpInside];
|
|
197
|
+
}
|
|
198
|
+
return button;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
- (NSInteger)bottomSafeViewHeight
|
|
202
|
+
{
|
|
203
|
+
#if TARGET_OS_MACCATALYST
|
|
204
|
+
return 0;
|
|
205
|
+
#else
|
|
206
|
+
return RCTKeyWindow().safeAreaInsets.bottom;
|
|
207
|
+
#endif
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
RCT_NOT_IMPLEMENTED(-(instancetype)initWithCoder : (NSCoder *)aDecoder)
|
|
211
|
+
|
|
212
|
+
- (NSString *)stripAnsi:(NSString *)text
|
|
213
|
+
{
|
|
214
|
+
NSError *error = nil;
|
|
215
|
+
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"\\x1b\\[[0-9;]*m"
|
|
216
|
+
options:NSRegularExpressionCaseInsensitive
|
|
217
|
+
error:&error];
|
|
218
|
+
return [regex stringByReplacingMatchesInString:text options:0 range:NSMakeRange(0, [text length]) withTemplate:@""];
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
- (void)showErrorMessage:(NSString *)message
|
|
222
|
+
withStack:(NSArray<RCTJSStackFrame *> *)stack
|
|
223
|
+
isUpdate:(BOOL)isUpdate
|
|
224
|
+
errorCookie:(int)errorCookie
|
|
225
|
+
{
|
|
226
|
+
// Remove ANSI color codes from the message
|
|
227
|
+
NSString *messageWithoutAnsi = [self stripAnsi:message];
|
|
228
|
+
|
|
229
|
+
BOOL isRootViewControllerPresented = self.presentingViewController != nil;
|
|
230
|
+
// Show if this is a new message, or if we're updating the previous message
|
|
231
|
+
BOOL isNew = !isRootViewControllerPresented && !isUpdate;
|
|
232
|
+
BOOL isUpdateForSameMessage = !isNew &&
|
|
233
|
+
(isRootViewControllerPresented && isUpdate &&
|
|
234
|
+
((errorCookie == -1 && [_lastErrorMessage isEqualToString:messageWithoutAnsi]) ||
|
|
235
|
+
(errorCookie == _lastErrorCookie)));
|
|
236
|
+
if (isNew || isUpdateForSameMessage) {
|
|
237
|
+
_lastStackTrace = stack;
|
|
238
|
+
// message is displayed using UILabel, which is unable to render text of
|
|
239
|
+
// unlimited length, so we truncate it
|
|
240
|
+
_lastErrorMessage = [messageWithoutAnsi substringToIndex:MIN((NSUInteger)10000, messageWithoutAnsi.length)];
|
|
241
|
+
_lastErrorCookie = errorCookie;
|
|
242
|
+
|
|
243
|
+
[_stackTraceTableView reloadData];
|
|
244
|
+
|
|
245
|
+
if (!isRootViewControllerPresented) {
|
|
246
|
+
[_stackTraceTableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]
|
|
247
|
+
atScrollPosition:UITableViewScrollPositionTop
|
|
248
|
+
animated:NO];
|
|
249
|
+
[RCTKeyWindow().rootViewController presentViewController:self animated:YES completion:nil];
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
- (void)dismiss
|
|
255
|
+
{
|
|
256
|
+
[self dismissViewControllerAnimated:YES completion:nil];
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
- (void)reload
|
|
260
|
+
{
|
|
261
|
+
if (_actionDelegate != nil) {
|
|
262
|
+
[_actionDelegate reloadFromRedBoxController:self];
|
|
263
|
+
} else {
|
|
264
|
+
// In bridgeless mode `RCTRedBox` gets deallocated, we need to notify listeners anyway.
|
|
265
|
+
RCTTriggerReloadCommandListeners(@"Redbox");
|
|
266
|
+
[self dismiss];
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
- (void)showExtraDataViewController
|
|
271
|
+
{
|
|
272
|
+
[_actionDelegate loadExtraDataViewController];
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
- (void)copyStack
|
|
276
|
+
{
|
|
277
|
+
NSMutableString *fullStackTrace;
|
|
278
|
+
|
|
279
|
+
if (_lastErrorMessage != nil) {
|
|
280
|
+
fullStackTrace = [_lastErrorMessage mutableCopy];
|
|
281
|
+
[fullStackTrace appendString:@"\n\n"];
|
|
282
|
+
} else {
|
|
283
|
+
fullStackTrace = [NSMutableString string];
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
for (RCTJSStackFrame *stackFrame in _lastStackTrace) {
|
|
287
|
+
[fullStackTrace appendString:[NSString stringWithFormat:@"%@\n", stackFrame.methodName]];
|
|
288
|
+
if (stackFrame.file) {
|
|
289
|
+
[fullStackTrace appendFormat:@" %@\n", [self formatFrameSource:stackFrame]];
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
#if !TARGET_OS_TV
|
|
293
|
+
UIPasteboard *pb = [UIPasteboard generalPasteboard];
|
|
294
|
+
[pb setString:fullStackTrace];
|
|
295
|
+
#endif
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
- (NSString *)formatFrameSource:(RCTJSStackFrame *)stackFrame
|
|
299
|
+
{
|
|
300
|
+
NSString *fileName = RCTNilIfNull(stackFrame.file) ? [stackFrame.file lastPathComponent] : @"<unknown file>";
|
|
301
|
+
NSString *lineInfo = [NSString stringWithFormat:@"%@:%lld", fileName, (long long)stackFrame.lineNumber];
|
|
302
|
+
|
|
303
|
+
if (stackFrame.column != 0) {
|
|
304
|
+
lineInfo = [lineInfo stringByAppendingFormat:@":%lld", (long long)stackFrame.column];
|
|
305
|
+
}
|
|
306
|
+
return lineInfo;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
#pragma mark - TableView
|
|
310
|
+
|
|
311
|
+
- (NSInteger)numberOfSectionsInTableView:(__unused UITableView *)tableView
|
|
312
|
+
{
|
|
313
|
+
return 2;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
- (NSInteger)tableView:(__unused UITableView *)tableView numberOfRowsInSection:(NSInteger)section
|
|
317
|
+
{
|
|
318
|
+
return section == 0 ? 1 : _lastStackTrace.count;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
|
|
322
|
+
{
|
|
323
|
+
if (indexPath.section == 0) {
|
|
324
|
+
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"msg-cell"];
|
|
325
|
+
return [self reuseCell:cell forErrorMessage:_lastErrorMessage];
|
|
326
|
+
}
|
|
327
|
+
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
|
|
328
|
+
NSUInteger index = indexPath.row;
|
|
329
|
+
RCTJSStackFrame *stackFrame = _lastStackTrace[index];
|
|
330
|
+
return [self reuseCell:cell forStackFrame:stackFrame];
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
- (UITableViewCell *)reuseCell:(UITableViewCell *)cell forErrorMessage:(NSString *)message
|
|
334
|
+
{
|
|
335
|
+
if (!cell) {
|
|
336
|
+
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"msg-cell"];
|
|
337
|
+
cell.textLabel.accessibilityIdentifier = @"redbox-error";
|
|
338
|
+
cell.textLabel.textColor = [UIColor whiteColor];
|
|
339
|
+
|
|
340
|
+
// Prefer a monofont for formatting messages that were designed
|
|
341
|
+
// to be displayed in a terminal.
|
|
342
|
+
cell.textLabel.font = [UIFont monospacedSystemFontOfSize:14 weight:UIFontWeightBold];
|
|
343
|
+
|
|
344
|
+
cell.textLabel.lineBreakMode = NSLineBreakByWordWrapping;
|
|
345
|
+
cell.textLabel.numberOfLines = 0;
|
|
346
|
+
cell.detailTextLabel.textColor = [UIColor whiteColor];
|
|
347
|
+
cell.backgroundColor = [UIColor colorWithRed:0.82 green:0.10 blue:0.15 alpha:1.0];
|
|
348
|
+
cell.selectionStyle = UITableViewCellSelectionStyleNone;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
cell.textLabel.text = message;
|
|
352
|
+
|
|
353
|
+
return cell;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
- (UITableViewCell *)reuseCell:(UITableViewCell *)cell forStackFrame:(RCTJSStackFrame *)stackFrame
|
|
357
|
+
{
|
|
358
|
+
if (!cell) {
|
|
359
|
+
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"cell"];
|
|
360
|
+
cell.textLabel.font = [UIFont fontWithName:@"Menlo-Regular" size:14];
|
|
361
|
+
cell.textLabel.lineBreakMode = NSLineBreakByCharWrapping;
|
|
362
|
+
cell.textLabel.numberOfLines = 2;
|
|
363
|
+
cell.detailTextLabel.textColor = [UIColor colorWithRed:0.70 green:0.70 blue:0.70 alpha:1.0];
|
|
364
|
+
cell.detailTextLabel.font = [UIFont fontWithName:@"Menlo-Regular" size:11];
|
|
365
|
+
cell.detailTextLabel.lineBreakMode = NSLineBreakByTruncatingMiddle;
|
|
366
|
+
cell.backgroundColor = [UIColor clearColor];
|
|
367
|
+
cell.selectedBackgroundView = [UIView new];
|
|
368
|
+
cell.selectedBackgroundView.backgroundColor = [UIColor colorWithWhite:0 alpha:0.2];
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
cell.textLabel.text = stackFrame.methodName ?: @"(unnamed method)";
|
|
372
|
+
if (stackFrame.file) {
|
|
373
|
+
cell.detailTextLabel.text = [self formatFrameSource:stackFrame];
|
|
374
|
+
} else {
|
|
375
|
+
cell.detailTextLabel.text = @"";
|
|
376
|
+
}
|
|
377
|
+
cell.textLabel.textColor = stackFrame.collapse ? [UIColor lightGrayColor] : [UIColor whiteColor];
|
|
378
|
+
cell.detailTextLabel.textColor = stackFrame.collapse ? [UIColor colorWithRed:0.50 green:0.50 blue:0.50 alpha:1.0]
|
|
379
|
+
: [UIColor colorWithRed:0.70 green:0.70 blue:0.70 alpha:1.0];
|
|
380
|
+
return cell;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
|
|
384
|
+
{
|
|
385
|
+
if (indexPath.section == 0) {
|
|
386
|
+
NSMutableParagraphStyle *paragraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
|
|
387
|
+
paragraphStyle.lineBreakMode = NSLineBreakByWordWrapping;
|
|
388
|
+
|
|
389
|
+
NSDictionary *attributes =
|
|
390
|
+
@{NSFontAttributeName : [UIFont boldSystemFontOfSize:16], NSParagraphStyleAttributeName : paragraphStyle};
|
|
391
|
+
CGRect boundingRect =
|
|
392
|
+
[_lastErrorMessage boundingRectWithSize:CGSizeMake(tableView.frame.size.width - 30, CGFLOAT_MAX)
|
|
393
|
+
options:NSStringDrawingUsesLineFragmentOrigin
|
|
394
|
+
attributes:attributes
|
|
395
|
+
context:nil];
|
|
396
|
+
return ceil(boundingRect.size.height) + 40;
|
|
397
|
+
} else {
|
|
398
|
+
return 50;
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
|
|
403
|
+
{
|
|
404
|
+
if (indexPath.section == 1) {
|
|
405
|
+
NSUInteger row = indexPath.row;
|
|
406
|
+
RCTJSStackFrame *stackFrame = _lastStackTrace[row];
|
|
407
|
+
[_actionDelegate redBoxController:self openStackFrameInEditor:stackFrame];
|
|
408
|
+
}
|
|
409
|
+
[tableView deselectRowAtIndexPath:indexPath animated:YES];
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
#pragma mark - Key commands
|
|
413
|
+
|
|
414
|
+
- (NSArray<UIKeyCommand *> *)keyCommands
|
|
415
|
+
{
|
|
416
|
+
// NOTE: We could use RCTKeyCommands for this, but since
|
|
417
|
+
// we control this window, we can use the standard, non-hacky
|
|
418
|
+
// mechanism instead
|
|
419
|
+
|
|
420
|
+
return @[
|
|
421
|
+
// Dismiss red box
|
|
422
|
+
[UIKeyCommand keyCommandWithInput:UIKeyInputEscape modifierFlags:0 action:@selector(dismiss)],
|
|
423
|
+
|
|
424
|
+
// Reload
|
|
425
|
+
[UIKeyCommand keyCommandWithInput:@"r" modifierFlags:UIKeyModifierCommand action:@selector(reload)],
|
|
426
|
+
|
|
427
|
+
// Copy = Cmd-Option C since Cmd-C in the simulator copies the pasteboard from
|
|
428
|
+
// the simulator to the desktop pasteboard.
|
|
429
|
+
[UIKeyCommand keyCommandWithInput:@"c"
|
|
430
|
+
modifierFlags:UIKeyModifierCommand | UIKeyModifierAlternate
|
|
431
|
+
action:@selector(copyStack)],
|
|
432
|
+
|
|
433
|
+
// Extra data
|
|
434
|
+
[UIKeyCommand keyCommandWithInput:@"e"
|
|
435
|
+
modifierFlags:UIKeyModifierCommand
|
|
436
|
+
action:@selector(showExtraDataViewController)]
|
|
437
|
+
];
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
- (BOOL)canBecomeFirstResponder
|
|
441
|
+
{
|
|
442
|
+
return YES;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
@end
|
|
446
|
+
|
|
447
|
+
#endif
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
#import <Foundation/Foundation.h>
|
|
9
|
+
|
|
10
|
+
#import <React/RCTDefines.h>
|
|
11
|
+
|
|
12
|
+
#if RCT_DEV_MENU
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Minimal native HMR client that connects to Metro's /hot WebSocket endpoint
|
|
16
|
+
* while RedBox 2.0 is displayed. When Metro detects a file change
|
|
17
|
+
* (update-start), this client triggers a reload so the user's fix is picked up
|
|
18
|
+
* automatically — even when the JS runtime has no active HMR connection.
|
|
19
|
+
*/
|
|
20
|
+
@interface RCTRedBoxHMRClient : NSObject <NSURLSessionWebSocketDelegate>
|
|
21
|
+
- (instancetype)initWithBundleURL:(NSURL *)bundleURL onFileChange:(void (^)(void))onFileChange;
|
|
22
|
+
- (void)start;
|
|
23
|
+
- (void)stop;
|
|
24
|
+
@end
|
|
25
|
+
|
|
26
|
+
#endif
|