UNPKG

4.14 kBJavaScriptView Raw
1var util = require('util')
2var log = require('./logger').create('reporter')
3var MultiReporter = require('./reporters/multi')
4var baseReporterDecoratorFactory = require('./reporters/base').decoratorFactory
5var SourceMapConsumer = require('source-map').SourceMapConsumer
6var WeakMap = require('core-js/es6/weak-map')
7
8var createErrorFormatter = function (basePath, emitter, SourceMapConsumer) {
9 var lastServedFiles = []
10
11 emitter.on('file_list_modified', function (files) {
12 lastServedFiles = files.served
13 })
14
15 var findFile = function (path) {
16 for (var i = 0; i < lastServedFiles.length; i++) {
17 if (lastServedFiles[i].path === path) {
18 return lastServedFiles[i]
19 }
20 }
21 return null
22 }
23
24 var URL_REGEXP = new RegExp('(?:https?:\\/\\/[^\\/]*)?\\/?' +
25 '(base|absolute)' + // prefix
26 '((?:[A-z]\\:)?[^\\?\\s\\:]*)' + // path
27 '(\\?\\w*)?' + // sha
28 '(\\:(\\d+))?' + // line
29 '(\\:(\\d+))?' + // column
30 '', 'g')
31
32 var getSourceMapConsumer = (function () {
33 var cache = new WeakMap()
34 return function (sourceMap) {
35 if (!cache.has(sourceMap)) {
36 cache.set(sourceMap, new SourceMapConsumer(sourceMap))
37 }
38 return cache.get(sourceMap)
39 }
40 }())
41
42 return function (msg, indentation) {
43 // remove domain and timestamp from source files
44 // and resolve base path / absolute path urls into absolute path
45 msg = (msg || '').replace(URL_REGEXP, function (_, prefix, path, __, ___, line, ____, column) {
46 if (prefix === 'base') {
47 path = basePath + path
48 }
49
50 var file = findFile(path)
51
52 if (file && file.sourceMap) {
53 line = parseInt(line || '0', 10)
54
55 column = parseInt(column, 10)
56
57 // When no column is given and we default to 0, it doesn't make sense to only search for smaller
58 // or equal columns in the sourcemap, let's search for equal or greater columns.
59 var bias = column ? SourceMapConsumer.GREATEST_LOWER_BOUND : SourceMapConsumer.LEAST_UPPER_BOUND
60
61 try {
62 var original = getSourceMapConsumer(file.sourceMap)
63 .originalPositionFor({line: line, column: (column || 0), bias: bias})
64
65 var formattedColumn = column ? util.format(':%s', column) : ''
66 return util.format('%s:%d%s <- %s:%d:%d', path, line, formattedColumn, original.source,
67 original.line, original.column)
68 } catch (e) {
69 log.warn('SourceMap position not found for trace: %s', msg)
70 // Fall back to non-source-mapped formatting.
71 }
72 }
73
74 var result = path + (line ? ':' + line : '') + (column ? ':' + column : '')
75 return result || prefix
76 })
77
78 // indent every line
79 if (indentation) {
80 msg = indentation + msg.replace(/\n/g, '\n' + indentation)
81 }
82
83 return msg + '\n'
84 }
85}
86
87var createReporters = function (names, config, emitter, injector) {
88 var errorFormatter = createErrorFormatter(config.basePath, emitter, SourceMapConsumer)
89 var reporters = []
90
91 // TODO(vojta): instantiate all reporters through DI
92 names.forEach(function (name) {
93 if (['dots', 'progress'].indexOf(name) !== -1) {
94 var Cls = require('./reporters/' + name + (config.colors ? '_color' : ''))
95 return reporters.push(new Cls(errorFormatter, config.reportSlowerThan))
96 }
97
98 var locals = {
99 baseReporterDecorator: ['factory', baseReporterDecoratorFactory],
100 formatError: ['value', errorFormatter]
101 }
102
103 try {
104 reporters.push(injector.createChild([locals], ['reporter:' + name]).get('reporter:' + name))
105 } catch (e) {
106 if (e.message.indexOf('No provider for "reporter:' + name + '"') !== -1) {
107 log.warn('Can not load "%s", it is not registered!\n ' +
108 'Perhaps you are missing some plugin?', name)
109 } else {
110 log.warn('Can not load "%s"!\n ' + e.stack, name)
111 }
112 }
113 })
114
115 // bind all reporters
116 reporters.forEach(function (reporter) {
117 emitter.bind(reporter)
118 })
119
120 return new MultiReporter(reporters)
121}
122
123createReporters.$inject = ['config.reporters', 'config', 'emitter', 'injector']
124
125// PUBLISH
126exports.createReporters = createReporters