react-native 0.83.5 → 0.83.7
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/RCTDevLoadingView.mm +17 -0
- 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 -450
- 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/FBReactNativeSpec/FBReactNativeSpecJSI.h +16 -0
- package/ReactAndroid/gradle.properties +1 -1
- package/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlags.kt +13 -1
- package/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxAccessor.kt +21 -1
- package/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxInterop.kt +5 -1
- package/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.kt +5 -1
- package/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsLocalAccessor.kt +23 -1
- package/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsProvider.kt +5 -1
- package/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/ReactNativeVersion.kt +1 -1
- package/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.cpp +29 -1
- package/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.h +7 -1
- package/ReactCommon/cxxreact/ReactNativeVersion.h +2 -2
- package/ReactCommon/hermes/inspector-modern/chrome/Registration.cpp +44 -2
- 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/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 +9 -1
- package/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h +11 -1
- package/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp +58 -22
- package/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h +6 -2
- package/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h +9 -1
- package/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDynamicProvider.h +19 -1
- package/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h +3 -1
- package/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp +11 -1
- package/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h +5 -1
- package/package.json +10 -10
- package/src/private/featureflags/ReactNativeFeatureFlags.js +11 -1
- package/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js +3 -1
|
@@ -16,451 +16,15 @@
|
|
|
16
16
|
#import <React/RCTRedBoxExtraDataViewController.h>
|
|
17
17
|
#import <React/RCTReloadCommand.h>
|
|
18
18
|
#import <React/RCTUtils.h>
|
|
19
|
-
|
|
20
|
-
#import <objc/runtime.h>
|
|
19
|
+
#import <react/featureflags/ReactNativeFeatureFlags.h>
|
|
21
20
|
|
|
22
21
|
#import "CoreModulesPlugins.h"
|
|
22
|
+
#import "RCTRedBox+Internal.h"
|
|
23
|
+
#import "RCTRedBox2Controller+Internal.h"
|
|
24
|
+
#import "RCTRedBoxController+Internal.h"
|
|
23
25
|
|
|
24
26
|
#if RCT_DEV_MENU
|
|
25
27
|
|
|
26
|
-
@class RCTRedBoxController;
|
|
27
|
-
|
|
28
|
-
@interface UIButton (RCTRedBox)
|
|
29
|
-
|
|
30
|
-
@property (nonatomic) RCTRedBoxButtonPressHandler rct_handler;
|
|
31
|
-
|
|
32
|
-
- (void)rct_addBlock:(RCTRedBoxButtonPressHandler)handler forControlEvents:(UIControlEvents)controlEvents;
|
|
33
|
-
|
|
34
|
-
@end
|
|
35
|
-
|
|
36
|
-
@implementation UIButton (RCTRedBox)
|
|
37
|
-
|
|
38
|
-
- (RCTRedBoxButtonPressHandler)rct_handler
|
|
39
|
-
{
|
|
40
|
-
return objc_getAssociatedObject(self, @selector(rct_handler));
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
- (void)setRct_handler:(RCTRedBoxButtonPressHandler)rct_handler
|
|
44
|
-
{
|
|
45
|
-
objc_setAssociatedObject(self, @selector(rct_handler), rct_handler, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
- (void)rct_callBlock
|
|
49
|
-
{
|
|
50
|
-
if (self.rct_handler) {
|
|
51
|
-
self.rct_handler();
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
- (void)rct_addBlock:(RCTRedBoxButtonPressHandler)handler forControlEvents:(UIControlEvents)controlEvents
|
|
56
|
-
{
|
|
57
|
-
self.rct_handler = handler;
|
|
58
|
-
[self addTarget:self action:@selector(rct_callBlock) forControlEvents:controlEvents];
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
@end
|
|
62
|
-
|
|
63
|
-
@protocol RCTRedBoxControllerActionDelegate <NSObject>
|
|
64
|
-
|
|
65
|
-
- (void)redBoxController:(RCTRedBoxController *)redBoxController openStackFrameInEditor:(RCTJSStackFrame *)stackFrame;
|
|
66
|
-
- (void)reloadFromRedBoxController:(RCTRedBoxController *)redBoxController;
|
|
67
|
-
- (void)loadExtraDataViewController;
|
|
68
|
-
|
|
69
|
-
@end
|
|
70
|
-
|
|
71
|
-
@interface RCTRedBoxController : UIViewController <UITableViewDelegate, UITableViewDataSource>
|
|
72
|
-
@property (nonatomic, weak) id<RCTRedBoxControllerActionDelegate> actionDelegate;
|
|
73
|
-
@end
|
|
74
|
-
|
|
75
|
-
@implementation RCTRedBoxController {
|
|
76
|
-
UITableView *_stackTraceTableView;
|
|
77
|
-
NSString *_lastErrorMessage;
|
|
78
|
-
NSArray<RCTJSStackFrame *> *_lastStackTrace;
|
|
79
|
-
NSArray<NSString *> *_customButtonTitles;
|
|
80
|
-
NSArray<RCTRedBoxButtonPressHandler> *_customButtonHandlers;
|
|
81
|
-
int _lastErrorCookie;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
- (instancetype)initWithCustomButtonTitles:(NSArray<NSString *> *)customButtonTitles
|
|
85
|
-
customButtonHandlers:(NSArray<RCTRedBoxButtonPressHandler> *)customButtonHandlers
|
|
86
|
-
{
|
|
87
|
-
if (self = [super init]) {
|
|
88
|
-
_lastErrorCookie = -1;
|
|
89
|
-
_customButtonTitles = customButtonTitles;
|
|
90
|
-
_customButtonHandlers = customButtonHandlers;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
return self;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
- (void)viewDidLoad
|
|
97
|
-
{
|
|
98
|
-
[super viewDidLoad];
|
|
99
|
-
self.view.backgroundColor = [UIColor blackColor];
|
|
100
|
-
|
|
101
|
-
const CGFloat buttonHeight = 60;
|
|
102
|
-
|
|
103
|
-
CGRect detailsFrame = self.view.bounds;
|
|
104
|
-
detailsFrame.size.height -= buttonHeight + (double)[self bottomSafeViewHeight];
|
|
105
|
-
|
|
106
|
-
_stackTraceTableView = [[UITableView alloc] initWithFrame:detailsFrame style:UITableViewStylePlain];
|
|
107
|
-
_stackTraceTableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
|
108
|
-
_stackTraceTableView.delegate = self;
|
|
109
|
-
_stackTraceTableView.dataSource = self;
|
|
110
|
-
_stackTraceTableView.backgroundColor = [UIColor clearColor];
|
|
111
|
-
_stackTraceTableView.separatorColor = [UIColor colorWithWhite:1 alpha:0.3];
|
|
112
|
-
_stackTraceTableView.separatorStyle = UITableViewCellSeparatorStyleNone;
|
|
113
|
-
_stackTraceTableView.indicatorStyle = UIScrollViewIndicatorStyleWhite;
|
|
114
|
-
[self.view addSubview:_stackTraceTableView];
|
|
115
|
-
|
|
116
|
-
#if TARGET_OS_SIMULATOR || TARGET_OS_MACCATALYST
|
|
117
|
-
NSString *reloadText = @"Reload\n(\u2318R)";
|
|
118
|
-
NSString *dismissText = @"Dismiss\n(ESC)";
|
|
119
|
-
NSString *copyText = @"Copy\n(\u2325\u2318C)";
|
|
120
|
-
NSString *extraText = @"Extra Info\n(\u2318E)";
|
|
121
|
-
#else
|
|
122
|
-
NSString *reloadText = @"Reload JS";
|
|
123
|
-
NSString *dismissText = @"Dismiss";
|
|
124
|
-
NSString *copyText = @"Copy";
|
|
125
|
-
NSString *extraText = @"Extra Info";
|
|
126
|
-
#endif
|
|
127
|
-
|
|
128
|
-
UIButton *dismissButton = [self redBoxButton:dismissText
|
|
129
|
-
accessibilityIdentifier:@"redbox-dismiss"
|
|
130
|
-
selector:@selector(dismiss)
|
|
131
|
-
block:nil];
|
|
132
|
-
UIButton *reloadButton = [self redBoxButton:reloadText
|
|
133
|
-
accessibilityIdentifier:@"redbox-reload"
|
|
134
|
-
selector:@selector(reload)
|
|
135
|
-
block:nil];
|
|
136
|
-
UIButton *copyButton = [self redBoxButton:copyText
|
|
137
|
-
accessibilityIdentifier:@"redbox-copy"
|
|
138
|
-
selector:@selector(copyStack)
|
|
139
|
-
block:nil];
|
|
140
|
-
UIButton *extraButton = [self redBoxButton:extraText
|
|
141
|
-
accessibilityIdentifier:@"redbox-extra"
|
|
142
|
-
selector:@selector(showExtraDataViewController)
|
|
143
|
-
block:nil];
|
|
144
|
-
|
|
145
|
-
[NSLayoutConstraint activateConstraints:@[
|
|
146
|
-
[dismissButton.heightAnchor constraintEqualToConstant:buttonHeight],
|
|
147
|
-
[reloadButton.heightAnchor constraintEqualToConstant:buttonHeight],
|
|
148
|
-
[copyButton.heightAnchor constraintEqualToConstant:buttonHeight],
|
|
149
|
-
[extraButton.heightAnchor constraintEqualToConstant:buttonHeight]
|
|
150
|
-
]];
|
|
151
|
-
|
|
152
|
-
UIStackView *buttonStackView = [[UIStackView alloc] init];
|
|
153
|
-
buttonStackView.translatesAutoresizingMaskIntoConstraints = NO;
|
|
154
|
-
buttonStackView.axis = UILayoutConstraintAxisHorizontal;
|
|
155
|
-
buttonStackView.distribution = UIStackViewDistributionFillEqually;
|
|
156
|
-
buttonStackView.alignment = UIStackViewAlignmentTop;
|
|
157
|
-
buttonStackView.backgroundColor = [UIColor colorWithRed:0.1 green:0.1 blue:0.1 alpha:1];
|
|
158
|
-
|
|
159
|
-
[buttonStackView addArrangedSubview:dismissButton];
|
|
160
|
-
[buttonStackView addArrangedSubview:reloadButton];
|
|
161
|
-
[buttonStackView addArrangedSubview:copyButton];
|
|
162
|
-
[buttonStackView addArrangedSubview:extraButton];
|
|
163
|
-
|
|
164
|
-
[self.view addSubview:buttonStackView];
|
|
165
|
-
|
|
166
|
-
[NSLayoutConstraint activateConstraints:@[
|
|
167
|
-
[buttonStackView.heightAnchor constraintEqualToConstant:buttonHeight + [self bottomSafeViewHeight]],
|
|
168
|
-
[buttonStackView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
|
|
169
|
-
[buttonStackView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
|
|
170
|
-
[buttonStackView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor]
|
|
171
|
-
]];
|
|
172
|
-
|
|
173
|
-
for (NSUInteger i = 0; i < [_customButtonTitles count]; i++) {
|
|
174
|
-
UIButton *button = [self redBoxButton:_customButtonTitles[i]
|
|
175
|
-
accessibilityIdentifier:@""
|
|
176
|
-
selector:nil
|
|
177
|
-
block:_customButtonHandlers[i]];
|
|
178
|
-
[button.heightAnchor constraintEqualToConstant:buttonHeight].active = YES;
|
|
179
|
-
[buttonStackView addArrangedSubview:button];
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
UIView *topBorder = [[UIView alloc] init];
|
|
183
|
-
topBorder.translatesAutoresizingMaskIntoConstraints = NO;
|
|
184
|
-
topBorder.backgroundColor = [UIColor colorWithRed:0.70 green:0.70 blue:0.70 alpha:1.0];
|
|
185
|
-
[topBorder.heightAnchor constraintEqualToConstant:1].active = YES;
|
|
186
|
-
|
|
187
|
-
[self.view addSubview:topBorder];
|
|
188
|
-
|
|
189
|
-
[NSLayoutConstraint activateConstraints:@[
|
|
190
|
-
[topBorder.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
|
|
191
|
-
[topBorder.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
|
|
192
|
-
[topBorder.bottomAnchor constraintEqualToAnchor:buttonStackView.topAnchor],
|
|
193
|
-
]];
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
- (UIButton *)redBoxButton:(NSString *)title
|
|
197
|
-
accessibilityIdentifier:(NSString *)accessibilityIdentifier
|
|
198
|
-
selector:(SEL)selector
|
|
199
|
-
block:(RCTRedBoxButtonPressHandler)block
|
|
200
|
-
{
|
|
201
|
-
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
|
|
202
|
-
button.autoresizingMask =
|
|
203
|
-
UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleRightMargin;
|
|
204
|
-
button.accessibilityIdentifier = accessibilityIdentifier;
|
|
205
|
-
button.titleLabel.font = [UIFont systemFontOfSize:13];
|
|
206
|
-
button.titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
|
|
207
|
-
button.titleLabel.textAlignment = NSTextAlignmentCenter;
|
|
208
|
-
button.backgroundColor = [UIColor colorWithRed:0.1 green:0.1 blue:0.1 alpha:1];
|
|
209
|
-
[button setTitle:title forState:UIControlStateNormal];
|
|
210
|
-
[button setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
|
|
211
|
-
[button setTitleColor:[UIColor colorWithWhite:1 alpha:0.5] forState:UIControlStateHighlighted];
|
|
212
|
-
if (selector) {
|
|
213
|
-
[button addTarget:self action:selector forControlEvents:UIControlEventTouchUpInside];
|
|
214
|
-
} else if (block) {
|
|
215
|
-
[button rct_addBlock:block forControlEvents:UIControlEventTouchUpInside];
|
|
216
|
-
}
|
|
217
|
-
return button;
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
- (NSInteger)bottomSafeViewHeight
|
|
221
|
-
{
|
|
222
|
-
#if TARGET_OS_MACCATALYST
|
|
223
|
-
return 0;
|
|
224
|
-
#else
|
|
225
|
-
return RCTKeyWindow().safeAreaInsets.bottom;
|
|
226
|
-
#endif
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
RCT_NOT_IMPLEMENTED(-(instancetype)initWithCoder : (NSCoder *)aDecoder)
|
|
230
|
-
|
|
231
|
-
- (NSString *)stripAnsi:(NSString *)text
|
|
232
|
-
{
|
|
233
|
-
NSError *error = nil;
|
|
234
|
-
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"\\x1b\\[[0-9;]*m"
|
|
235
|
-
options:NSRegularExpressionCaseInsensitive
|
|
236
|
-
error:&error];
|
|
237
|
-
return [regex stringByReplacingMatchesInString:text options:0 range:NSMakeRange(0, [text length]) withTemplate:@""];
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
- (void)showErrorMessage:(NSString *)message
|
|
241
|
-
withStack:(NSArray<RCTJSStackFrame *> *)stack
|
|
242
|
-
isUpdate:(BOOL)isUpdate
|
|
243
|
-
errorCookie:(int)errorCookie
|
|
244
|
-
{
|
|
245
|
-
// Remove ANSI color codes from the message
|
|
246
|
-
NSString *messageWithoutAnsi = [self stripAnsi:message];
|
|
247
|
-
|
|
248
|
-
BOOL isRootViewControllerPresented = self.presentingViewController != nil;
|
|
249
|
-
// Show if this is a new message, or if we're updating the previous message
|
|
250
|
-
BOOL isNew = !isRootViewControllerPresented && !isUpdate;
|
|
251
|
-
BOOL isUpdateForSameMessage = !isNew &&
|
|
252
|
-
(isRootViewControllerPresented && isUpdate &&
|
|
253
|
-
((errorCookie == -1 && [_lastErrorMessage isEqualToString:messageWithoutAnsi]) ||
|
|
254
|
-
(errorCookie == _lastErrorCookie)));
|
|
255
|
-
if (isNew || isUpdateForSameMessage) {
|
|
256
|
-
_lastStackTrace = stack;
|
|
257
|
-
// message is displayed using UILabel, which is unable to render text of
|
|
258
|
-
// unlimited length, so we truncate it
|
|
259
|
-
_lastErrorMessage = [messageWithoutAnsi substringToIndex:MIN((NSUInteger)10000, messageWithoutAnsi.length)];
|
|
260
|
-
_lastErrorCookie = errorCookie;
|
|
261
|
-
|
|
262
|
-
[_stackTraceTableView reloadData];
|
|
263
|
-
|
|
264
|
-
if (!isRootViewControllerPresented) {
|
|
265
|
-
[_stackTraceTableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]
|
|
266
|
-
atScrollPosition:UITableViewScrollPositionTop
|
|
267
|
-
animated:NO];
|
|
268
|
-
[RCTKeyWindow().rootViewController presentViewController:self animated:YES completion:nil];
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
- (void)dismiss
|
|
274
|
-
{
|
|
275
|
-
[self dismissViewControllerAnimated:YES completion:nil];
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
- (void)reload
|
|
279
|
-
{
|
|
280
|
-
if (_actionDelegate != nil) {
|
|
281
|
-
[_actionDelegate reloadFromRedBoxController:self];
|
|
282
|
-
} else {
|
|
283
|
-
// In bridgeless mode `RCTRedBox` gets deallocated, we need to notify listeners anyway.
|
|
284
|
-
RCTTriggerReloadCommandListeners(@"Redbox");
|
|
285
|
-
[self dismiss];
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
- (void)showExtraDataViewController
|
|
290
|
-
{
|
|
291
|
-
[_actionDelegate loadExtraDataViewController];
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
- (void)copyStack
|
|
295
|
-
{
|
|
296
|
-
NSMutableString *fullStackTrace;
|
|
297
|
-
|
|
298
|
-
if (_lastErrorMessage != nil) {
|
|
299
|
-
fullStackTrace = [_lastErrorMessage mutableCopy];
|
|
300
|
-
[fullStackTrace appendString:@"\n\n"];
|
|
301
|
-
} else {
|
|
302
|
-
fullStackTrace = [NSMutableString string];
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
for (RCTJSStackFrame *stackFrame in _lastStackTrace) {
|
|
306
|
-
[fullStackTrace appendString:[NSString stringWithFormat:@"%@\n", stackFrame.methodName]];
|
|
307
|
-
if (stackFrame.file) {
|
|
308
|
-
[fullStackTrace appendFormat:@" %@\n", [self formatFrameSource:stackFrame]];
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
UIPasteboard *pb = [UIPasteboard generalPasteboard];
|
|
312
|
-
[pb setString:fullStackTrace];
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
- (NSString *)formatFrameSource:(RCTJSStackFrame *)stackFrame
|
|
316
|
-
{
|
|
317
|
-
NSString *fileName = RCTNilIfNull(stackFrame.file) ? [stackFrame.file lastPathComponent] : @"<unknown file>";
|
|
318
|
-
NSString *lineInfo = [NSString stringWithFormat:@"%@:%lld", fileName, (long long)stackFrame.lineNumber];
|
|
319
|
-
|
|
320
|
-
if (stackFrame.column != 0) {
|
|
321
|
-
lineInfo = [lineInfo stringByAppendingFormat:@":%lld", (long long)stackFrame.column];
|
|
322
|
-
}
|
|
323
|
-
return lineInfo;
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
#pragma mark - TableView
|
|
327
|
-
|
|
328
|
-
- (NSInteger)numberOfSectionsInTableView:(__unused UITableView *)tableView
|
|
329
|
-
{
|
|
330
|
-
return 2;
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
- (NSInteger)tableView:(__unused UITableView *)tableView numberOfRowsInSection:(NSInteger)section
|
|
334
|
-
{
|
|
335
|
-
return section == 0 ? 1 : _lastStackTrace.count;
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
|
|
339
|
-
{
|
|
340
|
-
if (indexPath.section == 0) {
|
|
341
|
-
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"msg-cell"];
|
|
342
|
-
return [self reuseCell:cell forErrorMessage:_lastErrorMessage];
|
|
343
|
-
}
|
|
344
|
-
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
|
|
345
|
-
NSUInteger index = indexPath.row;
|
|
346
|
-
RCTJSStackFrame *stackFrame = _lastStackTrace[index];
|
|
347
|
-
return [self reuseCell:cell forStackFrame:stackFrame];
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
- (UITableViewCell *)reuseCell:(UITableViewCell *)cell forErrorMessage:(NSString *)message
|
|
351
|
-
{
|
|
352
|
-
if (!cell) {
|
|
353
|
-
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"msg-cell"];
|
|
354
|
-
cell.textLabel.accessibilityIdentifier = @"redbox-error";
|
|
355
|
-
cell.textLabel.textColor = [UIColor whiteColor];
|
|
356
|
-
|
|
357
|
-
// Prefer a monofont for formatting messages that were designed
|
|
358
|
-
// to be displayed in a terminal.
|
|
359
|
-
cell.textLabel.font = [UIFont monospacedSystemFontOfSize:14 weight:UIFontWeightBold];
|
|
360
|
-
|
|
361
|
-
cell.textLabel.lineBreakMode = NSLineBreakByWordWrapping;
|
|
362
|
-
cell.textLabel.numberOfLines = 0;
|
|
363
|
-
cell.detailTextLabel.textColor = [UIColor whiteColor];
|
|
364
|
-
cell.backgroundColor = [UIColor colorWithRed:0.82 green:0.10 blue:0.15 alpha:1.0];
|
|
365
|
-
cell.selectionStyle = UITableViewCellSelectionStyleNone;
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
cell.textLabel.text = message;
|
|
369
|
-
|
|
370
|
-
return cell;
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
- (UITableViewCell *)reuseCell:(UITableViewCell *)cell forStackFrame:(RCTJSStackFrame *)stackFrame
|
|
374
|
-
{
|
|
375
|
-
if (!cell) {
|
|
376
|
-
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"cell"];
|
|
377
|
-
cell.textLabel.font = [UIFont fontWithName:@"Menlo-Regular" size:14];
|
|
378
|
-
cell.textLabel.lineBreakMode = NSLineBreakByCharWrapping;
|
|
379
|
-
cell.textLabel.numberOfLines = 2;
|
|
380
|
-
cell.detailTextLabel.textColor = [UIColor colorWithRed:0.70 green:0.70 blue:0.70 alpha:1.0];
|
|
381
|
-
cell.detailTextLabel.font = [UIFont fontWithName:@"Menlo-Regular" size:11];
|
|
382
|
-
cell.detailTextLabel.lineBreakMode = NSLineBreakByTruncatingMiddle;
|
|
383
|
-
cell.backgroundColor = [UIColor clearColor];
|
|
384
|
-
cell.selectedBackgroundView = [UIView new];
|
|
385
|
-
cell.selectedBackgroundView.backgroundColor = [UIColor colorWithWhite:0 alpha:0.2];
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
cell.textLabel.text = stackFrame.methodName ?: @"(unnamed method)";
|
|
389
|
-
if (stackFrame.file) {
|
|
390
|
-
cell.detailTextLabel.text = [self formatFrameSource:stackFrame];
|
|
391
|
-
} else {
|
|
392
|
-
cell.detailTextLabel.text = @"";
|
|
393
|
-
}
|
|
394
|
-
cell.textLabel.textColor = stackFrame.collapse ? [UIColor lightGrayColor] : [UIColor whiteColor];
|
|
395
|
-
cell.detailTextLabel.textColor = stackFrame.collapse ? [UIColor colorWithRed:0.50 green:0.50 blue:0.50 alpha:1.0]
|
|
396
|
-
: [UIColor colorWithRed:0.70 green:0.70 blue:0.70 alpha:1.0];
|
|
397
|
-
return cell;
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
|
|
401
|
-
{
|
|
402
|
-
if (indexPath.section == 0) {
|
|
403
|
-
NSMutableParagraphStyle *paragraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
|
|
404
|
-
paragraphStyle.lineBreakMode = NSLineBreakByWordWrapping;
|
|
405
|
-
|
|
406
|
-
NSDictionary *attributes =
|
|
407
|
-
@{NSFontAttributeName : [UIFont boldSystemFontOfSize:16], NSParagraphStyleAttributeName : paragraphStyle};
|
|
408
|
-
CGRect boundingRect =
|
|
409
|
-
[_lastErrorMessage boundingRectWithSize:CGSizeMake(tableView.frame.size.width - 30, CGFLOAT_MAX)
|
|
410
|
-
options:NSStringDrawingUsesLineFragmentOrigin
|
|
411
|
-
attributes:attributes
|
|
412
|
-
context:nil];
|
|
413
|
-
return ceil(boundingRect.size.height) + 40;
|
|
414
|
-
} else {
|
|
415
|
-
return 50;
|
|
416
|
-
}
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
|
|
420
|
-
{
|
|
421
|
-
if (indexPath.section == 1) {
|
|
422
|
-
NSUInteger row = indexPath.row;
|
|
423
|
-
RCTJSStackFrame *stackFrame = _lastStackTrace[row];
|
|
424
|
-
[_actionDelegate redBoxController:self openStackFrameInEditor:stackFrame];
|
|
425
|
-
}
|
|
426
|
-
[tableView deselectRowAtIndexPath:indexPath animated:YES];
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
#pragma mark - Key commands
|
|
430
|
-
|
|
431
|
-
- (NSArray<UIKeyCommand *> *)keyCommands
|
|
432
|
-
{
|
|
433
|
-
// NOTE: We could use RCTKeyCommands for this, but since
|
|
434
|
-
// we control this window, we can use the standard, non-hacky
|
|
435
|
-
// mechanism instead
|
|
436
|
-
|
|
437
|
-
return @[
|
|
438
|
-
// Dismiss red box
|
|
439
|
-
[UIKeyCommand keyCommandWithInput:UIKeyInputEscape modifierFlags:0 action:@selector(dismiss)],
|
|
440
|
-
|
|
441
|
-
// Reload
|
|
442
|
-
[UIKeyCommand keyCommandWithInput:@"r" modifierFlags:UIKeyModifierCommand action:@selector(reload)],
|
|
443
|
-
|
|
444
|
-
// Copy = Cmd-Option C since Cmd-C in the simulator copies the pasteboard from
|
|
445
|
-
// the simulator to the desktop pasteboard.
|
|
446
|
-
[UIKeyCommand keyCommandWithInput:@"c"
|
|
447
|
-
modifierFlags:UIKeyModifierCommand | UIKeyModifierAlternate
|
|
448
|
-
action:@selector(copyStack)],
|
|
449
|
-
|
|
450
|
-
// Extra data
|
|
451
|
-
[UIKeyCommand keyCommandWithInput:@"e"
|
|
452
|
-
modifierFlags:UIKeyModifierCommand
|
|
453
|
-
action:@selector(showExtraDataViewController)]
|
|
454
|
-
];
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
- (BOOL)canBecomeFirstResponder
|
|
458
|
-
{
|
|
459
|
-
return YES;
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
@end
|
|
463
|
-
|
|
464
28
|
@interface RCTRedBox () <
|
|
465
29
|
RCTInvalidating,
|
|
466
30
|
RCTRedBoxControllerActionDelegate,
|
|
@@ -469,7 +33,7 @@ RCT_NOT_IMPLEMENTED(-(instancetype)initWithCoder : (NSCoder *)aDecoder)
|
|
|
469
33
|
@end
|
|
470
34
|
|
|
471
35
|
@implementation RCTRedBox {
|
|
472
|
-
|
|
36
|
+
id<RCTRedBoxControlling> _controller;
|
|
473
37
|
NSMutableArray<id<RCTErrorCustomizer>> *_errorCustomizers;
|
|
474
38
|
RCTRedBoxExtraDataViewController *_extraDataViewController;
|
|
475
39
|
NSMutableArray<NSString *> *_customButtonTitles;
|
|
@@ -601,6 +165,14 @@ RCT_EXPORT_MODULE()
|
|
|
601
165
|
[self showErrorMessage:message withParsedStack:stack isUpdate:YES errorCookie:errorCookie];
|
|
602
166
|
}
|
|
603
167
|
|
|
168
|
+
- (id<RCTRedBox2Controlling>)_redBox2Controller
|
|
169
|
+
{
|
|
170
|
+
if ([_controller conformsToProtocol:@protocol(RCTRedBox2Controlling)]) {
|
|
171
|
+
return (id<RCTRedBox2Controlling>)_controller;
|
|
172
|
+
}
|
|
173
|
+
return nil;
|
|
174
|
+
}
|
|
175
|
+
|
|
604
176
|
- (void)showErrorMessage:(NSString *)message
|
|
605
177
|
withParsedStack:(NSArray<RCTJSStackFrame *> *)stack
|
|
606
178
|
isUpdate:(BOOL)isUpdate
|
|
@@ -617,14 +189,21 @@ RCT_EXPORT_MODULE()
|
|
|
617
189
|
[[self->_moduleRegistry moduleForName:"EventDispatcher"] sendDeviceEventWithName:@"collectRedBoxExtraData"
|
|
618
190
|
body:nil];
|
|
619
191
|
#pragma clang diagnostic pop
|
|
620
|
-
if (!self->_controller) {
|
|
621
|
-
self->_controller = [[RCTRedBoxController alloc] initWithCustomButtonTitles:self->_customButtonTitles
|
|
622
|
-
customButtonHandlers:self->_customButtonHandlers];
|
|
623
|
-
self->_controller.actionDelegate = self;
|
|
624
|
-
}
|
|
625
192
|
|
|
626
193
|
RCTErrorInfo *errorInfo = [[RCTErrorInfo alloc] initWithErrorMessage:message stack:stack];
|
|
627
194
|
errorInfo = [self _customizeError:errorInfo];
|
|
195
|
+
|
|
196
|
+
if (self->_controller == nullptr) {
|
|
197
|
+
if (facebook::react::ReactNativeFeatureFlags::redBoxV2IOS()) {
|
|
198
|
+
self->_controller = [[RCTRedBox2Controller alloc] initWithCustomButtonTitles:self->_customButtonTitles
|
|
199
|
+
customButtonHandlers:self->_customButtonHandlers];
|
|
200
|
+
} else {
|
|
201
|
+
self->_controller = [[RCTRedBoxController alloc] initWithCustomButtonTitles:self->_customButtonTitles
|
|
202
|
+
customButtonHandlers:self->_customButtonHandlers];
|
|
203
|
+
}
|
|
204
|
+
self->_controller.actionDelegate = self;
|
|
205
|
+
}
|
|
206
|
+
[self _redBox2Controller].bundleURL = self->_overrideBundleURL ?: self->_bundleManager.bundleURL;
|
|
628
207
|
[self->_controller showErrorMessage:errorInfo.errorMessage
|
|
629
208
|
withStack:errorInfo.stack
|
|
630
209
|
isUpdate:isUpdate
|
|
@@ -635,9 +214,10 @@ RCT_EXPORT_MODULE()
|
|
|
635
214
|
- (void)loadExtraDataViewController
|
|
636
215
|
{
|
|
637
216
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
217
|
+
UIViewController *controller = static_cast<UIViewController *>(self->_controller);
|
|
638
218
|
// Make sure the CMD+E shortcut doesn't call this twice
|
|
639
|
-
if (self->_extraDataViewController != nil &&
|
|
640
|
-
[
|
|
219
|
+
if (self->_extraDataViewController != nil && ([controller presentedViewController] == nullptr)) {
|
|
220
|
+
[controller presentViewController:self->_extraDataViewController animated:YES completion:nil];
|
|
641
221
|
}
|
|
642
222
|
});
|
|
643
223
|
}
|
|
@@ -659,7 +239,7 @@ RCT_EXPORT_METHOD(dismiss)
|
|
|
659
239
|
[self dismiss];
|
|
660
240
|
}
|
|
661
241
|
|
|
662
|
-
- (void)redBoxController:(__unused
|
|
242
|
+
- (void)redBoxController:(__unused UIViewController *)redBoxController
|
|
663
243
|
openStackFrameInEditor:(RCTJSStackFrame *)stackFrame
|
|
664
244
|
{
|
|
665
245
|
NSURL *const bundleURL = _overrideBundleURL ?: _bundleManager.bundleURL;
|
|
@@ -686,7 +266,7 @@ RCT_EXPORT_METHOD(dismiss)
|
|
|
686
266
|
[self reloadFromRedBoxController:nil];
|
|
687
267
|
}
|
|
688
268
|
|
|
689
|
-
- (void)reloadFromRedBoxController:(__unused
|
|
269
|
+
- (void)reloadFromRedBoxController:(__unused UIViewController *)redBoxController
|
|
690
270
|
{
|
|
691
271
|
if (_overrideReloadAction) {
|
|
692
272
|
_overrideReloadAction();
|
|
@@ -0,0 +1,22 @@
|
|
|
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 <UIKit/UIKit.h>
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Parses ANSI escape sequences in text and produces an NSAttributedString
|
|
12
|
+
* with the corresponding foreground/background colors applied.
|
|
13
|
+
*
|
|
14
|
+
* Uses the Afterglow color theme (matching LogBox's AnsiHighlight.js).
|
|
15
|
+
*/
|
|
16
|
+
@interface RCTRedBox2AnsiParser : NSObject
|
|
17
|
+
|
|
18
|
+
+ (NSAttributedString *)attributedStringFromAnsiText:(NSString *)text
|
|
19
|
+
baseFont:(UIFont *)font
|
|
20
|
+
baseColor:(UIColor *)color;
|
|
21
|
+
|
|
22
|
+
@end
|
|
@@ -0,0 +1,55 @@
|
|
|
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 "RCTRedBox2AnsiParser+Internal.h"
|
|
9
|
+
|
|
10
|
+
#import <React/RCTDefines.h>
|
|
11
|
+
#import <react/debug/redbox/AnsiParser.h>
|
|
12
|
+
|
|
13
|
+
#if RCT_DEV_MENU
|
|
14
|
+
|
|
15
|
+
using facebook::react::unstable_redbox::AnsiColor;
|
|
16
|
+
using facebook::react::unstable_redbox::parseAnsi;
|
|
17
|
+
|
|
18
|
+
static UIColor *RCTUIColorFromAnsiColor(const AnsiColor &c)
|
|
19
|
+
{
|
|
20
|
+
return [UIColor colorWithRed:c.r / 255.0 green:c.g / 255.0 blue:c.b / 255.0 alpha:1.0];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
@implementation RCTRedBox2AnsiParser
|
|
24
|
+
|
|
25
|
+
+ (NSAttributedString *)attributedStringFromAnsiText:(NSString *)text baseFont:(UIFont *)font baseColor:(UIColor *)color
|
|
26
|
+
{
|
|
27
|
+
if (text == nil) {
|
|
28
|
+
return [[NSAttributedString alloc] init];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
auto spans = parseAnsi(text.UTF8String);
|
|
32
|
+
NSMutableAttributedString *result =[NSMutableAttributedString new];
|
|
33
|
+
NSDictionary *baseAttributes = @{NSFontAttributeName : font, NSForegroundColorAttributeName : color};
|
|
34
|
+
|
|
35
|
+
for (const auto &span : spans) {
|
|
36
|
+
NSString *str = [NSString stringWithUTF8String:span.text.c_str()];
|
|
37
|
+
if (str == nil) {
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
NSMutableDictionary *attrs = [baseAttributes mutableCopy];
|
|
41
|
+
if (span.foregroundColor.has_value()) {
|
|
42
|
+
attrs[NSForegroundColorAttributeName] = RCTUIColorFromAnsiColor(*span.foregroundColor);
|
|
43
|
+
}
|
|
44
|
+
if (span.backgroundColor.has_value()) {
|
|
45
|
+
attrs[NSBackgroundColorAttributeName] = RCTUIColorFromAnsiColor(*span.backgroundColor);
|
|
46
|
+
}
|
|
47
|
+
[result appendAttributedString:[[NSAttributedString alloc] initWithString:str attributes:attrs]];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return result;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
@end
|
|
54
|
+
|
|
55
|
+
#endif
|
|
@@ -0,0 +1,34 @@
|
|
|
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
|
+
|
|
12
|
+
#if RCT_DEV_MENU
|
|
13
|
+
|
|
14
|
+
typedef void (^RCTRedBox2ButtonPressHandler)(void);
|
|
15
|
+
|
|
16
|
+
@interface RCTRedBox2Controller : UIViewController <RCTRedBox2Controlling, UITableViewDelegate, UITableViewDataSource>
|
|
17
|
+
|
|
18
|
+
@property (nonatomic, weak) id<RCTRedBoxControllerActionDelegate> actionDelegate;
|
|
19
|
+
|
|
20
|
+
- (instancetype)initWithCustomButtonTitles:(NSArray<NSString *> *)customButtonTitles
|
|
21
|
+
customButtonHandlers:(NSArray<RCTRedBox2ButtonPressHandler> *)customButtonHandlers;
|
|
22
|
+
|
|
23
|
+
- (void)showErrorMessage:(NSString *)message
|
|
24
|
+
withStack:(NSArray<RCTJSStackFrame *> *)stack
|
|
25
|
+
isUpdate:(BOOL)isUpdate
|
|
26
|
+
errorCookie:(int)errorCookie;
|
|
27
|
+
|
|
28
|
+
/// The bundle URL used by the app, for the native HMR connection.
|
|
29
|
+
@property (nonatomic, strong, nullable) NSURL *bundleURL;
|
|
30
|
+
|
|
31
|
+
- (void)dismiss;
|
|
32
|
+
@end
|
|
33
|
+
|
|
34
|
+
#endif
|