UNPKG

3.91 kBJavaScriptView Raw
1'use strict';
2const path = require('path');
3const eslint = require('eslint');
4const globby = require('globby');
5const isEqual = require('lodash/isEqual');
6const uniq = require('lodash/uniq');
7const micromatch = require('micromatch');
8const arrify = require('arrify');
9const pReduce = require('p-reduce');
10const {cosmiconfig, defaultLoaders} = require('cosmiconfig');
11const {CONFIG_FILES, MODULE_NAME, DEFAULT_IGNORES} = require('./lib/constants');
12const {
13 normalizeOptions,
14 getIgnores,
15 mergeWithFileConfig,
16 mergeWithFileConfigs,
17 buildConfig,
18 mergeOptions
19} = require('./lib/options-manager');
20
21const mergeReports = reports => {
22 // Merge multiple reports into a single report
23 let results = [];
24 let errorCount = 0;
25 let warningCount = 0;
26
27 for (const report of reports) {
28 results = results.concat(report.results);
29 errorCount += report.errorCount;
30 warningCount += report.warningCount;
31 }
32
33 return {
34 errorCount,
35 warningCount,
36 results
37 };
38};
39
40const processReport = (report, options) => {
41 report.results = options.quiet ? eslint.CLIEngine.getErrorResults(report.results) : report.results;
42 return report;
43};
44
45const runEslint = (paths, options) => {
46 const engine = new eslint.CLIEngine(options);
47 const report = engine.executeOnFiles(
48 paths.filter(path => !engine.isPathIgnored(path)),
49 options
50 );
51 return processReport(report, options);
52};
53
54const globFiles = async (patterns, {ignores, extensions, cwd}) => (
55 await globby(
56 patterns.length === 0 ? [`**/*.{${extensions.join(',')}}`] : arrify(patterns),
57 {ignore: ignores, gitignore: true, cwd}
58 )).filter(file => extensions.includes(path.extname(file).slice(1))).map(file => path.resolve(cwd, file));
59
60const lintText = (string, options) => {
61 const {options: foundOptions, prettierOptions} = mergeWithFileConfig(normalizeOptions(options));
62 options = buildConfig(foundOptions, prettierOptions);
63
64 if (options.ignores && !isEqual(getIgnores({}), options.ignores) && typeof options.filename !== 'string') {
65 throw new Error('The `ignores` option requires the `filename` option to be defined.');
66 }
67
68 const engine = new eslint.CLIEngine(options);
69
70 if (options.filename) {
71 const filename = path.relative(options.cwd, options.filename);
72
73 if (
74 micromatch.isMatch(filename, options.ignores) ||
75 globby.gitignore.sync({cwd: options.cwd, ignore: options.ignores})(options.filename) ||
76 engine.isPathIgnored(options.filename)
77 ) {
78 return {
79 errorCount: 0,
80 warningCount: 0,
81 results: [{
82 errorCount: 0,
83 filePath: filename,
84 messages: [],
85 warningCount: 0
86 }]
87 };
88 }
89 }
90
91 const report = engine.executeOnText(string, options.filename);
92
93 return processReport(report, options);
94};
95
96const lintFiles = async (patterns, options = {}) => {
97 options.cwd = path.resolve(options.cwd || process.cwd());
98 const configExplorer = cosmiconfig(MODULE_NAME, {searchPlaces: CONFIG_FILES, loaders: {noExt: defaultLoaders['.json']}, stopDir: options.cwd});
99
100 const configFiles = (await Promise.all(
101 (await globby(
102 CONFIG_FILES.map(configFile => `**/${configFile}`),
103 {ignore: DEFAULT_IGNORES, gitignore: true, cwd: options.cwd}
104 )).map(async configFile => configExplorer.load(path.resolve(options.cwd, configFile)))
105 )).filter(Boolean);
106
107 const paths = configFiles.length > 0 ?
108 await pReduce(
109 configFiles,
110 async (paths, {filepath, config}) =>
111 [...paths, ...(await globFiles(patterns, {...mergeOptions(options, config), cwd: path.dirname(filepath)}))],
112 []) :
113 await globFiles(patterns, mergeOptions(options));
114
115 return mergeReports((await mergeWithFileConfigs(uniq(paths), options, configFiles)).map(
116 ({files, options, prettierOptions}) => runEslint(files, buildConfig(options, prettierOptions)))
117 );
118};
119
120module.exports = {
121 getFormatter: eslint.CLIEngine.getFormatter,
122 getErrorResults: eslint.CLIEngine.getErrorResults,
123 outputFixes: eslint.CLIEngine.outputFixes,
124 lintText,
125 lintFiles
126};