parser.js 2.62 KB
Newer Older
Dan Abramov's avatar
Dan Abramov committed
1
2
3
4
5
6
7
8
9
/**
 * 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.
 */

10
/* @flow */
11
12
13
14
15
import StackFrame from './stack-frame';

const regexExtractLocation = /\(?(.+?)(?::(\d+))?(?::(\d+))?\)?$/;

function extractLocation(token: string): [string, number, number] {
16
17
18
19
20
21
22
23
24
25
  return regexExtractLocation
    .exec(token)
    .slice(1)
    .map(v => {
      const p = Number(v);
      if (!isNaN(p)) {
        return p;
      }
      return v;
    });
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
}

const regexValidFrame_Chrome = /^\s*(at|in)\s.+(:\d+)/;
const regexValidFrame_FireFox = /(^|@)\S+:\d+|.+line\s+\d+\s+>\s+(eval|Function).+/;

function parseStack(stack: string[]): StackFrame[] {
  const frames = stack
    .filter(
      e => regexValidFrame_Chrome.test(e) || regexValidFrame_FireFox.test(e)
    )
    .map(e => {
      if (regexValidFrame_FireFox.test(e)) {
        // Strip eval, we don't care about it
        let isEval = false;
        if (/ > (eval|Function)/.test(e)) {
          e = e.replace(
            / line (\d+)(?: > eval line \d+)* > (eval|Function):\d+:\d+/g,
            ':$1'
          );
          isEval = true;
        }
        const data = e.split(/[@]/g);
        const last = data.pop();
        return new StackFrame(
          data.join('@') || (isEval ? 'eval' : null),
          ...extractLocation(last)
        );
      } else {
        // Strip eval, we don't care about it
        if (e.indexOf('(eval ') !== -1) {
          e = e.replace(/(\(eval at [^()]*)|(\),.*$)/g, '');
        }
        if (e.indexOf('(at ') !== -1) {
          e = e.replace(/\(at /, '(');
        }
61
62
63
64
        const data = e
          .trim()
          .split(/\s+/g)
          .slice(1);
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
        const last = data.pop();
        return new StackFrame(data.join(' ') || null, ...extractLocation(last));
      }
    });
  return frames;
}

/**
 * Turns an <code>Error</code>, or similar object, into a set of <code>StackFrame</code>s.
 * @alias parse
 */
function parseError(error: Error | string | string[]): StackFrame[] {
  if (error == null) {
    throw new Error('You cannot pass a null object.');
  }
  if (typeof error === 'string') {
    return parseStack(error.split('\n'));
  }
  if (Array.isArray(error)) {
    return parseStack(error);
  }
  if (typeof error.stack === 'string') {
    return parseStack(error.stack.split('\n'));
  }
  throw new Error('The error you provided does not contain a stack trace.');
}

export { parseError as parse };
export default parseError;