/**
 * Copyright (c) 2015-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule symbolicateStackTrace
 * @flow
 */
'use strict';

const {fetch} = require('fetch');
const getDevServer = require('getDevServer');

import type {StackFrame} from 'parseErrorStack';

async function symbolicateStackTrace(stack: Array<StackFrame>): Promise<Array<StackFrame>> {
  const devServer = getDevServer();
  if (!devServer.bundleLoadedFromServer) {
    throw new Error('Bundle was not loaded from the packager');
  }
  const response = await fetch(devServer.url + 'symbolicate', {
    method: 'POST',
    body: JSON.stringify({stack}),
  });
  const json = await response.json();
  return json.stack;
}

module.exports = symbolicateStackTrace;

/**
 * Copyright (c) 2015-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule symbolicateStackTrace
 * @flow
 */
'use strict';

const {fetch} = require('fetch');
const getDevServer = require('getDevServer');
const {SourceCode} = require('NativeModules');

import type {StackFrame} from 'parseErrorStack';

async function symbolicateStackTrace(stack: Array<StackFrame>): Promise<Array<StackFrame>> {
  const devServer = getDevServer();
  if (!devServer.bundleLoadedFromServer) {
    throw new Error('Bundle was not loaded from the packager');
  }
  if (SourceCode.scriptURL) {
    for (let i = 0; i < stack.length; ++i) {
      // If the sources exist on disk rather than appearing to come from the packager,
      // replace the location with the packager URL until we reach an internal source
      // which does not have a path (no slashes), indicating a switch from within
      // the application to a surrounding debugging environment.
      if (/^http/.test(stack[i].file) || !/[\\/]/.test(stack[i].file)) {
        break;
      }
      stack[i].file = SourceCode.scriptURL;
    }
  }

  const response = await fetch(devServer.url + 'symbolicate', {
    method: 'POST',
    body: JSON.stringify({stack}),
  });
  const json = await response.json();
  return json.stack;
}

module.exports = symbolicateStackTrace;

Fix symbolication outside of chrome debugging
Fix symbolication outside of chrome debugging

Summary:
When debugging in VScode or nucleide using a nodejs environment rather than chrome, the JS sources are made to appear as if they exist on disk, rather than coming from a `http://` url. Prior to this change the packager would see these file paths and not know how to handle them.

Since all the application JS will be part of a bundle file, we can switch out the path to the bundle on the filesystem with paths to the bundle served by the packager, and things will work just as though it was debugging in chrome. We stop the replacement once we reach an internal module (`vm.js` in the case of both nucleide and VSCode) since that is the point when the execution switches from inside the app to the surrounding debugging environment.

I've verified that this fixes redbox stack trace symbolication in VSCode, and from my understanding of nucleide's debugging environment it should also work there without requiring any changes.
Closes https://github.com/facebook/react-native/pull/9906

Differential Revision: D3887166

Pulled By: davidaurelio

fbshipit-source-id: e3a6704f30e0fd045ad836bba51f6e20d9854c30
