1// Copyright 2015-present 650 Industries. All rights reserved.
2
3#import <React/RCTAssert.h>
4
5#import <EXDevLauncher/EXDevLauncherRedBox.h>
6#import <EXDevLauncher/EXDevLauncherController.h>
7
8#if __has_include(<EXDevLauncher/EXDevLauncher-Swift.h>)
9// For cocoapods framework, the generated swift header will be inside EXDevLauncher module
10#import <EXDevLauncher/EXDevLauncher-Swift.h>
11#else
12#import <EXDevLauncher-Swift.h>
13#endif
14
15@interface EXDevLauncherRedBox ()
16
17@property (nonatomic, weak) RCTLogBox *logBox;
18
19@end
20
21@implementation EXDevLauncherRedBox
22
23@synthesize overrideBundleURL;
24@synthesize overrideReloadAction;
25
26- (void)registerLogBox:(RCTLogBox * _Nullable)logBox
27{
28  self.logBox = logBox;
29}
30
31- (void)addCustomButton:(NSString *)title onPressHandler:(RCTRedBoxButtonPressHandler)handler {
32
33}
34
35- (void)dismiss {
36
37}
38
39- (void)registerErrorCustomizer:(id<RCTErrorCustomizer>)errorCustomizer {
40
41}
42
43- (void)showError:(NSError *)error
44{
45  [self showErrorMessage:error.localizedDescription
46             withDetails:error.localizedFailureReason
47                   stack:error.userInfo[RCTJSStackTraceKey]
48             errorCookie:-1];
49}
50
51- (void)showErrorMessage:(NSString *)message
52{
53  [self showErrorMessage:message withParsedStack:nil isUpdate:NO errorCookie:-1];
54}
55
56- (void)showErrorMessage:(NSString *)message withDetails:(NSString *)details
57{
58  [self showErrorMessage:message withDetails:details stack:nil errorCookie:-1];
59}
60
61- (void)showErrorMessage:(NSString *)message
62             withDetails:(NSString *)details
63                   stack:(NSArray<RCTJSStackFrame *> *)stack
64             errorCookie:(int)errorCookie
65{
66  NSString *combinedMessage = message;
67  if (details) {
68    combinedMessage = [NSString stringWithFormat:@"%@\n\n%@", message, details];
69  }
70  [self showErrorMessage:combinedMessage withParsedStack:stack isUpdate:NO errorCookie:errorCookie];
71}
72
73- (void)showErrorMessage:(NSString *)message withRawStack:(NSString *)rawStack
74{
75  [self showErrorMessage:message withRawStack:rawStack errorCookie:-1];
76}
77
78- (void)showErrorMessage:(NSString *)message withRawStack:(NSString *)rawStack errorCookie:(int)errorCookie
79{
80  NSArray<RCTJSStackFrame *> *stack = [RCTJSStackFrame stackFramesWithLines:rawStack];
81  [self showErrorMessage:message withParsedStack:stack isUpdate:NO errorCookie:errorCookie];
82}
83
84- (void)showErrorMessage:(NSString *)message withStack:(NSArray<NSDictionary *> *)stack
85{
86  [self showErrorMessage:message withStack:stack errorCookie:-1];
87}
88
89- (void)updateErrorMessage:(NSString *)message withStack:(NSArray<NSDictionary *> *)stack
90{
91  [self updateErrorMessage:message withStack:stack errorCookie:-1];
92}
93
94- (void)showErrorMessage:(NSString *)message withStack:(NSArray<NSDictionary *> *)stack errorCookie:(int)errorCookie
95{
96  [self showErrorMessage:message
97         withParsedStack:[RCTJSStackFrame stackFramesWithDictionaries:stack]
98                isUpdate:NO
99             errorCookie:errorCookie];
100}
101
102- (void)updateErrorMessage:(NSString *)message withStack:(NSArray<NSDictionary *> *)stack errorCookie:(int)errorCookie
103{
104  [self showErrorMessage:message
105         withParsedStack:[RCTJSStackFrame stackFramesWithDictionaries:stack]
106                isUpdate:YES
107             errorCookie:errorCookie];
108}
109
110- (void)showErrorMessage:(NSString *)message withParsedStack:(NSArray<RCTJSStackFrame *> *)stack
111{
112  [self showErrorMessage:message withParsedStack:stack errorCookie:-1];
113}
114
115- (void)updateErrorMessage:(NSString *)message withParsedStack:(NSArray<RCTJSStackFrame *> *)stack
116{
117  [self updateErrorMessage:message withParsedStack:stack errorCookie:-1];
118}
119
120- (void)showErrorMessage:(NSString *)message
121         withParsedStack:(NSArray<RCTJSStackFrame *> *)stack
122             errorCookie:(int)errorCookie
123{
124  [self showErrorMessage:message withParsedStack:stack isUpdate:NO errorCookie:errorCookie];
125}
126
127- (void)updateErrorMessage:(NSString *)message
128           withParsedStack:(NSArray<RCTJSStackFrame *> *)stack
129               errorCookie:(int)errorCookie
130{
131  [self showErrorMessage:message withParsedStack:stack isUpdate:YES errorCookie:errorCookie];
132}
133
134- (void)showErrorMessage:(NSString *)message
135         withParsedStack:(NSArray<RCTJSStackFrame *> *)stack
136                isUpdate:(BOOL)isUpdate
137             errorCookie:(int)errorCookie
138{
139  if (isUpdate || errorCookie != -1) {
140    // These errors should be handled by LogBox
141    return;
142  }
143
144  // hide method was removed from the RCTLogBox interface in RN 0.64
145  if ([self.logBox respondsToSelector:@selector(hide)]) {
146    [self.logBox performSelector:@selector(hide)];
147  }
148
149  dispatch_async(dispatch_get_main_queue(), ^{
150    EXDevLauncherAppError *appError = [[EXDevLauncherAppError alloc] initWithMessage:[self stripAnsi:message] stack:stack];
151    [[EXDevLauncherController sharedInstance].errorManager showError:appError];
152  });
153}
154
155- (RCTRedBox *)unsafe_castToRCTRedBox {
156  return (RCTRedBox *)self;
157}
158
159- (NSString *)stripAnsi:(NSString *)text
160{
161  NSError *error = nil;
162  NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"\\x1b\\[[0-9;]*m"
163                                                                         options:NSRegularExpressionCaseInsensitive
164                                                                           error:&error];
165  return [regex stringByReplacingMatchesInString:text options:0 range:NSMakeRange(0, [text length]) withTemplate:@""];
166}
167
168@end
169