source: frontend/node_modules/eslint-webpack-plugin/dist/linter.js

Last change on this file was 9af201e, checked in by MBK <marija.karapandzova@…>, 2 weeks ago

Fix frontend appearance

  • Property mode set to 100644
File size: 7.7 KB
RevLine 
[9af201e]1"use strict";
2
3const {
4 dirname,
5 isAbsolute,
6 join
7} = require('path');
8
9const ESLintError = require('./ESLintError');
10
11const {
12 getESLint
13} = require('./getESLint');
14/** @typedef {import('eslint').ESLint} ESLint */
15
16/** @typedef {import('eslint').ESLint.Formatter} Formatter */
17
18/** @typedef {import('eslint').ESLint.LintResult} LintResult */
19
20/** @typedef {import('webpack').Compiler} Compiler */
21
22/** @typedef {import('webpack').Compilation} Compilation */
23
24/** @typedef {import('./options').Options} Options */
25
26/** @typedef {import('./options').FormatterFunction} FormatterFunction */
27
28/** @typedef {(compilation: Compilation) => Promise<void>} GenerateReport */
29
30/** @typedef {{errors?: ESLintError, warnings?: ESLintError, generateReportAsset?: GenerateReport}} Report */
31
32/** @typedef {() => Promise<Report>} Reporter */
33
34/** @typedef {(files: string|string[]) => void} Linter */
35
36/** @typedef {{[files: string]: LintResult}} LintResultMap */
37
38/** @type {WeakMap<Compiler, LintResultMap>} */
39
40
41const resultStorage = new WeakMap();
42/**
43 * @param {string|undefined} key
44 * @param {Options} options
45 * @param {Compilation} compilation
46 * @returns {{lint: Linter, report: Reporter, threads: number}}
47 */
48
49function linter(key, options, compilation) {
50 /** @type {ESLint} */
51 let eslint;
52 /** @type {(files: string|string[]) => Promise<LintResult[]>} */
53
54 let lintFiles;
55 /** @type {() => Promise<void>} */
56
57 let cleanup;
58 /** @type number */
59
60 let threads;
61 /** @type {Promise<LintResult[]>[]} */
62
63 const rawResults = [];
64 const crossRunResultStorage = getResultStorage(compilation);
65
66 try {
67 ({
68 eslint,
69 lintFiles,
70 cleanup,
71 threads
72 } = getESLint(key, options));
73 } catch (e) {
74 throw new ESLintError(e.message);
75 }
76
77 return {
78 lint,
79 report,
80 threads
81 };
82 /**
83 * @param {string | string[]} files
84 */
85
86 function lint(files) {
87 for (const file of asList(files)) {
88 delete crossRunResultStorage[file];
89 }
90
91 rawResults.push(lintFiles(files).catch(e => {
92 // @ts-ignore
93 compilation.errors.push(new ESLintError(e.message));
94 return [];
95 }));
96 }
97
98 async function report() {
99 // Filter out ignored files.
100 let results = await removeIgnoredWarnings(eslint, // Get the current results, resetting the rawResults to empty
101 await flatten(rawResults.splice(0, rawResults.length)));
102 await cleanup();
103
104 for (const result of results) {
105 crossRunResultStorage[result.filePath] = result;
106 }
107
108 results = Object.values(crossRunResultStorage); // do not analyze if there are no results or eslint config
109
110 if (!results || results.length < 1) {
111 return {};
112 }
113
114 const formatter = await loadFormatter(eslint, options.formatter);
115 const {
116 errors,
117 warnings
118 } = await formatResults(formatter, parseResults(options, results));
119 return {
120 errors,
121 warnings,
122 generateReportAsset
123 };
124 /**
125 * @param {Compilation} compilation
126 * @returns {Promise<void>}
127 */
128
129 async function generateReportAsset({
130 compiler
131 }) {
132 const {
133 outputReport
134 } = options;
135 /**
136 * @param {string} name
137 * @param {string | Buffer} content
138 */
139
140 const save = (name, content) =>
141 /** @type {Promise<void>} */
142 new Promise((finish, bail) => {
143 const {
144 mkdir,
145 writeFile
146 } = compiler.outputFileSystem; // ensure directory exists
147 // @ts-ignore - the types for `outputFileSystem` are missing the 3 arg overload
148
149 mkdir(dirname(name), {
150 recursive: true
151 }, err => {
152 /* istanbul ignore if */
153 if (err) bail(err);else writeFile(name, content, err2 => {
154 /* istanbul ignore if */
155 if (err2) bail(err2);else finish();
156 });
157 });
158 });
159
160 if (!outputReport || !outputReport.filePath) {
161 return;
162 }
163
164 const content = await (outputReport.formatter ? (await loadFormatter(eslint, outputReport.formatter)).format(results) : formatter.format(results));
165 let {
166 filePath
167 } = outputReport;
168
169 if (!isAbsolute(filePath)) {
170 filePath = join(compiler.outputPath, filePath);
171 }
172
173 await save(filePath, content);
174 }
175 }
176}
177/**
178 * @param {Formatter} formatter
179 * @param {{ errors: LintResult[]; warnings: LintResult[]; }} results
180 * @returns {Promise<{errors?: ESLintError, warnings?: ESLintError}>}
181 */
182
183
184async function formatResults(formatter, results) {
185 let errors;
186 let warnings;
187
188 if (results.warnings.length > 0) {
189 warnings = new ESLintError(await formatter.format(results.warnings));
190 }
191
192 if (results.errors.length > 0) {
193 errors = new ESLintError(await formatter.format(results.errors));
194 }
195
196 return {
197 errors,
198 warnings
199 };
200}
201/**
202 * @param {Options} options
203 * @param {LintResult[]} results
204 * @returns {{errors: LintResult[], warnings: LintResult[]}}
205 */
206
207
208function parseResults(options, results) {
209 /** @type {LintResult[]} */
210 const errors = [];
211 /** @type {LintResult[]} */
212
213 const warnings = [];
214 results.forEach(file => {
215 if (fileHasErrors(file)) {
216 const messages = file.messages.filter(message => options.emitError && message.severity === 2);
217
218 if (messages.length > 0) {
219 errors.push({ ...file,
220 messages
221 });
222 }
223 }
224
225 if (fileHasWarnings(file)) {
226 const messages = file.messages.filter(message => options.emitWarning && message.severity === 1);
227
228 if (messages.length > 0) {
229 warnings.push({ ...file,
230 messages
231 });
232 }
233 }
234 });
235 return {
236 errors,
237 warnings
238 };
239}
240/**
241 * @param {LintResult} file
242 * @returns {boolean}
243 */
244
245
246function fileHasErrors(file) {
247 return file.errorCount > 0;
248}
249/**
250 * @param {LintResult} file
251 * @returns {boolean}
252 */
253
254
255function fileHasWarnings(file) {
256 return file.warningCount > 0;
257}
258/**
259 * @param {ESLint} eslint
260 * @param {string|FormatterFunction=} formatter
261 * @returns {Promise<Formatter>}
262 */
263
264
265async function loadFormatter(eslint, formatter) {
266 if (typeof formatter === 'function') {
267 return {
268 format: formatter
269 };
270 }
271
272 if (typeof formatter === 'string') {
273 try {
274 return eslint.loadFormatter(formatter);
275 } catch (_) {// Load the default formatter.
276 }
277 }
278
279 return eslint.loadFormatter();
280}
281/**
282 * @param {ESLint} eslint
283 * @param {LintResult[]} results
284 * @returns {Promise<LintResult[]>}
285 */
286
287
288async function removeIgnoredWarnings(eslint, results) {
289 const filterPromises = results.map(async result => {
290 // Short circuit the call to isPathIgnored.
291 // fatal is false for ignored file warnings.
292 // ruleId is unset for internal ESLint errors.
293 // line is unset for warnings not involving file contents.
294 const ignored = result.messages.length === 0 || result.warningCount === 1 && result.errorCount === 0 && !result.messages[0].fatal && !result.messages[0].ruleId && !result.messages[0].line && (await eslint.isPathIgnored(result.filePath));
295 return ignored ? false : result;
296 }); // @ts-ignore
297
298 return (await Promise.all(filterPromises)).filter(result => !!result);
299}
300/**
301 * @param {Promise<LintResult[]>[]} results
302 * @returns {Promise<LintResult[]>}
303 */
304
305
306async function flatten(results) {
307 /**
308 * @param {LintResult[]} acc
309 * @param {LintResult[]} list
310 */
311 const flat = (acc, list) => [...acc, ...list];
312
313 return (await Promise.all(results)).reduce(flat, []);
314}
315/**
316 * @param {Compilation} compilation
317 * @returns {LintResultMap}
318 */
319
320
321function getResultStorage({
322 compiler
323}) {
324 let storage = resultStorage.get(compiler);
325
326 if (!storage) {
327 resultStorage.set(compiler, storage = {});
328 }
329
330 return storage;
331}
332/**
333 * @param {string | string[]} x
334 */
335
336
337function asList(x) {
338 /* istanbul ignore next */
339 return Array.isArray(x) ? x : [x];
340}
341
342module.exports = linter;
Note: See TracBrowser for help on using the repository browser.