11
11
import Platform from '../Utilities/Platform' ;
12
12
import RCTLog from '../Utilities/RCTLog' ;
13
13
14
- import type { IgnorePattern } from './Data/LogBoxData' ;
14
+ import type { IgnorePattern , LogData } from './Data/LogBoxData' ;
15
+ import type { ExtendedExceptionData } from './Data/parseLogBoxLog' ;
16
+
17
+ export type { LogData , ExtendedExceptionData , IgnorePattern } ;
15
18
16
19
let LogBox ;
17
20
21
+ interface ILogBox {
22
+ install ( ) : void ;
23
+ uninstall ( ) : void ;
24
+ isInstalled ( ) : boolean ;
25
+ ignoreLogs ( $ReadOnlyArray < IgnorePattern > ) : void ;
26
+ ignoreAllLogs ( ?boolean ) : void ;
27
+ clearAllLogs ( ) : void ;
28
+ addLog ( log : LogData ) : void ;
29
+ addException ( error : ExtendedExceptionData ) : void ;
30
+ }
31
+
18
32
/**
19
33
* LogBox displays logs in the app.
20
34
*/
21
35
if ( __DEV__ ) {
22
36
const LogBoxData = require ( './Data/LogBoxData' ) ;
23
37
const { parseLogBoxLog, parseInterpolation} = require ( './Data/parseLogBoxLog' ) ;
24
38
25
- // LogBox needs to insert itself early,
26
- // in order to access the component stacks appended by React DevTools.
27
- const { error, warn} = console ;
28
- let errorImpl = error . bind ( console ) ;
29
- let warnImpl = warn . bind ( console ) ;
39
+ let originalConsoleError ;
40
+ let originalConsoleWarn ;
41
+ let consoleErrorImpl ;
42
+ let consoleWarnImpl ;
30
43
31
- ( console : any ) . error = function ( ...args ) {
32
- errorImpl ( ...args ) ;
33
- } ;
34
- ( console : any ) . warn = function ( ...args ) {
35
- warnImpl ( ...args ) ;
36
- } ;
44
+ let isLogBoxInstalled : boolean = false ;
37
45
38
46
LogBox = {
39
- ignoreLogs : ( patterns : $ReadOnlyArray < IgnorePattern > ) : void => {
40
- LogBoxData. addIgnorePatterns ( patterns ) ;
41
- } ,
47
+ install ( ) : void {
48
+ if ( isLogBoxInstalled ) {
49
+ return ;
50
+ }
42
51
43
- ignoreAllLogs : ( value ?: ?boolean ) : void => {
44
- LogBoxData . setDisabled ( value == null ? true : value ) ;
45
- } ,
52
+ isLogBoxInstalled = true ;
46
53
47
- uninstall : ( ) : void => {
48
- errorImpl = error ;
49
- warnImpl = warn ;
50
- delete ( console : any ) . disableLogBox ;
51
- } ,
52
-
53
- install : ( ) : void => {
54
54
// Trigger lazy initialization of module.
55
55
require ( '../NativeModules/specs/NativeLogBox' ) ;
56
56
57
- errorImpl = function ( ...args ) {
58
- registerError ( ...args ) ;
59
- } ;
57
+ // IMPORTANT: we only overwrite `console.error` and `console.warn` once.
58
+ // When we uninstall we keep the same reference and only change its
59
+ // internal implementation
60
+ const isFirstInstall = originalConsoleError == null ;
61
+ if ( isFirstInstall ) {
62
+ originalConsoleError = console . error . bind ( console ) ;
63
+ originalConsoleWarn = console . warn . bind ( console ) ;
64
+
65
+ // $FlowExpectedError[cannot-write]
66
+ console . error = ( ...args ) => {
67
+ consoleErrorImpl ( ...args ) ;
68
+ } ;
69
+ // $FlowExpectedError[cannot-write]
70
+ console . warn = ( ...args ) => {
71
+ consoleWarnImpl ( ...args ) ;
72
+ } ;
73
+ }
60
74
61
- warnImpl = function ( ...args ) {
62
- registerWarning ( ...args ) ;
63
- } ;
75
+ consoleErrorImpl = registerError ;
76
+ consoleWarnImpl = registerWarning ;
64
77
65
78
if ( ( console : any ) . disableYellowBox === true ) {
66
79
LogBoxData . setDisabled ( true ) ;
@@ -88,6 +101,50 @@ if (__DEV__) {
88
101
registerWarning ( ...args ) ;
89
102
} ) ;
90
103
} ,
104
+
105
+ uninstall ( ) : void {
106
+ if ( ! isLogBoxInstalled ) {
107
+ return ;
108
+ }
109
+
110
+ isLogBoxInstalled = false ;
111
+
112
+ // IMPORTANT: we don't re-assign to `console` in case the method has been
113
+ // decorated again after installing LogBox. E.g.:
114
+ // Before uninstalling: original > LogBox > OtherErrorHandler
115
+ // After uninstalling: original > LogBox (noop) > OtherErrorHandler
116
+ consoleErrorImpl = originalConsoleError ;
117
+ consoleWarnImpl = originalConsoleWarn ;
118
+ delete ( console : any ) . disableLogBox ;
119
+ } ,
120
+
121
+ isInstalled ( ) : boolean {
122
+ return isLogBoxInstalled ;
123
+ } ,
124
+
125
+ ignoreLogs ( patterns : $ReadOnlyArray < IgnorePattern > ) : void {
126
+ LogBoxData. addIgnorePatterns ( patterns ) ;
127
+ } ,
128
+
129
+ ignoreAllLogs ( value ?: ?boolean ) : void {
130
+ LogBoxData . setDisabled ( value == null ? true : value ) ;
131
+ } ,
132
+
133
+ clearAllLogs ( ) : void {
134
+ LogBoxData. clear ( ) ;
135
+ } ,
136
+
137
+ addLog ( log : LogData ) : void {
138
+ if ( isLogBoxInstalled ) {
139
+ LogBoxData . addLog ( log ) ;
140
+ }
141
+ } ,
142
+
143
+ addException ( error : ExtendedExceptionData ) : void {
144
+ if ( isLogBoxInstalled ) {
145
+ LogBoxData . addException ( error ) ;
146
+ }
147
+ } ,
91
148
} ;
92
149
93
150
const isRCTLogAdviceWarning = ( ...args ) => {
@@ -103,7 +160,7 @@ if (__DEV__) {
103
160
const registerWarning = ( ...args ) : void => {
104
161
// Let warnings within LogBox itself fall through.
105
162
if ( LogBoxData . isLogBoxErrorMessage ( String ( args [ 0 ] ) ) ) {
106
- error . call ( console , ...args ) ;
163
+ originalConsoleError ( ...args ) ;
107
164
return ;
108
165
}
109
166
@@ -113,7 +170,7 @@ if (__DEV__) {
113
170
114
171
if ( ! LogBoxData . isMessageIgnored ( message . content ) ) {
115
172
// Be sure to pass LogBox warnings through.
116
- warn . call ( console , ...args ) ;
173
+ originalConsoleWarn ( ...args ) ;
117
174
118
175
LogBoxData . addLog ( {
119
176
level : 'warn' ,
@@ -131,7 +188,7 @@ if (__DEV__) {
131
188
const registerError = ( ...args ) : void => {
132
189
// Let errors within LogBox itself fall through.
133
190
if ( LogBoxData . isLogBoxErrorMessage ( args [ 0 ] ) ) {
134
- error . call ( console , ...args ) ;
191
+ originalConsoleError ( ...args ) ;
135
192
return ;
136
193
}
137
194
@@ -144,7 +201,7 @@ if (__DEV__) {
144
201
//
145
202
// The 'warning' module needs to be handled here because React internally calls
146
203
// `console.error('Warning: ')` with the component stack already included.
147
- error . call ( console , ...args ) ;
204
+ originalConsoleError ( ...args ) ;
148
205
return ;
149
206
}
150
207
@@ -169,7 +226,7 @@ if (__DEV__) {
169
226
// Interpolate the message so they are formatted for adb and other CLIs.
170
227
// This is different than the message.content above because it includes component stacks.
171
228
const interpolated = parseInterpolation ( args ) ;
172
- error . call ( console , interpolated . message . content ) ;
229
+ originalConsoleError ( interpolated . message . content ) ;
173
230
174
231
LogBoxData . addLog ( {
175
232
level,
@@ -184,28 +241,38 @@ if (__DEV__) {
184
241
} ;
185
242
} else {
186
243
LogBox = {
187
- ignoreLogs : ( patterns : $ReadOnlyArray < IgnorePattern > ) : void => {
244
+ install ( ) : void {
245
+ // Do nothing.
246
+ } ,
247
+
248
+ uninstall ( ) : void {
249
+ // Do nothing.
250
+ } ,
251
+
252
+ isInstalled ( ) : boolean {
253
+ return false ;
254
+ } ,
255
+
256
+ ignoreLogs ( patterns : $ReadOnlyArray < IgnorePattern > ) : void {
257
+ // Do nothing.
258
+ } ,
259
+
260
+ ignoreAllLogs ( value ?: ?boolean ) : void {
188
261
// Do nothing.
189
262
} ,
190
263
191
- ignoreAllLogs : ( value ?: ? boolean ) : void => {
264
+ clearAllLogs ( ) : void {
192
265
// Do nothing.
193
266
} ,
194
267
195
- install : ( ) : void => {
268
+ addLog ( log : LogData ) : void {
196
269
// Do nothing.
197
270
} ,
198
271
199
- uninstall : ( ) : void => {
272
+ addException ( error : ExtendedExceptionData ) : void {
200
273
// Do nothing.
201
274
} ,
202
275
} ;
203
276
}
204
277
205
- module . exports = ( LogBox : {
206
- ignoreLogs ( $ReadOnlyArray < IgnorePattern > ) : void ,
207
- ignoreAllLogs ( ?boolean ) : void ,
208
- install ( ) : void ,
209
- uninstall ( ) : void ,
210
- ...
211
- } ) ;
278
+ module . exports = ( LogBox : ILogBox ) ;
0 commit comments