@honeybadger-io/react-native 0.0.11 → 4.7.0

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/index.js CHANGED
@@ -13,10 +13,10 @@ const HoneybadgerNativeModule = NativeModules.HoneybadgerReactNative;
13
13
  let _apiKey = null;
14
14
  let _initialized = false;
15
15
  let _context = {};
16
- let _logLevel = "warning"; // "error", "warning", "debug"
16
+ let _logLevel = 'warning'; // "error", "warning", "debug"
17
17
  let _previousJSGlobalExceptionHandler = null;
18
- let _revision = "";
19
- let _projectRoot = "";
18
+ let _revision = '';
19
+ let _projectRoot = '';
20
20
  let _reportErrors = true;
21
21
 
22
22
 
@@ -26,143 +26,143 @@ let _reportErrors = true;
26
26
  // ----------------------------------------------------------------------------
27
27
  const honeybadger = {
28
28
 
29
- /**
29
+ /**
30
30
  * Initialize and configure the Honeybadger React Native library.
31
31
  * @param {string} apiKey - Your Honeybadger API key.
32
32
  * @param {boolean} [reportErrors=true] reportErrors - Whether to send error reports to Honeybadger (disable for dev environments, etc.)
33
33
  * @param {string=} revision - The git revision of the current build.
34
34
  * @param {string=} projectRoot - The path to the project root.
35
35
  */
36
- configure ( apiKey, reportErrors = true, revision = '', projectRoot = '' )
36
+ configure ( apiKey, reportErrors = true, revision = '', projectRoot = '' )
37
+ {
38
+ if ( !isValidAPIKey(apiKey) )
37
39
  {
38
- if ( !isValidAPIKey(apiKey) )
39
- {
40
- informUserOfInvalidAPIKey();
41
- return;
42
- }
43
-
44
- _apiKey = apiKey.trim();
45
- _revision = (revision || '').trim();
46
- _projectRoot = (projectRoot || '').trim();
47
- _reportErrors = reportErrors;
48
-
49
- if ( !_initialized )
50
- {
51
- setNativeExceptionHandler();
52
- setJavaScriptErrorHandler();
53
- _initialized = true;
54
- }
55
- },
40
+ informUserOfInvalidAPIKey();
41
+ return;
42
+ }
56
43
 
57
- /**
44
+ _apiKey = apiKey.trim();
45
+ _revision = (revision || '').trim();
46
+ _projectRoot = (projectRoot || '').trim();
47
+ _reportErrors = reportErrors;
48
+
49
+ if ( !_initialized )
50
+ {
51
+ setNativeExceptionHandler();
52
+ setJavaScriptErrorHandler();
53
+ _initialized = true;
54
+ }
55
+ },
56
+
57
+ /**
58
58
  * Send any kind of error, exception, object, String, etc. to Honeybadger.
59
59
  * @param {string|object} err - The error string or object.
60
60
  * @param {string|object} additionalData - Additional data to include with the error.
61
61
  */
62
- notify ( err, additionalData )
63
- {
64
- if ( !isValidAPIKey(_apiKey) ) {
65
- informUserOfInvalidAPIKey();
66
- return;
67
- }
68
-
69
- if ( !err || (isString(err) && err.trim().length === 0) || (isObject(err) && err.length === 0) ) {
70
- logError("Honeybadger.notify() - invalid error");
71
- return;
72
- }
73
-
74
- if ( isString(err) ) {
75
- err = {
76
- 'message' : err.trim(),
77
- };
78
- }
79
-
80
- if ( isStringWithValue(additionalData) ) {
81
- additionalData = {
82
- 'additionalData' : additionalData.trim(),
83
- };
84
- }
85
- else if ( !isObject(additionalData) ) {
86
- additionalData = {};
87
- }
88
-
89
- const errName = safeStringFromField(err, 'name', 'Error via notify()');
90
- const errMsg = safeStringFromField(err, 'message', 'Unknown error message');
91
-
92
- let contextForThisError = {};
93
- Object.assign(contextForThisError, _context);
94
- Object.assign(contextForThisError, additionalData);
95
-
96
- let payloadData = {
97
- errorClass : `React Native ${(Platform.OS === 'ios' ? 'iOS' : 'Android')} ${errName}`,
98
- errorMsg : errMsg,
99
- details: {
100
- initialHandler: 'notify',
101
- },
102
- context: contextForThisError,
103
- };
104
-
105
- let backTrace = backTraceFromJavaScriptError(err);
106
-
107
- if ( arrayHasValues(backTrace.framesFromComponentStack) ) {
108
- payloadData.backTrace = backTrace.framesFromComponentStack;
109
- payloadData.details.primaryBackTraceSource = 'ReactNativeComponentStack';
110
- if ( arrayHasValues(backTrace.framesFromJavaScriptErrorStack) ) {
111
- payloadData.details.javaScriptStackTrace = backTrace.framesFromJavaScriptErrorStack;
112
- }
113
- } else if ( arrayHasValues(backTrace.framesFromJavaScriptErrorStack) ) {
114
- payloadData.backTrace = backTrace.framesFromJavaScriptErrorStack;
115
- payloadData.details.primaryBackTraceSource = 'JavaScriptErrorStack';
116
- }
117
-
118
- sendToHoneybadger(buildPayload(payloadData));
119
- },
62
+ notify ( err, additionalData )
63
+ {
64
+ if ( !isValidAPIKey(_apiKey) ) {
65
+ informUserOfInvalidAPIKey();
66
+ return;
67
+ }
68
+
69
+ if ( !err || (isString(err) && err.trim().length === 0) || (isObject(err) && err.length === 0) ) {
70
+ logError('Honeybadger.notify() - invalid error');
71
+ return;
72
+ }
73
+
74
+ if ( isString(err) ) {
75
+ err = {
76
+ 'message' : err.trim(),
77
+ };
78
+ }
79
+
80
+ if ( isStringWithValue(additionalData) ) {
81
+ additionalData = {
82
+ 'additionalData' : additionalData.trim(),
83
+ };
84
+ }
85
+ else if ( !isObject(additionalData) ) {
86
+ additionalData = {};
87
+ }
88
+
89
+ const errName = safeStringFromField(err, 'name', 'Error via notify()');
90
+ const errMsg = safeStringFromField(err, 'message', 'Unknown error message');
91
+
92
+ let contextForThisError = {};
93
+ Object.assign(contextForThisError, _context);
94
+ Object.assign(contextForThisError, additionalData);
95
+
96
+ let payloadData = {
97
+ errorClass : `React Native ${(Platform.OS === 'ios' ? 'iOS' : 'Android')} ${errName}`,
98
+ errorMsg : errMsg,
99
+ details: {
100
+ initialHandler: 'notify',
101
+ },
102
+ context: contextForThisError,
103
+ };
104
+
105
+ let backTrace = backTraceFromJavaScriptError(err);
106
+
107
+ if ( arrayHasValues(backTrace.framesFromComponentStack) ) {
108
+ payloadData.backTrace = backTrace.framesFromComponentStack;
109
+ payloadData.details.primaryBackTraceSource = 'ReactNativeComponentStack';
110
+ if ( arrayHasValues(backTrace.framesFromJavaScriptErrorStack) ) {
111
+ payloadData.details.javaScriptStackTrace = backTrace.framesFromJavaScriptErrorStack;
112
+ }
113
+ } else if ( arrayHasValues(backTrace.framesFromJavaScriptErrorStack) ) {
114
+ payloadData.backTrace = backTrace.framesFromJavaScriptErrorStack;
115
+ payloadData.details.primaryBackTraceSource = 'JavaScriptErrorStack';
116
+ }
117
+
118
+ sendToHoneybadger(buildPayload(payloadData));
119
+ },
120
120
 
121
121
 
122
- /**
122
+ /**
123
123
  * Include additional data whenever an error or an exception occurs. This can be called as many times as needed. New context data will be merged with any previously-set context data.
124
124
  * @param {object} context - Additional data to include with all errors and exceptions.
125
125
  */
126
- setContext ( context )
127
- {
128
- if ( isObject(context) ) {
129
- Object.assign(_context, context);
130
- }
131
- },
126
+ setContext ( context )
127
+ {
128
+ if ( isObject(context) ) {
129
+ Object.assign(_context, context);
130
+ }
131
+ },
132
132
 
133
133
 
134
- /**
134
+ /**
135
135
  * Clears/resets any data previously set through setContext().
136
136
  * @param {object=} context - Optional new context to set.
137
137
  */
138
- resetContext ( context )
139
- {
140
- _context = (isObject(context) ? context : {});
141
- },
138
+ resetContext ( context )
139
+ {
140
+ _context = (isObject(context) ? context : {});
141
+ },
142
142
 
143
143
 
144
- /**
145
- * Sets the logging level for the Honeybadger library.
144
+ /**
145
+ * Sets the logging level for the Honeybadger library.
146
146
  * @param {('debug'|'warning'|'error')} [level=warning] - The logging level.
147
147
  */
148
- setLogLevel ( level = "warning" )
148
+ setLogLevel ( level = 'warning' )
149
+ {
150
+ if ( !level ) {
151
+ return;
152
+ }
153
+
154
+ switch (level.toLowerCase())
149
155
  {
150
- if ( !level ) {
151
- return;
152
- }
153
-
154
- switch (level.toLowerCase())
155
- {
156
- case "debug":
157
- case "warning":
158
- case "error":
159
- _logLevel = level.toLowerCase();
160
- break;
161
-
162
- default:
163
- logWarning("Honeybadger: Log level should be one of 'debug', 'warning', or 'error'.");
164
- }
156
+ case 'debug':
157
+ case 'warning':
158
+ case 'error':
159
+ _logLevel = level.toLowerCase();
160
+ break;
161
+
162
+ default:
163
+ logWarning("Honeybadger: Log level should be one of 'debug', 'warning', or 'error'.");
165
164
  }
165
+ }
166
166
  };
167
167
 
168
168
 
@@ -175,177 +175,178 @@ export default honeybadger;
175
175
  // -----------------------------------------------------------------------------
176
176
 
177
177
  function informUserOfInvalidAPIKey() {
178
- logError('Please initialize Honeybadger by calling configure() with a valid Honeybadger.io API key.');
178
+ logError('Please initialize Honeybadger by calling configure() with a valid Honeybadger.io API key.');
179
179
  }
180
180
 
181
181
 
182
182
  function isValidAPIKey(apiKey) {
183
- return apiKey && apiKey.trim().length > 0;
183
+ return apiKey && apiKey.trim().length > 0;
184
184
  }
185
185
 
186
186
 
187
187
 
188
- function setJavaScriptErrorHandler()
188
+ function setJavaScriptErrorHandler()
189
189
  {
190
- logDebug("Setting up the JavaScript global error handler.");
191
-
192
- _previousJSGlobalExceptionHandler = global.ErrorUtils.getGlobalHandler();
190
+ logDebug('Setting up the JavaScript global error handler.');
193
191
 
194
- global.ErrorUtils.setGlobalHandler(function(err, isFatal) {
195
- logDebug("JavaScript global error handler triggered.");
192
+ _previousJSGlobalExceptionHandler = global.ErrorUtils.getGlobalHandler();
196
193
 
197
- onJavaScriptError(err, {
198
- initialHandler: 'Global JavaScript Error Handler',
199
- });
194
+ global.ErrorUtils.setGlobalHandler(function(err, isFatal) {
195
+ logDebug('JavaScript global error handler triggered.');
200
196
 
201
- // Allowing the default error handler to process the error after
202
- // we're done with it will show the useful RN red info box in dev.
203
- if ( _previousJSGlobalExceptionHandler && _previousJSGlobalExceptionHandler != this ) {
204
- logDebug("Passing error to previous error handler.");
205
- _previousJSGlobalExceptionHandler(err, isFatal);
206
- }
197
+ onJavaScriptError(err, {
198
+ initialHandler: 'Global JavaScript Error Handler',
207
199
  });
200
+
201
+ // Allowing the default error handler to process the error after
202
+ // we're done with it will show the useful RN red info box in dev.
203
+ if ( _previousJSGlobalExceptionHandler && _previousJSGlobalExceptionHandler != this ) {
204
+ logDebug('Passing error to previous error handler.');
205
+ _previousJSGlobalExceptionHandler(err, isFatal);
206
+ }
207
+ });
208
208
  }
209
209
 
210
210
 
211
211
 
212
212
  function setNativeExceptionHandler() {
213
- if ( !HoneybadgerNativeModule ) {
214
- logError('Honeybadger: The native module was not found. Please review the installation instructions.');
215
- return;
216
- }
213
+ if ( !HoneybadgerNativeModule ) {
214
+ logError('Honeybadger: The native module was not found. Please review the installation instructions.');
215
+ return;
216
+ }
217
217
 
218
- logDebug("Starting HoneyBadger native module.");
219
- HoneybadgerNativeModule.start();
218
+ logDebug('Starting HoneyBadger native module.');
219
+ HoneybadgerNativeModule.start();
220
220
 
221
- const nativeEventEmitter = new NativeEventEmitter(HoneybadgerNativeModule);
221
+ const nativeEventEmitter = new NativeEventEmitter(HoneybadgerNativeModule);
222
222
 
223
- logDebug("Listening for native exceptions...");
224
- nativeEventEmitter.addListener('native-exception-event', function(data) {
225
- switch ( Platform.OS ) {
226
- case 'ios': onNativeIOSException(data); break;
227
- case 'android': onNativeAndroidException(data); break;
228
- }
229
- });
223
+ logDebug('Listening for native exceptions...');
224
+ nativeEventEmitter.addListener('native-exception-event', function(data) {
225
+ switch ( Platform.OS ) {
226
+ case 'ios': onNativeIOSException(data); break;
227
+ case 'android': onNativeAndroidException(data); break;
228
+ }
229
+ });
230
230
  }
231
231
 
232
232
 
233
233
 
234
234
  function sendToHoneybadger(payload) {
235
- if ( !payload || !isValidAPIKey(_apiKey) || !_reportErrors ) {
236
- return;
237
- }
235
+ if ( !payload || !isValidAPIKey(_apiKey) || !_reportErrors ) {
236
+ return;
237
+ }
238
238
 
239
239
 
240
- logDebug("Sending error report to Honeybadger...");
241
-
242
- const params = {
243
- method: 'POST',
244
- headers: {
245
- 'Content-Type' : 'application/json',
246
- 'Accept' : 'text/json, application/json',
247
- 'X-API-Key' : _apiKey,
248
- 'User-Agent' : buildUserAgent(),
249
- },
250
- body: JSON.stringify(payload)
251
- };
240
+ logDebug('Sending error report to Honeybadger...');
252
241
 
253
- fetch('https://api.honeybadger.io/v1/notices/js', params).then(response => {
254
- if ( !response.ok ) {
255
- logDebug(`Failed to post error to Honeybadger: ${response.status}`);
256
- logDebug(response);
257
- } else {
258
- logDebug('Successful post to Honeybadger.');
259
- logDebug(response);
260
- }
261
- });
242
+ const params = {
243
+ method: 'POST',
244
+ headers: {
245
+ 'Content-Type' : 'application/json',
246
+ 'Accept' : 'text/json, application/json',
247
+ 'X-API-Key' : _apiKey,
248
+ 'User-Agent' : buildUserAgent(),
249
+ },
250
+ body: JSON.stringify(payload)
251
+ };
252
+
253
+ fetch('https://api.honeybadger.io/v1/notices/js', params).then(response => {
254
+ if ( !response.ok ) {
255
+ logDebug(`Failed to post error to Honeybadger: ${response.status}`);
256
+ logDebug(response);
257
+ } else {
258
+ logDebug('Successful post to Honeybadger.');
259
+ logDebug(response);
260
+ }
261
+ });
262
262
  }
263
263
 
264
264
 
265
265
 
266
266
  function buildUserAgent() {
267
- let reactNativeVersion = `${Platform.constants.reactNativeVersion.major}.${Platform.constants.reactNativeVersion.minor}.${Platform.constants.reactNativeVersion.patch}`;
268
- const nativePlatformName = Platform.constants.systemName || (Platform.OS === 'ios' ? 'iOS' : 'Android');
269
- const nativePlatformVersion = Platform.constants.osVersion || '';
270
- let nativePlatform = `${nativePlatformName} ${nativePlatformVersion}`;
271
- return `${pkg.name} ${pkg.version}; ${reactNativeVersion}; ${nativePlatform}`;
267
+ let reactNativeVersion = `${Platform.constants.reactNativeVersion.major}.${Platform.constants.reactNativeVersion.minor}.${Platform.constants.reactNativeVersion.patch}`;
268
+ const nativePlatformName = Platform.constants.systemName || (Platform.OS === 'ios' ? 'iOS' : 'Android');
269
+ const nativePlatformVersion = Platform.constants.osVersion || '';
270
+ let nativePlatform = `${nativePlatformName} ${nativePlatformVersion}`;
271
+ return `${pkg.name} ${pkg.version}; ${reactNativeVersion}; ${nativePlatform}`;
272
272
  }
273
273
 
274
274
 
275
275
 
276
276
  function buildPayload ( data ) {
277
- let payload = {
278
- notifier : {
279
- name : pkg.name,
280
- url : pkg.repository.url,
281
- version : pkg.version,
282
- },
283
- error : {
284
- class : data.errorClass || 'React Native Error',
285
- message : data.errorMsg || 'Unknown Error',
286
- backtrace : data.backTrace,
287
- },
288
- request : {
289
- context: data.context,
290
- },
291
- server : {
292
- environment_name: (__DEV__ ? "development" : "production"),
293
- project_root: _projectRoot || '',
294
- revision: _revision || ''
295
- },
296
- };
277
+ let payload = {
278
+ notifier : {
279
+ name : pkg.name,
280
+ url : pkg.repository.url,
281
+ version : pkg.version,
282
+ },
283
+ error : {
284
+ class : data.errorClass || 'React Native Error',
285
+ message : data.errorMsg || 'Unknown Error',
286
+ backtrace : data.backTrace,
287
+ },
288
+ request : {
289
+ context: data.context,
290
+ },
291
+ server : {
292
+ // eslint-disable-next-line no-undef
293
+ environment_name: (__DEV__ ? 'development' : 'production'),
294
+ project_root: _projectRoot || '',
295
+ revision: _revision || ''
296
+ },
297
+ };
297
298
 
298
- if ( data.details && data.details.length > 0 ) {
299
- payload.details = {
300
- 'React Native' : data.details
301
- }
299
+ if ( data.details && data.details.length > 0 ) {
300
+ payload.details = {
301
+ 'React Native' : data.details
302
302
  }
303
+ }
303
304
 
304
- return payload;
305
+ return payload;
305
306
  }
306
307
 
307
308
 
308
309
 
309
310
  function framesFromComponentStack(str) {
310
- str = str || '';
311
- let frames = [];
312
- const regex = /^\s*in\s(\S+)(\s\(at\s(\S+):(\S+)\)\s*$)?/gm;
313
- let match;
314
- while ( (match = regex.exec(str)) !== null ) {
315
- if ( match.index === regex.lastIndex) {
316
- regex.lastIndex++;
317
- }
318
- frames.push({
319
- method: match && match.length > 1 ? match[1] : '',
320
- file: match && match.length > 3 ? match[3] : '',
321
- number: match && match.length > 4 ? match[4] : '',
322
- });
311
+ str = str || '';
312
+ let frames = [];
313
+ const regex = /^\s*in\s(\S+)(\s\(at\s(\S+):(\S+)\)\s*$)?/gm;
314
+ let match;
315
+ while ( (match = regex.exec(str)) !== null ) {
316
+ if ( match.index === regex.lastIndex) {
317
+ regex.lastIndex++;
323
318
  }
324
- return frames;
319
+ frames.push({
320
+ method: match && match.length > 1 ? match[1] : '',
321
+ file: match && match.length > 3 ? match[3] : '',
322
+ number: match && match.length > 4 ? match[4] : '',
323
+ });
324
+ }
325
+ return frames;
325
326
  }
326
327
 
327
328
 
328
329
 
329
330
  function logDebug(data) {
330
- if ( data && _logLevel.toLowerCase() === "debug" ) {
331
- console.log(data);
332
- }
331
+ if ( data && _logLevel.toLowerCase() === 'debug' ) {
332
+ console.log(data);
333
+ }
333
334
  }
334
335
 
335
336
 
336
337
 
337
338
  function logWarning(data) {
338
- if ( data && _logLevel.toLowerCase() === "warning" || _logLevel.toLowerCase() === "error" ) {
339
- console.warn(data);
340
- }
339
+ if ( data && _logLevel.toLowerCase() === 'warning' || _logLevel.toLowerCase() === 'error' ) {
340
+ console.warn(data);
341
+ }
341
342
  }
342
343
 
343
344
 
344
345
 
345
346
  function logError(data) {
346
- if ( data ) {
347
- console.error(data);
348
- }
347
+ if ( data ) {
348
+ console.error(data);
349
+ }
349
350
  }
350
351
 
351
352
 
@@ -355,90 +356,90 @@ function logError(data) {
355
356
  // ----------------------------------------------------------------------------
356
357
 
357
358
  function onJavaScriptError(err, data) {
358
- if ( !err ) {
359
- return;
360
- }
361
-
362
- let payloadData = {
363
- errorClass: `React Native ${(Platform.OS === 'ios' ? 'iOS' : 'Android')} Error`,
364
- errorMsg: errorMessageFromJavaScriptError(err),
365
- details: {
366
- initialHandler: data.initialHandler || '',
367
- },
368
- context: _context || {},
369
- };
359
+ if ( !err ) {
360
+ return;
361
+ }
362
+
363
+ let payloadData = {
364
+ errorClass: `React Native ${(Platform.OS === 'ios' ? 'iOS' : 'Android')} Error`,
365
+ errorMsg: errorMessageFromJavaScriptError(err),
366
+ details: {
367
+ initialHandler: data.initialHandler || '',
368
+ },
369
+ context: _context || {},
370
+ };
370
371
 
371
- let backTrace = backTraceFromJavaScriptError(err);
372
+ let backTrace = backTraceFromJavaScriptError(err);
372
373
 
373
- if ( arrayHasValues(backTrace.framesFromComponentStack) ) {
374
- payloadData.backTrace = backTrace.framesFromComponentStack;
375
- payloadData.details.primaryBackTraceSource = 'ReactNativeComponentStack';
376
- if ( arrayHasValues(backTrace.framesFromJavaScriptErrorStack) ) {
377
- payloadData.details.javaScriptStackTrace = backTrace.framesFromJavaScriptErrorStack;
378
- }
379
- } else if ( arrayHasValues(backTrace.framesFromJavaScriptErrorStack) ) {
380
- payloadData.backTrace = backTrace.framesFromJavaScriptErrorStack;
381
- payloadData.details.primaryBackTraceSource = 'JavaScriptErrorStack';
374
+ if ( arrayHasValues(backTrace.framesFromComponentStack) ) {
375
+ payloadData.backTrace = backTrace.framesFromComponentStack;
376
+ payloadData.details.primaryBackTraceSource = 'ReactNativeComponentStack';
377
+ if ( arrayHasValues(backTrace.framesFromJavaScriptErrorStack) ) {
378
+ payloadData.details.javaScriptStackTrace = backTrace.framesFromJavaScriptErrorStack;
382
379
  }
380
+ } else if ( arrayHasValues(backTrace.framesFromJavaScriptErrorStack) ) {
381
+ payloadData.backTrace = backTrace.framesFromJavaScriptErrorStack;
382
+ payloadData.details.primaryBackTraceSource = 'JavaScriptErrorStack';
383
+ }
383
384
 
384
- sendToHoneybadger(buildPayload(payloadData));
385
+ sendToHoneybadger(buildPayload(payloadData));
385
386
  }
386
387
 
387
388
 
388
389
 
389
390
  function errorMessageFromJavaScriptError(err) {
390
- if ( !err ) {
391
- return '';
392
- }
391
+ if ( !err ) {
392
+ return '';
393
+ }
393
394
 
394
- if ( isStringWithValue(err) ) {
395
- return err.trim();
396
- }
397
- else if ( isObject(err) && err.message && err.message.length > 0 ) {
398
- return err.message;
399
- }
395
+ if ( isStringWithValue(err) ) {
396
+ return err.trim();
397
+ }
398
+ else if ( isObject(err) && err.message && err.message.length > 0 ) {
399
+ return err.message;
400
+ }
400
401
 
401
- return '';
402
+ return '';
402
403
  }
403
404
 
404
405
 
405
406
 
406
407
  function backTraceFromJavaScriptError(err) {
407
- return {
408
- framesFromComponentStack: ( isObjectWithField(err, 'componentStack') ? framesFromComponentStack(err.componentStack) : []),
409
- framesFromJavaScriptErrorStack: ( isObjectWithField(err, 'stack') ? framesFromJavaScriptErrorStack(err.stack) : []),
410
- };
408
+ return {
409
+ framesFromComponentStack: ( isObjectWithField(err, 'componentStack') ? framesFromComponentStack(err.componentStack) : []),
410
+ framesFromJavaScriptErrorStack: ( isObjectWithField(err, 'stack') ? framesFromJavaScriptErrorStack(err.stack) : []),
411
+ };
411
412
  }
412
413
 
413
414
 
414
415
 
415
416
  function framesFromJavaScriptErrorStack(stack) {
416
- let frames = [];
417
- let lines = stack.split('\n');
418
- const javaScriptCoreRe = /^\s*(?:([^@]*)(?:\((.*?)\))?@)?(\S.*?):(\d+)(?::(\d+))?\s*$/i;
419
- for ( let i = 0 ; i < lines.length ; ++i ) {
420
- const line = lines[i];
421
- const parts = javaScriptCoreRe.exec(line);
422
- if ( parts ) {
423
- frames.push({
424
- file: parts[3] || '',
425
- method: parts[1] || '',
426
- number: (parts[4] ? +parts[4] : ''),
427
- column: (parts[5] ? +parts[5] : ''),
428
- });
429
- } else if ( line.indexOf('[native code]') !== -1 ) {
430
- let parts = line.split('@');
431
- if ( parts && parts.length === 2 ) {
432
- frames.push({
433
- file: parts[1],
434
- method: parts[0],
435
- number: '',
436
- column: '',
437
- });
438
- }
439
- }
417
+ let frames = [];
418
+ let lines = stack.split('\n');
419
+ const javaScriptCoreRe = /^\s*(?:([^@]*)(?:\((.*?)\))?@)?(\S.*?):(\d+)(?::(\d+))?\s*$/i;
420
+ for ( let i = 0 ; i < lines.length ; ++i ) {
421
+ const line = lines[i];
422
+ const parts = javaScriptCoreRe.exec(line);
423
+ if ( parts ) {
424
+ frames.push({
425
+ file: parts[3] || '',
426
+ method: parts[1] || '',
427
+ number: (parts[4] ? +parts[4] : ''),
428
+ column: (parts[5] ? +parts[5] : ''),
429
+ });
430
+ } else if ( line.indexOf('[native code]') !== -1 ) {
431
+ let parts = line.split('@');
432
+ if ( parts && parts.length === 2 ) {
433
+ frames.push({
434
+ file: parts[1],
435
+ method: parts[0],
436
+ number: '',
437
+ column: '',
438
+ });
439
+ }
440
440
  }
441
- return frames;
441
+ }
442
+ return frames;
442
443
  }
443
444
 
444
445
 
@@ -449,34 +450,34 @@ function framesFromJavaScriptErrorStack(stack) {
449
450
 
450
451
  function onNativeAndroidException(data)
451
452
  {
452
- let payloadData = {
453
- errorClass: `React Native Android ${data.type}`,
454
- errorMsg: data.message || '',
455
- context: _context || {},
456
- };
453
+ let payloadData = {
454
+ errorClass: `React Native Android ${data.type}`,
455
+ errorMsg: data.message || '',
456
+ context: _context || {},
457
+ };
457
458
 
458
- let backTrace = backTraceFromAndroidException(data);
459
+ let backTrace = backTraceFromAndroidException(data);
459
460
 
460
- if ( arrayHasValues(backTrace) ) {
461
- payloadData.backTrace = backTrace;
462
- }
461
+ if ( arrayHasValues(backTrace) ) {
462
+ payloadData.backTrace = backTrace;
463
+ }
463
464
 
464
- sendToHoneybadger(buildPayload(payloadData));
465
+ sendToHoneybadger(buildPayload(payloadData));
465
466
  }
466
467
 
467
468
 
468
469
 
469
470
  function backTraceFromAndroidException(data)
470
471
  {
471
- if ( !data || !data.stackTrace ) return [];
472
- return data.stackTrace.map ( (frame) => {
473
- let method = ( isStringWithValue(frame.class) && isStringWithValue(frame.method) ) ? (frame.class + '.' + frame.method) : frame.method;
474
- return {
475
- method: method || '',
476
- file: frame.file || '',
477
- number: frame.line || ''
478
- };
479
- });
472
+ if ( !data || !data.stackTrace ) return [];
473
+ return data.stackTrace.map ( (frame) => {
474
+ let method = ( isStringWithValue(frame.class) && isStringWithValue(frame.method) ) ? (frame.class + '.' + frame.method) : frame.method;
475
+ return {
476
+ method: method || '',
477
+ file: frame.file || '',
478
+ number: frame.line || ''
479
+ };
480
+ });
480
481
  }
481
482
 
482
483
 
@@ -487,138 +488,138 @@ function backTraceFromAndroidException(data)
487
488
 
488
489
  function onNativeIOSException(data)
489
490
  {
490
- let payloadData = {
491
- errorClass: `React Native iOS ${data.type}`,
492
- errorMsg: errorMessageFromIOSException(data),
493
- details: {
494
- errorDomain: data.errorDomain || '',
495
- initialHandler: data.initialHandler || '',
496
- userInfo: data.userInfo || {},
497
- architecture: data.architecture || '',
498
- },
499
- context: _context || {},
500
- };
491
+ let payloadData = {
492
+ errorClass: `React Native iOS ${data.type}`,
493
+ errorMsg: errorMessageFromIOSException(data),
494
+ details: {
495
+ errorDomain: data.errorDomain || '',
496
+ initialHandler: data.initialHandler || '',
497
+ userInfo: data.userInfo || {},
498
+ architecture: data.architecture || '',
499
+ },
500
+ context: _context || {},
501
+ };
501
502
 
502
- let backTrace = backTraceFromIOSException(data);
503
+ let backTrace = backTraceFromIOSException(data);
503
504
 
504
- if ( arrayHasValues(backTrace.framesFromComponentStack) )
505
- {
506
- payloadData.backTrace = backTrace.framesFromComponentStack;
507
- payloadData.details.primaryBackTraceSource = 'ReactNativeComponentStack';
508
- if ( arrayHasValues(backTrace.framesFromReactNativeIOSStackTrace) ) {
509
- payloadData.details.reactNativeIOSStackTrace = backTrace.framesFromReactNativeIOSStackTrace;
510
- }
511
- if ( arrayHasValues(backTrace.framesFromIOSCallStack) ) {
512
- payloadData.details.iosCallStack = backTrace.framesFromIOSCallStack;
513
- }
505
+ if ( arrayHasValues(backTrace.framesFromComponentStack) )
506
+ {
507
+ payloadData.backTrace = backTrace.framesFromComponentStack;
508
+ payloadData.details.primaryBackTraceSource = 'ReactNativeComponentStack';
509
+ if ( arrayHasValues(backTrace.framesFromReactNativeIOSStackTrace) ) {
510
+ payloadData.details.reactNativeIOSStackTrace = backTrace.framesFromReactNativeIOSStackTrace;
514
511
  }
515
- else if ( arrayHasValues(backTrace.framesFromReactNativeIOSStackTrace) )
516
- {
517
- payloadData.backTrace = backTrace.framesFromReactNativeIOSStackTrace;
518
- payloadData.details.primaryBackTraceSource = 'ReactNativeIOSStackTrace';
519
- if ( arrayHasValues(backTrace.framesFromIOSCallStack) ) {
520
- payloadData.details.iosCallStack = backTrace.framesFromIOSCallStack;
521
- }
512
+ if ( arrayHasValues(backTrace.framesFromIOSCallStack) ) {
513
+ payloadData.details.iosCallStack = backTrace.framesFromIOSCallStack;
522
514
  }
523
- else if ( arrayHasValues(backTrace.framesFromIOSCallStack) )
524
- {
525
- payloadData.backTrace = backTrace.framesFromIOSCallStack;
526
- payloadData.details.primaryBackTraceSource = 'iOSCallStack';
515
+ }
516
+ else if ( arrayHasValues(backTrace.framesFromReactNativeIOSStackTrace) )
517
+ {
518
+ payloadData.backTrace = backTrace.framesFromReactNativeIOSStackTrace;
519
+ payloadData.details.primaryBackTraceSource = 'ReactNativeIOSStackTrace';
520
+ if ( arrayHasValues(backTrace.framesFromIOSCallStack) ) {
521
+ payloadData.details.iosCallStack = backTrace.framesFromIOSCallStack;
527
522
  }
528
-
529
- sendToHoneybadger(buildPayload(payloadData));
523
+ }
524
+ else if ( arrayHasValues(backTrace.framesFromIOSCallStack) )
525
+ {
526
+ payloadData.backTrace = backTrace.framesFromIOSCallStack;
527
+ payloadData.details.primaryBackTraceSource = 'iOSCallStack';
528
+ }
529
+
530
+ sendToHoneybadger(buildPayload(payloadData));
530
531
  }
531
532
 
532
533
 
533
534
 
534
535
  function errorMessageFromIOSException(data) {
535
- if ( !data ) {
536
- return '';
537
- }
538
-
539
- if ( data.localizedDescription && data.localizedDescription !== '' ) {
540
- const localizedDescription = data.localizedDescription;
541
- const startOfNativeIOSCallStack = localizedDescription.indexOf('callstack: (\n');
542
- if ( startOfNativeIOSCallStack === -1 ) {
543
- const lines = localizedDescription.split('\n');
544
- return lines.length === 0 ? localizedDescription : lines[0].trim();
545
- } else {
546
- return localizedDescription.substr(0, startOfNativeIOSCallStack).trim();
547
- }
548
- }
549
- else if ( (data.name && data.name !== '') || (data.reason && data.reason !== '') ) {
550
- return `${data.name} : ${data.reason}`.trim();
536
+ if ( !data ) {
537
+ return '';
538
+ }
539
+
540
+ if ( data.localizedDescription && data.localizedDescription !== '' ) {
541
+ const localizedDescription = data.localizedDescription;
542
+ const startOfNativeIOSCallStack = localizedDescription.indexOf('callstack: (\n');
543
+ if ( startOfNativeIOSCallStack === -1 ) {
544
+ const lines = localizedDescription.split('\n');
545
+ return lines.length === 0 ? localizedDescription : lines[0].trim();
546
+ } else {
547
+ return localizedDescription.substr(0, startOfNativeIOSCallStack).trim();
551
548
  }
549
+ }
550
+ else if ( (data.name && data.name !== '') || (data.reason && data.reason !== '') ) {
551
+ return `${data.name} : ${data.reason}`.trim();
552
+ }
552
553
 
553
- return '';
554
+ return '';
554
555
  }
555
556
 
556
557
 
557
558
 
558
559
  function backTraceFromIOSException(data) {
559
- return {
560
- framesFromComponentStack: framesFromComponentStack(data.localizedDescription),
561
- framesFromReactNativeIOSStackTrace: framesFromReactNativeIOSStackTrace(data),
562
- framesFromIOSCallStack: framesFromIOSCallStack(data),
563
- };
560
+ return {
561
+ framesFromComponentStack: framesFromComponentStack(data.localizedDescription),
562
+ framesFromReactNativeIOSStackTrace: framesFromReactNativeIOSStackTrace(data),
563
+ framesFromIOSCallStack: framesFromIOSCallStack(data),
564
+ };
564
565
  }
565
566
 
566
567
 
567
568
 
568
569
  function framesFromReactNativeIOSStackTrace(data) {
569
- if ( !data.reactNativeStackTrace ) {
570
- return [];
571
- }
572
- let frames = [];
573
- data.reactNativeStackTrace.forEach( (frame) => {
574
- frames.push({
575
- method: frame.methodName || '',
576
- number: frame.lineNumber || '',
577
- file: frame.file || '',
578
- column: frame.column || '',
579
- });
570
+ if ( !data.reactNativeStackTrace ) {
571
+ return [];
572
+ }
573
+ let frames = [];
574
+ data.reactNativeStackTrace.forEach( (frame) => {
575
+ frames.push({
576
+ method: frame.methodName || '',
577
+ number: frame.lineNumber || '',
578
+ file: frame.file || '',
579
+ column: frame.column || '',
580
580
  });
581
- return frames;
581
+ });
582
+ return frames;
582
583
  }
583
584
 
584
585
 
585
586
 
586
587
  function framesFromIOSCallStack(data) {
587
- let callStack = [];
588
-
589
- if ( isStringWithValue(data.localizedDescription) ) {
590
- callStack = data.localizedDescription.split('\n').map(item => item.trim());
591
- }
592
- else if ( arrayHasValues(data.callStackSymbols) ) {
593
- callStack = data.callStackSymbols.map(item => item.trim());
588
+ let callStack = [];
589
+
590
+ if ( isStringWithValue(data.localizedDescription) ) {
591
+ callStack = data.localizedDescription.split('\n').map(item => item.trim());
592
+ }
593
+ else if ( arrayHasValues(data.callStackSymbols) ) {
594
+ callStack = data.callStackSymbols.map(item => item.trim());
595
+ }
596
+
597
+ let frames = [];
598
+ const regex = /\d+\s+(\S+)\s+(\S+)\s(.+)\s\+\s(\d+)(\s+\((\S+):(\S+)\))?/gm;
599
+ let match;
600
+ callStack.forEach(element => {
601
+ while ( (match = regex.exec(element)) !== null ) {
602
+ if ( match.index === regex.lastIndex) {
603
+ regex.lastIndex++;
604
+ }
605
+
606
+ let moduleName = match && match.length > 1 ? match[1] : '';
607
+ let stackAddress = match && match.length > 2 ? match[2] : '';
608
+ let loadAddress = match && match.length > 3 ? match[3] : '';
609
+ // let symbolOffset = match && match.length > 4 ? match[4] : '';
610
+ let file = match && match.length > 6 ? match[6] : '';
611
+ let line = match && match.length > 7 ? match[7] : '';
612
+
613
+ frames.push({
614
+ file: file || moduleName || '',
615
+ line: line || '',
616
+ method: loadAddress || '',
617
+ stack_address: stackAddress || '',
618
+ });
594
619
  }
620
+ });
595
621
 
596
- let frames = [];
597
- const regex = /\d+\s+(\S+)\s+(\S+)\s(.+)\s\+\s(\d+)(\s+\((\S+):(\S+)\))?/gm;
598
- let match;
599
- callStack.forEach(element => {
600
- while ( (match = regex.exec(element)) !== null ) {
601
- if ( match.index === regex.lastIndex) {
602
- regex.lastIndex++;
603
- }
604
-
605
- let moduleName = match && match.length > 1 ? match[1] : '';
606
- let stackAddress = match && match.length > 2 ? match[2] : '';
607
- let loadAddress = match && match.length > 3 ? match[3] : '';
608
- // let symbolOffset = match && match.length > 4 ? match[4] : '';
609
- let file = match && match.length > 6 ? match[6] : '';
610
- let line = match && match.length > 7 ? match[7] : '';
611
-
612
- frames.push({
613
- file: file || moduleName || '',
614
- line: line || '',
615
- method: loadAddress || '',
616
- stack_address: stackAddress || '',
617
- });
618
- }
619
- });
620
-
621
- return frames;
622
+ return frames;
622
623
  }
623
624
 
624
625
 
@@ -628,29 +629,29 @@ function framesFromIOSCallStack(data) {
628
629
  // ----------------------------------------------------------------------------
629
630
 
630
631
  function isObject(val) {
631
- return val != null && (typeof val === 'object') && !(Array.isArray(val));
632
+ return val != null && (typeof val === 'object') && !(Array.isArray(val));
632
633
  }
633
634
 
634
635
  function isObjectWithField(possibleObj, field) {
635
- return isObject(possibleObj) && (field in possibleObj);
636
+ return isObject(possibleObj) && (field in possibleObj);
636
637
  }
637
638
 
638
639
  function isString(val) {
639
- return val != null && typeof val === 'string';
640
+ return val != null && typeof val === 'string';
640
641
  }
641
642
 
642
643
  function isStringWithValue(val) {
643
- return isString(val) && val.trim().length > 0;
644
+ return isString(val) && val.trim().length > 0;
644
645
  }
645
646
 
646
647
  function arrayHasValues(obj) {
647
- return obj != null && Array.isArray(obj) && obj.length !== 0;
648
+ return obj != null && Array.isArray(obj) && obj.length !== 0;
648
649
  }
649
650
 
650
651
  function safeStringFromField(obj, field, defaultValue = '') {
651
- if ( isObjectWithField(obj, field) && isStringWithValue(obj[field]) ) {
652
- return obj[field].trim();
653
- }
654
- return defaultValue;
652
+ if ( isObjectWithField(obj, field) && isStringWithValue(obj[field]) ) {
653
+ return obj[field].trim();
654
+ }
655
+ return defaultValue;
655
656
  }
656
657