stack-trace.js 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. exports.get = function(belowFn) {
  2. var oldLimit = Error.stackTraceLimit;
  3. Error.stackTraceLimit = Infinity;
  4. var dummyObject = {};
  5. var v8Handler = Error.prepareStackTrace;
  6. Error.prepareStackTrace = function(dummyObject, v8StackTrace) {
  7. return v8StackTrace;
  8. };
  9. Error.captureStackTrace(dummyObject, belowFn || exports.get);
  10. var v8StackTrace = dummyObject.stack;
  11. Error.prepareStackTrace = v8Handler;
  12. Error.stackTraceLimit = oldLimit;
  13. return v8StackTrace;
  14. };
  15. exports.parse = function(err) {
  16. if (!err.stack) {
  17. return [];
  18. }
  19. var self = this;
  20. var lines = err.stack.split('\n').slice(1);
  21. return lines
  22. .map(function(line) {
  23. if (line.match(/^\s*[-]{4,}$/)) {
  24. return self._createParsedCallSite({
  25. fileName: line,
  26. lineNumber: null,
  27. functionName: null,
  28. typeName: null,
  29. methodName: null,
  30. columnNumber: null,
  31. 'native': null,
  32. });
  33. }
  34. var lineMatch = line.match(/at (?:(.+)\s+)?\(?(?:(.+?):(\d+):(\d+)|([^)]+))\)?/);
  35. if (!lineMatch) {
  36. return;
  37. }
  38. var object = null;
  39. var method = null;
  40. var functionName = null;
  41. var typeName = null;
  42. var methodName = null;
  43. var isNative = (lineMatch[5] === 'native');
  44. if (lineMatch[1]) {
  45. var methodMatch = lineMatch[1].match(/([^\.]+)(?:\.(.+))?/);
  46. object = methodMatch[1];
  47. method = methodMatch[2];
  48. functionName = lineMatch[1];
  49. typeName = 'Object';
  50. }
  51. if (method) {
  52. typeName = object;
  53. methodName = method;
  54. }
  55. if (method === '<anonymous>') {
  56. methodName = null;
  57. functionName = '';
  58. }
  59. var properties = {
  60. fileName: lineMatch[2] || null,
  61. lineNumber: parseInt(lineMatch[3], 10) || null,
  62. functionName: functionName,
  63. typeName: typeName,
  64. methodName: methodName,
  65. columnNumber: parseInt(lineMatch[4], 10) || null,
  66. 'native': isNative,
  67. };
  68. return self._createParsedCallSite(properties);
  69. })
  70. .filter(function(callSite) {
  71. return !!callSite;
  72. });
  73. };
  74. exports._createParsedCallSite = function(properties) {
  75. var methods = {};
  76. for (var property in properties) {
  77. var prefix = 'get';
  78. if (property === 'native') {
  79. prefix = 'is';
  80. }
  81. var method = prefix + property.substr(0, 1).toUpperCase() + property.substr(1);
  82. (function(property) {
  83. methods[method] = function() {
  84. return properties[property];
  85. }
  86. })(property);
  87. }
  88. var callSite = Object.create(methods);
  89. for (var property in properties) {
  90. callSite[property] = properties[property];
  91. }
  92. return callSite;
  93. };