UNPKG

2.67 kBJavaScriptView Raw
1/**
2 * Copyright (c) Facebook, Inc. and its 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 * @format
8 * @flow
9 */
10
11'use strict';
12
13const getDevServer = require('getDevServer');
14
15const {SourceCode} = require('NativeModules');
16
17// Avoid requiring fetch on load of this module; see symbolicateStackTrace
18let fetch;
19
20import type {StackFrame} from 'parseErrorStack';
21
22function isSourcedFromDisk(sourcePath: string): boolean {
23 return !/^http/.test(sourcePath) && /[\\/]/.test(sourcePath);
24}
25
26async function symbolicateStackTrace(
27 stack: Array<StackFrame>,
28): Promise<Array<StackFrame>> {
29 // RN currently lazy loads whatwg-fetch using a custom fetch module, which,
30 // when called for the first time, requires and re-exports 'whatwg-fetch'.
31 // However, when a dependency of the project tries to require whatwg-fetch
32 // either directly or indirectly, whatwg-fetch is required before
33 // RN can lazy load whatwg-fetch. As whatwg-fetch checks
34 // for a fetch polyfill before loading, it will in turn try to load
35 // RN's fetch module, which immediately tries to import whatwg-fetch AGAIN.
36 // This causes a circular require which results in RN's fetch module
37 // exporting fetch as 'undefined'.
38 // The fix below postpones trying to load fetch until the first call to symbolicateStackTrace.
39 // At that time, we will have either global.fetch (whatwg-fetch) or RN's fetch.
40 if (!fetch) {
41 fetch = global.fetch || require('fetch').fetch;
42 }
43
44 const devServer = getDevServer();
45 if (!devServer.bundleLoadedFromServer) {
46 throw new Error('Bundle was not loaded from the packager');
47 }
48
49 let stackCopy = stack;
50
51 if (SourceCode.scriptURL) {
52 let foundInternalSource: boolean = false;
53 stackCopy = stack.map((frame: StackFrame) => {
54 // If the sources exist on disk rather than appearing to come from the packager,
55 // replace the location with the packager URL until we reach an internal source
56 // which does not have a path (no slashes), indicating a switch from within
57 // the application to a surrounding debugging environment.
58 if (!foundInternalSource && isSourcedFromDisk(frame.file)) {
59 // Copy frame into new object and replace 'file' property
60 return {...frame, file: SourceCode.scriptURL};
61 }
62
63 foundInternalSource = true;
64 return frame;
65 });
66 }
67
68 const response = await fetch(devServer.url + 'symbolicate', {
69 method: 'POST',
70 body: JSON.stringify({stack: stackCopy}),
71 });
72 const json = await response.json();
73 return json.stack;
74}
75
76module.exports = symbolicateStackTrace;