UNPKG

3.86 kBJavaScriptView Raw
1'use strict';
2
3const program = require('commander');
4
5const { defaultConfig } = require('../config');
6
7const { uniq } = require('../helpers/array');
8const { consoleError } = require('../helpers/console');
9const { splitByCommas } = require('../helpers/string');
10
11const consoleReport = require('./console');
12const errorDictionaryReport = require('./error_dictionary');
13const htmlReport = require('./html');
14const jsonReport = require('./json');
15const junitReport = require('./junit');
16const markdownReport = require('./markdown');
17
18class Reports {
19 constructor() {
20 this.buffer = [];
21
22 this.innerReports = [
23 consoleReport,
24 errorDictionaryReport,
25 htmlReport,
26 jsonReport,
27 junitReport,
28 markdownReport,
29 ];
30
31 this.innerReportsByName = this.innerReports.reduce((acc, current) => {
32 acc[current.name] = current;
33
34 return acc;
35 }, {});
36
37 this.stats = {
38 errors: 0,
39 hasTypos: false,
40 ok: 0,
41 total: 0,
42 };
43
44 this.reports = [];
45 }
46
47 /**
48 * Set reports.
49 *
50 * @param {string|string[]|undefined} names
51 */
52 set(names) {
53 this.reports = [];
54
55 if (typeof names === 'string') {
56 names = splitByCommas(names);
57 } else if (Array.isArray(names)) {
58 names = names.map(item => item.trim());
59 } else {
60 names = [];
61 }
62
63 names = uniq(names).filter(Boolean);
64 if (!names.length) {
65 names = defaultConfig.report;
66 }
67
68 names.forEach(name => {
69 const report = this.innerReportsByName[name] || this.loadExternalReport(name);
70 if (report) {
71 this.reports.push(report);
72 }
73 });
74 }
75
76 /**
77 * Load external report.
78 *
79 * @param {string} name
80 * @returns {Report|undefined}
81 */
82 loadExternalReport(name) {
83 try {
84 const report = require(require.resolve(name, {
85 paths: ['./']
86 }));
87
88 if (!report.name) {
89 consoleError(`Missing "name" property in report module "${name}".`);
90 return;
91 }
92
93 if (!report.onStart && !report.onComplete && !report.onResourceComplete) {
94 consoleError(`Missing methods (onStart, onResourceComplete or onComplete) in report module "${name}".`);
95 return;
96 }
97
98 return report;
99 } catch (e) {
100 consoleError(e);
101 }
102 }
103
104 onStart() {
105 this.reports.forEach(report => {
106 report.onStart && report.onStart();
107 });
108 }
109
110 onResourceComplete(hasError, data, dictionary) {
111 this.stats.total++;
112
113 const hasTypos = Boolean(data && data.data && data.data.length);
114
115 if (hasTypos) {
116 this.stats.hasTypos = true;
117 }
118
119 if (hasError || hasTypos) {
120 this.stats.errors++;
121
122 this.buffer.push([hasError, data]);
123 } else {
124 this.stats.ok++;
125
126 if (!program.onlyErrors) {
127 this.buffer.push([hasError, data]);
128 }
129 }
130
131 if (!program.onlyErrors || hasError || hasTypos) {
132 this.reports.forEach(report => {
133 report.onResourceComplete && report.onResourceComplete(hasError, data, dictionary);
134 });
135 }
136 }
137
138 onComplete(configPath) {
139 this.reports.forEach(report => {
140 report.onComplete && report.onComplete(this.buffer, this.stats, configPath);
141 });
142 }
143}
144
145module.exports = new Reports();
146
147/**
148 @typedef Report
149 @type {Object}
150 @property {string} name
151 @property {Function?} onStart
152 @property {Function?} onResourceComplete
153 @property {Function?} onComplete
154 */