-
Notifications
You must be signed in to change notification settings - Fork 1.7k
/
reporter.js
158 lines (134 loc) · 5.38 KB
/
reporter.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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
61
62
63
64
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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
var util = require('util')
var resolve = require('url').resolve
var SourceMapConsumer = require('source-map').SourceMapConsumer
var WeakMap = require('core-js/es6/weak-map')
var _ = require('lodash')
var log = require('./logger').create('reporter')
var MultiReporter = require('./reporters/multi')
var baseReporterDecoratorFactory = require('./reporters/base').decoratorFactory
var createErrorFormatter = function (basePath, emitter, SourceMapConsumer) {
var lastServedFiles = []
emitter.on('file_list_modified', function (files) {
lastServedFiles = files.served
})
var findFile = function (path) {
for (var i = 0; i < lastServedFiles.length; i++) {
if (lastServedFiles[i].path === path) {
return lastServedFiles[i]
}
}
return null
}
var URL_REGEXP = new RegExp('(?:https?:\\/\\/[^\\/]*)?\\/?' +
'(base/|absolute)' + // prefix, including slash for base/ to create relative paths.
'((?:[A-z]\\:)?[^\\?\\s\\:]*)' + // path
'(\\?\\w*)?' + // sha
'(\\:(\\d+))?' + // line
'(\\:(\\d+))?' + // column
'', 'g')
var getSourceMapConsumer = (function () {
var cache = new WeakMap()
return function (sourceMap) {
if (!cache.has(sourceMap)) {
cache.set(sourceMap, new SourceMapConsumer(sourceMap))
}
return cache.get(sourceMap)
}
}())
return function (input, indentation) {
indentation = _.isString(indentation) ? indentation : ''
if (_.isError(input)) {
input = input.message
} else if (_.isEmpty(input)) {
input = ''
} else if (!_.isString(input)) {
input = JSON.stringify(input, null, indentation)
}
// remove domain and timestamp from source files
// and resolve base path / absolute path urls into absolute path
var msg = input.replace(URL_REGEXP, function (_, prefix, path, __, ___, line, ____, column) {
// Find the file using basePath + path, but use the more readable path down below.
var file = findFile(prefix === 'base/' ? basePath + '/' + path : path)
if (file && file.sourceMap && line) {
line = parseInt(line || '0', 10)
column = parseInt(column, 10)
// When no column is given and we default to 0, it doesn't make sense to only search for smaller
// or equal columns in the sourcemap, let's search for equal or greater columns.
var bias = column ? SourceMapConsumer.GREATEST_LOWER_BOUND : SourceMapConsumer.LEAST_UPPER_BOUND
try {
var original = getSourceMapConsumer(file.sourceMap)
.originalPositionFor({line: line, column: (column || 0), bias: bias})
// Source maps often only have a local file name, resolve to turn into a full path if
// the path is not absolute yet.
var sourcePath = resolve(path, original.source)
var formattedColumn = column ? util.format(':%s', column) : ''
return util.format('%s:%d:%d <- %s:%d%s', sourcePath, original.line, original.column,
path, line, formattedColumn)
} catch (e) {
log.warn('SourceMap position not found for trace: %s', msg)
// Fall back to non-source-mapped formatting.
}
}
var result = path + (line ? ':' + line : '') + (column ? ':' + column : '')
return result || prefix
})
// indent every line
if (indentation) {
msg = indentation + msg.replace(/\n/g, '\n' + indentation)
}
return msg + '\n'
}
}
var createReporters = function (names, config, emitter, injector) {
var errorFormatter = createErrorFormatter(config.basePath, emitter, SourceMapConsumer)
var reporters = []
// TODO(vojta): instantiate all reporters through DI
names.forEach(function (name) {
if (['dots', 'progress'].indexOf(name) !== -1) {
var Cls = require('./reporters/' + name)
var ClsColor = require('./reporters/' + name + '_color')
reporters.push(new Cls(errorFormatter, config.reportSlowerThan, config.colors, config.browserConsoleLogOptions))
return reporters.push(new ClsColor(errorFormatter, config.reportSlowerThan, config.colors, config.browserConsoleLogOptions))
}
var locals = {
baseReporterDecorator: ['factory', baseReporterDecoratorFactory],
formatError: ['value', errorFormatter]
}
try {
log.debug('Trying to load reporter: %s', name)
reporters.push(injector.createChild([locals], ['reporter:' + name]).get('reporter:' + name))
} catch (e) {
if (e.message.indexOf('No provider for "reporter:' + name + '"') !== -1) {
log.error('Can not load reporter "%s", it is not registered!\n ' +
'Perhaps you are missing some plugin?', name)
} else {
log.error('Can not load "%s"!\n ' + e.stack, name)
}
emitter.emit('load_error', 'reporter', name)
return
}
var colorName = name + '_color'
if (names.indexOf(colorName) !== -1) {
return
}
try {
log.debug('Trying to load color-version of reporter: %s (%s)', name, colorName)
reporters.push(injector.createChild([locals], ['reporter:' + name + '_color']).get('reporter:' + name))
} catch (e) {
log.debug('Couldn\'t load color-version.')
}
})
// bind all reporters
reporters.forEach(function (reporter) {
emitter.bind(reporter)
})
return new MultiReporter(reporters)
}
createReporters.$inject = [
'config.reporters',
'config',
'emitter',
'injector'
]
// PUBLISH
exports.createReporters = createReporters