1 | var util = require('util')
|
2 | var log = require('./logger').create('reporter')
|
3 | var MultiReporter = require('./reporters/multi')
|
4 | var baseReporterDecoratorFactory = require('./reporters/base').decoratorFactory
|
5 | var SourceMapConsumer = require('source-map').SourceMapConsumer
|
6 | var WeakMap = require('core-js/es6/weak-map')
|
7 |
|
8 | var 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)' +
|
26 | '((?:[A-z]\\:)?[^\\?\\s\\:]*)' +
|
27 | '(\\?\\w*)?' +
|
28 | '(\\:(\\d+))?' +
|
29 | '(\\:(\\d+))?' +
|
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 |
|
44 |
|
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 |
|
58 |
|
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 |
|
71 | }
|
72 | }
|
73 |
|
74 | var result = path + (line ? ':' + line : '') + (column ? ':' + column : '')
|
75 | return result || prefix
|
76 | })
|
77 |
|
78 |
|
79 | if (indentation) {
|
80 | msg = indentation + msg.replace(/\n/g, '\n' + indentation)
|
81 | }
|
82 |
|
83 | return msg + '\n'
|
84 | }
|
85 | }
|
86 |
|
87 | var createReporters = function (names, config, emitter, injector) {
|
88 | var errorFormatter = createErrorFormatter(config.basePath, emitter, SourceMapConsumer)
|
89 | var reporters = []
|
90 |
|
91 |
|
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 |
|
116 | reporters.forEach(function (reporter) {
|
117 | emitter.bind(reporter)
|
118 | })
|
119 |
|
120 | return new MultiReporter(reporters)
|
121 | }
|
122 |
|
123 | createReporters.$inject = ['config.reporters', 'config', 'emitter', 'injector']
|
124 |
|
125 |
|
126 | exports.createReporters = createReporters
|