123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226 |
- sysPath = require 'path'
- module.exports = class ParsedError
- constructor: (@error) ->
- do @_parse
- _parse: ->
- @_trace = []
- @_kind = 'Error'
- @_wrapper = ''
- @_wrapper = String @error.wrapper if @error.wrapper?
- unless typeof @error is 'object'
- @_message = String @error
- else
- @_stack = @error.stack
- if @error.kind?
- @_kind = String @error.kind
- else if typeof @_stack is 'string'
- if m = @_stack.match /^([a-zA-Z0-9\_\$]+):\ /
- @_kind = m[1]
- if typeof @_stack is 'string'
- @_parseStack()
- else
- @_message = @error.message? and String(@error.message) or ''
- return
- _parseStack: ->
- messageLines = []
- reachedTrace = no
- for line in @_stack.split '\n'
- continue if line.trim() is ''
- if reachedTrace
- @_trace.push @_parseTraceItem line
- else
- if line.match /^\s*at\s.+/
- reachedTrace = yes
- @_trace.push @_parseTraceItem line
- else
- messageLines.push line
- message = messageLines.join '\n'
- if message.substr(0, @_kind.length) is @_kind
- message =
- message
- .substr(@_kind.length, message.length)
- .replace(/^\:\s+/, '')
- @_message = message
- return
- _parseTraceItem: (text) ->
- text = text.trim()
- return if text is ''
- return text unless text.match /^at\ /
- # remove the 'at ' part
- text = text.replace /^at /, ''
- return if text in ['Error (<anonymous>)', 'Error (<anonymous>:null:null)']
- original = text
- # the part that comes before the address
- what = null
- # address, including path to module and line/col
- addr = null
- # path to module
- path = null
- # module dir
- dir = null
- # module basename
- file = null
- # line number (if using a compiler, the line number of the module
- # in that compiler will be used)
- line = null
- # column, same as above
- col = null
- # if using a compiler, this will translate to the line number of
- # the js equivalent of that module
- jsLine = null
- # like above
- jsCol = null
- # path that doesn't include `node_module` dirs
- shortenedPath = null
- # like above
- shortenedAddr = null
- packageName = '[current]'
- # pick out the address
- if m = text.match /\(([^\)]+)\)$/
- addr = m[1].trim()
- if addr?
- what = text.substr 0, text.length - addr.length - 2
- what = what.trim()
- # might not have a 'what' clause
- unless addr?
- addr = text.trim()
- addr = @_fixPath addr
- remaining = addr
- # remove the <js> clause if the file is a compiled one
- if m = remaining.match /\,\ <js>:(\d+):(\d+)$/
- jsLine = m[1]
- jsCol = m[2]
- remaining = remaining.substr 0, remaining.length - m[0].length
- # the line/col part
- if m = remaining.match /:(\d+):(\d+)$/
- line = m[1]
- col = m[2]
- remaining = remaining.substr 0, remaining.length - m[0].length
- path = remaining
- # file and dir
- if path?
- file = sysPath.basename path
- dir = sysPath.dirname path
- if dir is '.' then dir = ''
- path = @_fixPath path
- file = @_fixPath file
- dir = @_fixPath dir
- if dir?
- d = dir.replace /[\\]{1,2}/g, '/'
- if m = d.match ///
- node_modules/([^/]+)(?!.*node_modules.*)
- ///
- packageName = m[1]
- unless jsLine?
- jsLine = line
- jsCol = col
- if path?
- r = @_rectifyPath path
- shortenedPath = r.path
- shortenedAddr = shortenedPath + addr.substr(path.length, addr.length)
- packages = r.packages
- original: original
- what: what
- addr: addr
- path: path
- dir: dir
- file: file
- line: parseInt line
- col: parseInt col
- jsLine: parseInt jsLine
- jsCol: parseInt jsCol
- packageName: packageName
- shortenedPath: shortenedPath
- shortenedAddr: shortenedAddr
- packages: packages || []
- _getMessage: -> @_message
- _getKind: -> @_kind
- _getWrapper: -> @_wrapper
- _getStack: -> @_stack
- _getArguments: -> @error.arguments
- _getType: -> @error.type
- _getTrace: -> @_trace
- _fixPath: (path) -> path.replace(///[\\]{1,2}///g, '/')
- _rectifyPath: (path, nameForCurrentPackage) ->
- path = String path
- remaining = path
- return path: path, packages: [] unless m = path.match /^(.+?)\/node_modules\/(.+)$/
- parts = []
- packages = []
- if typeof nameForCurrentPackage is 'string'
- parts.push "[#{nameForCurrentPackage}]"
- packages.push "[#{nameForCurrentPackage}]"
- else
- parts.push "[#{m[1].match(/([^\/]+)$/)[1]}]"
- packages.push m[1].match(/([^\/]+)$/)[1]
- rest = m[2]
- while m = rest.match /([^\/]+)\/node_modules\/(.+)$/
- parts.push "[#{m[1]}]"
- packages.push m[1]
- rest = m[2]
- if m = rest.match /([^\/]+)\/(.+)$/
- parts.push "[#{m[1]}]"
- packages.push m[1]
- rest = m[2]
- parts.push rest
- path: parts.join "/"
- packages: packages
- for prop in ['message', 'kind', 'arguments', 'type', 'stack', 'trace', 'wrapper'] then do ->
- methodName = '_get' + prop[0].toUpperCase() + prop.substr(1, prop.length)
- Object.defineProperty ParsedError::, prop,
- get: -> this[methodName]()
|