xo 0.43.0 → 0.44.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cli.js +2 -2
- package/index.js +53 -130
- package/lib/options-manager.js +41 -92
- package/lib/report.js +84 -0
- package/package.json +12 -20
- package/readme.md +1 -1
package/cli.js
CHANGED
|
@@ -173,8 +173,8 @@ if (options.nodeVersion) {
|
|
|
173
173
|
}
|
|
174
174
|
|
|
175
175
|
(async () => {
|
|
176
|
-
if (options.printConfig) {
|
|
177
|
-
if (input.length > 0) {
|
|
176
|
+
if (typeof options.printConfig === 'string') {
|
|
177
|
+
if (input.length > 0 || options.printConfig === '') {
|
|
178
178
|
console.error('The `--print-config` flag must be used with exactly one filename');
|
|
179
179
|
process.exit(1);
|
|
180
180
|
}
|
package/index.js
CHANGED
|
@@ -1,169 +1,92 @@
|
|
|
1
|
-
import process from 'node:process';
|
|
2
1
|
import path from 'node:path';
|
|
3
2
|
import {ESLint} from 'eslint';
|
|
4
3
|
import {globby, isGitIgnoredSync} from 'globby';
|
|
5
4
|
import {isEqual} from 'lodash-es';
|
|
6
5
|
import micromatch from 'micromatch';
|
|
7
6
|
import arrify from 'arrify';
|
|
8
|
-
import pReduce from 'p-reduce';
|
|
9
|
-
import pMap from 'p-map';
|
|
10
|
-
import {cosmiconfig, defaultLoaders} from 'cosmiconfig';
|
|
11
|
-
import defineLazyProperty from 'define-lazy-prop';
|
|
12
|
-
import pFilter from 'p-filter';
|
|
13
7
|
import slash from 'slash';
|
|
14
|
-
import {CONFIG_FILES, MODULE_NAME, DEFAULT_IGNORES} from './lib/constants.js';
|
|
15
8
|
import {
|
|
16
|
-
|
|
9
|
+
parseOptions,
|
|
17
10
|
getIgnores,
|
|
18
11
|
mergeWithFileConfig,
|
|
19
|
-
mergeWithFileConfigs,
|
|
20
|
-
buildConfig,
|
|
21
|
-
mergeOptions,
|
|
22
12
|
} from './lib/options-manager.js';
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
const
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
13
|
+
import {mergeReports, processReport, getIgnoredReport} from './lib/report.js';
|
|
14
|
+
|
|
15
|
+
const runEslint = async (lint, options) => {
|
|
16
|
+
const {filePath, eslintOptions, isQuiet} = options;
|
|
17
|
+
const {cwd, baseConfig: {ignorePatterns}} = eslintOptions;
|
|
18
|
+
|
|
19
|
+
if (
|
|
20
|
+
filePath
|
|
21
|
+
&& (
|
|
22
|
+
micromatch.isMatch(path.relative(cwd, filePath), ignorePatterns)
|
|
23
|
+
|| isGitIgnoredSync({cwd, ignore: ignorePatterns})(filePath)
|
|
24
|
+
)
|
|
25
|
+
) {
|
|
26
|
+
return getIgnoredReport(filePath);
|
|
36
27
|
}
|
|
37
28
|
|
|
38
|
-
|
|
39
|
-
};
|
|
29
|
+
const eslint = new ESLint(eslintOptions);
|
|
40
30
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
errorCount: 0,
|
|
44
|
-
warningCount: 0,
|
|
45
|
-
fixableErrorCount: 0,
|
|
46
|
-
fixableWarningCount: 0,
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
for (const result of results) {
|
|
50
|
-
statistics.errorCount += result.errorCount;
|
|
51
|
-
statistics.warningCount += result.warningCount;
|
|
52
|
-
statistics.fixableErrorCount += result.fixableErrorCount;
|
|
53
|
-
statistics.fixableWarningCount += result.fixableWarningCount;
|
|
31
|
+
if (filePath && await eslint.isPathIgnored(filePath)) {
|
|
32
|
+
return getIgnoredReport(filePath);
|
|
54
33
|
}
|
|
55
34
|
|
|
56
|
-
|
|
35
|
+
const report = await lint(eslint);
|
|
36
|
+
return processReport(report, {isQuiet});
|
|
57
37
|
};
|
|
58
38
|
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
report = ESLint.getErrorResults(report);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
const result = {
|
|
65
|
-
results: report,
|
|
66
|
-
...getReportStatistics(report),
|
|
67
|
-
};
|
|
39
|
+
const globFiles = async (patterns, options) => {
|
|
40
|
+
const {ignores, extensions, cwd} = (await mergeWithFileConfig(options)).options;
|
|
68
41
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
for (const {usedDeprecatedRules} of report) {
|
|
74
|
-
for (const rule of usedDeprecatedRules) {
|
|
75
|
-
if (seenRules.has(rule.ruleId)) {
|
|
76
|
-
continue;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
seenRules.add(rule.ruleId);
|
|
80
|
-
rules.push(rule);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
return rules;
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
return result;
|
|
88
|
-
};
|
|
42
|
+
patterns = patterns.length === 0
|
|
43
|
+
? [`**/*.{${extensions.join(',')}}`]
|
|
44
|
+
: arrify(patterns).map(pattern => slash(pattern));
|
|
89
45
|
|
|
90
|
-
const
|
|
91
|
-
|
|
46
|
+
const files = await globby(
|
|
47
|
+
patterns,
|
|
48
|
+
{ignore: ignores, gitignore: true, absolute: true, cwd},
|
|
49
|
+
);
|
|
92
50
|
|
|
93
|
-
|
|
94
|
-
return processReport(report, processorOptions);
|
|
51
|
+
return files.filter(file => extensions.includes(path.extname(file).slice(1)));
|
|
95
52
|
};
|
|
96
53
|
|
|
97
|
-
const globFiles = async (patterns, {ignores, extensions, cwd}) => (
|
|
98
|
-
await globby(
|
|
99
|
-
patterns.length === 0 ? [`**/*.{${extensions.join(',')}}`] : arrify(patterns).map(pattern => slash(pattern)),
|
|
100
|
-
{ignore: ignores, gitignore: true, absolute: true, cwd},
|
|
101
|
-
)).filter(file => extensions.includes(path.extname(file).slice(1)));
|
|
102
|
-
|
|
103
54
|
const getConfig = async options => {
|
|
104
|
-
const {
|
|
105
|
-
const {filePath, warnIgnored, ...eslintOptions} = buildConfig(foundOptions, prettierOptions);
|
|
55
|
+
const {filePath, eslintOptions} = await parseOptions(options);
|
|
106
56
|
const engine = new ESLint(eslintOptions);
|
|
107
57
|
return engine.calculateConfigForFile(filePath);
|
|
108
58
|
};
|
|
109
59
|
|
|
110
|
-
const lintText = async (string,
|
|
111
|
-
|
|
112
|
-
const
|
|
60
|
+
const lintText = async (string, options) => {
|
|
61
|
+
options = await parseOptions(options);
|
|
62
|
+
const {filePath, warnIgnored, eslintOptions} = options;
|
|
63
|
+
const {ignorePatterns} = eslintOptions.baseConfig;
|
|
113
64
|
|
|
114
|
-
if (
|
|
65
|
+
if (typeof filePath !== 'string' && !isEqual(getIgnores({}), ignorePatterns)) {
|
|
115
66
|
throw new Error('The `ignores` option requires the `filePath` option to be defined.');
|
|
116
67
|
}
|
|
117
68
|
|
|
118
|
-
|
|
119
|
-
|
|
69
|
+
return runEslint(
|
|
70
|
+
eslint => eslint.lintText(string, {filePath, warnIgnored}),
|
|
71
|
+
options,
|
|
72
|
+
);
|
|
73
|
+
};
|
|
120
74
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
micromatch.isMatch(filename, options.baseConfig.ignorePatterns)
|
|
126
|
-
|| isGitIgnoredSync({cwd: options.cwd, ignore: options.baseConfig.ignorePatterns})(filePath)
|
|
127
|
-
|| await engine.isPathIgnored(filePath)
|
|
128
|
-
) {
|
|
129
|
-
return {
|
|
130
|
-
errorCount: 0,
|
|
131
|
-
warningCount: 0,
|
|
132
|
-
results: [{
|
|
133
|
-
errorCount: 0,
|
|
134
|
-
filePath: filename,
|
|
135
|
-
messages: [],
|
|
136
|
-
warningCount: 0,
|
|
137
|
-
}],
|
|
138
|
-
};
|
|
139
|
-
}
|
|
140
|
-
}
|
|
75
|
+
const lintFile = async (filePath, options) => runEslint(
|
|
76
|
+
eslint => eslint.lintFiles([filePath]),
|
|
77
|
+
await parseOptions({...options, filePath}),
|
|
78
|
+
);
|
|
141
79
|
|
|
142
|
-
|
|
80
|
+
const lintFiles = async (patterns, options) => {
|
|
81
|
+
const files = await globFiles(patterns, options);
|
|
143
82
|
|
|
144
|
-
|
|
145
|
-
|
|
83
|
+
const reports = await Promise.all(
|
|
84
|
+
files.map(filePath => lintFile(filePath, options)),
|
|
85
|
+
);
|
|
146
86
|
|
|
147
|
-
const
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
const configFiles = (await Promise.all(
|
|
152
|
-
(await globby(
|
|
153
|
-
CONFIG_FILES.map(configFile => `**/${configFile}`),
|
|
154
|
-
{ignore: DEFAULT_IGNORES, gitignore: true, absolute: true, cwd: inputOptions.cwd},
|
|
155
|
-
)).map(configFile => configExplorer.load(configFile)),
|
|
156
|
-
)).filter(Boolean);
|
|
157
|
-
|
|
158
|
-
const paths = configFiles.length > 0
|
|
159
|
-
? await pReduce(
|
|
160
|
-
configFiles,
|
|
161
|
-
async (paths, {filepath, config}) =>
|
|
162
|
-
[...paths, ...(await globFiles(patterns, {...mergeOptions(inputOptions, config), cwd: path.dirname(filepath)}))],
|
|
163
|
-
[])
|
|
164
|
-
: await globFiles(patterns, mergeOptions(inputOptions));
|
|
165
|
-
|
|
166
|
-
return mergeReports(await pMap(await mergeWithFileConfigs([...new Set(paths)], inputOptions, configFiles), async ({files, options, prettierOptions}) => runEslint(files, buildConfig(options, prettierOptions), {isQuiet: options.quiet})));
|
|
87
|
+
const report = mergeReports(reports.filter(({isIgnored}) => !isIgnored));
|
|
88
|
+
|
|
89
|
+
return report;
|
|
167
90
|
};
|
|
168
91
|
|
|
169
92
|
const getFormatter = async name => {
|
package/lib/options-manager.js
CHANGED
|
@@ -3,21 +3,19 @@ import os from 'node:os';
|
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import fsExtra from 'fs-extra';
|
|
5
5
|
import arrify from 'arrify';
|
|
6
|
-
import {mergeWith,
|
|
6
|
+
import {mergeWith, flow, pick} from 'lodash-es';
|
|
7
7
|
import pathExists from 'path-exists';
|
|
8
8
|
import findUp from 'find-up';
|
|
9
9
|
import findCacheDir from 'find-cache-dir';
|
|
10
10
|
import prettier from 'prettier';
|
|
11
11
|
import semver from 'semver';
|
|
12
|
-
import {cosmiconfig,
|
|
13
|
-
import pReduce from 'p-reduce';
|
|
12
|
+
import {cosmiconfig, defaultLoaders} from 'cosmiconfig';
|
|
14
13
|
import micromatch from 'micromatch';
|
|
15
14
|
import JSON5 from 'json5';
|
|
16
15
|
import toAbsoluteGlob from 'to-absolute-glob';
|
|
17
16
|
import stringify from 'json-stable-stringify-without-jsonify';
|
|
18
17
|
import murmur from 'imurmurhash';
|
|
19
|
-
import
|
|
20
|
-
import eslintrc from '@eslint/eslintrc';
|
|
18
|
+
import {Legacy} from '@eslint/eslintrc';
|
|
21
19
|
import createEsmUtils from 'esm-utils';
|
|
22
20
|
import {
|
|
23
21
|
DEFAULT_IGNORES,
|
|
@@ -33,10 +31,8 @@ import {
|
|
|
33
31
|
} from './constants.js';
|
|
34
32
|
|
|
35
33
|
const {__dirname, json, require} = createEsmUtils(import.meta);
|
|
36
|
-
const
|
|
37
|
-
const
|
|
38
|
-
const {normalizePackageName} = eslintrc.Legacy.naming;
|
|
39
|
-
const resolveModule = eslintrc.Legacy.ModuleResolver.resolve;
|
|
34
|
+
const {normalizePackageName} = Legacy.naming;
|
|
35
|
+
const resolveModule = Legacy.ModuleResolver.resolve;
|
|
40
36
|
|
|
41
37
|
const resolveFrom = (moduleId, fromDirectory = process.cwd()) => resolveModule(moduleId, path.join(fromDirectory, '__placeholder__.js'));
|
|
42
38
|
|
|
@@ -105,18 +101,18 @@ const isTypescript = file => TYPESCRIPT_EXTENSION.includes(path.extname(file).sl
|
|
|
105
101
|
Find config for `lintText`.
|
|
106
102
|
The config files are searched starting from `options.filePath` if defined or `options.cwd` otherwise.
|
|
107
103
|
*/
|
|
108
|
-
const mergeWithFileConfig = options => {
|
|
104
|
+
const mergeWithFileConfig = async options => {
|
|
109
105
|
options.cwd = path.resolve(options.cwd || process.cwd());
|
|
110
|
-
const configExplorer =
|
|
111
|
-
const pkgConfigExplorer =
|
|
106
|
+
const configExplorer = cosmiconfig(MODULE_NAME, {searchPlaces: CONFIG_FILES, loaders: {noExt: defaultLoaders['.json']}, stopDir: options.cwd});
|
|
107
|
+
const pkgConfigExplorer = cosmiconfig('engines', {searchPlaces: ['package.json'], stopDir: options.cwd});
|
|
112
108
|
if (options.filePath) {
|
|
113
109
|
options.filePath = path.resolve(options.cwd, options.filePath);
|
|
114
110
|
}
|
|
115
111
|
|
|
116
112
|
const searchPath = options.filePath || options.cwd;
|
|
117
113
|
|
|
118
|
-
const {config: xoOptions, filepath: xoConfigPath} = configExplorer.search(searchPath) || {};
|
|
119
|
-
const {config: enginesOptions} = pkgConfigExplorer.search(searchPath) || {};
|
|
114
|
+
const {config: xoOptions, filepath: xoConfigPath} = (await configExplorer.search(searchPath)) || {};
|
|
115
|
+
const {config: enginesOptions} = (await pkgConfigExplorer.search(searchPath)) || {};
|
|
120
116
|
|
|
121
117
|
options = mergeOptions(options, xoOptions, enginesOptions);
|
|
122
118
|
options.cwd = xoConfigPath && path.dirname(xoConfigPath) !== options.cwd ? path.resolve(options.cwd, path.dirname(xoConfigPath)) : options.cwd;
|
|
@@ -125,91 +121,31 @@ const mergeWithFileConfig = options => {
|
|
|
125
121
|
({options} = applyOverrides(options.filePath, options));
|
|
126
122
|
}
|
|
127
123
|
|
|
128
|
-
const prettierOptions = options.prettier ? prettier.resolveConfig
|
|
124
|
+
const prettierOptions = options.prettier ? await prettier.resolveConfig(searchPath, {editorconfig: true}) || {} : {};
|
|
129
125
|
|
|
130
126
|
if (options.filePath && isTypescript(options.filePath)) {
|
|
131
|
-
const tsConfigExplorer =
|
|
132
|
-
const {config: tsConfig, filepath: tsConfigPath} = tsConfigExplorer.search(options.filePath) || {};
|
|
127
|
+
const tsConfigExplorer = cosmiconfig([], {searchPlaces: ['tsconfig.json'], loaders: {'.json': (_, content) => JSON5.parse(content)}});
|
|
128
|
+
const {config: tsConfig, filepath: tsConfigPath} = (await tsConfigExplorer.search(options.filePath)) || {};
|
|
133
129
|
|
|
134
|
-
options.tsConfigPath = getTsConfigCachePath([options.filePath], options.tsConfigPath, options.cwd);
|
|
130
|
+
options.tsConfigPath = await getTsConfigCachePath([options.filePath], options.tsConfigPath, options.cwd);
|
|
135
131
|
options.ts = true;
|
|
136
|
-
|
|
132
|
+
await fsExtra.outputJson(options.tsConfigPath, makeTSConfig(tsConfig, tsConfigPath, [options.filePath]));
|
|
137
133
|
}
|
|
138
134
|
|
|
139
135
|
return {options, prettierOptions};
|
|
140
136
|
};
|
|
141
137
|
|
|
142
|
-
/**
|
|
143
|
-
Find config for each files found by `lintFiles`.
|
|
144
|
-
The config files are searched starting from each files.
|
|
145
|
-
*/
|
|
146
|
-
const mergeWithFileConfigs = async (files, options, configFiles) => {
|
|
147
|
-
configFiles = configFiles.sort((a, b) => b.filepath.split(path.sep).length - a.filepath.split(path.sep).length);
|
|
148
|
-
const tsConfigs = {};
|
|
149
|
-
|
|
150
|
-
const groups = [...(await pReduce(files, async (configs, file) => {
|
|
151
|
-
const pkgConfigExplorer = cosmiconfig('engines', {searchPlaces: ['package.json'], stopDir: options.cwd});
|
|
152
|
-
|
|
153
|
-
const {config: xoOptions, filepath: xoConfigPath} = findApplicableConfig(file, configFiles) || {};
|
|
154
|
-
const {config: enginesOptions, filepath: enginesConfigPath} = await pkgConfigExplorer.search(file) || {};
|
|
155
|
-
|
|
156
|
-
let fileOptions = mergeOptions(options, xoOptions, enginesOptions);
|
|
157
|
-
fileOptions.cwd = xoConfigPath && path.dirname(xoConfigPath) !== fileOptions.cwd ? path.resolve(fileOptions.cwd, path.dirname(xoConfigPath)) : fileOptions.cwd;
|
|
158
|
-
|
|
159
|
-
const {hash, options: optionsWithOverrides} = applyOverrides(file, fileOptions);
|
|
160
|
-
fileOptions = optionsWithOverrides;
|
|
161
|
-
|
|
162
|
-
const prettierOptions = fileOptions.prettier ? await prettier.resolveConfig(file, {editorconfig: true}) || {} : {};
|
|
163
|
-
|
|
164
|
-
let tsConfigPath;
|
|
165
|
-
if (isTypescript(file)) {
|
|
166
|
-
let tsConfig;
|
|
167
|
-
const tsConfigExplorer = cosmiconfig([], {searchPlaces: ['tsconfig.json'], loaders: {'.json': (_, content) => JSON5.parse(content)}});
|
|
168
|
-
({config: tsConfig, filepath: tsConfigPath} = await tsConfigExplorer.search(file) || {});
|
|
169
|
-
|
|
170
|
-
fileOptions.tsConfigPath = tsConfigPath;
|
|
171
|
-
tsConfigs[tsConfigPath || ''] = tsConfig;
|
|
172
|
-
fileOptions.ts = true;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
const cacheKey = stringify({xoConfigPath, enginesConfigPath, prettierOptions, hash, tsConfigPath: fileOptions.tsConfigPath, ts: fileOptions.ts});
|
|
176
|
-
const cachedGroup = configs.get(cacheKey);
|
|
177
|
-
|
|
178
|
-
configs.set(cacheKey, {
|
|
179
|
-
files: [file, ...(cachedGroup ? cachedGroup.files : [])],
|
|
180
|
-
options: cachedGroup ? cachedGroup.options : fileOptions,
|
|
181
|
-
prettierOptions,
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
return configs;
|
|
185
|
-
}, new Map())).values()];
|
|
186
|
-
|
|
187
|
-
await Promise.all(Object.entries(groupBy(groups.filter(({options}) => Boolean(options.ts)), group => group.options.tsConfigPath || '')).map(
|
|
188
|
-
([tsConfigPath, groups]) => {
|
|
189
|
-
const files = groups.flatMap(group => group.files);
|
|
190
|
-
const cachePath = getTsConfigCachePath(files, tsConfigPath, options.cwd);
|
|
191
|
-
|
|
192
|
-
for (const group of groups) {
|
|
193
|
-
group.options.tsConfigPath = cachePath;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
return outputJson(cachePath, makeTSConfig(tsConfigs[tsConfigPath], tsConfigPath, files));
|
|
197
|
-
},
|
|
198
|
-
));
|
|
199
|
-
|
|
200
|
-
return groups;
|
|
201
|
-
};
|
|
202
|
-
|
|
203
|
-
const findApplicableConfig = (file, configFiles) => configFiles.find(({filepath}) => isPathInside(file, path.dirname(filepath)));
|
|
204
|
-
|
|
205
138
|
/**
|
|
206
139
|
Generate a unique and consistent path for the temporary `tsconfig.json`.
|
|
207
140
|
Hashing based on https://github.com/eslint/eslint/blob/cf38d0d939b62f3670cdd59f0143fd896fccd771/lib/cli-engine/lint-result-cache.js#L30
|
|
208
141
|
*/
|
|
209
|
-
const getTsConfigCachePath = (files, tsConfigPath, cwd) =>
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
)
|
|
142
|
+
const getTsConfigCachePath = async (files, tsConfigPath, cwd) => {
|
|
143
|
+
const {version} = await json.load('../package.json');
|
|
144
|
+
return path.join(
|
|
145
|
+
cacheLocation(cwd),
|
|
146
|
+
`tsconfig.${murmur(`${version}_${nodeVersion}_${stringify({files: files.sort(), tsConfigPath})}`).result().toString(36)}.json`,
|
|
147
|
+
);
|
|
148
|
+
};
|
|
213
149
|
|
|
214
150
|
const makeTSConfig = (tsConfig, tsConfigPath, files) => {
|
|
215
151
|
const config = {files: files.filter(file => isTypescript(file))};
|
|
@@ -493,7 +429,7 @@ const mergeWithPrettierConfig = (options, prettierOptions) => {
|
|
|
493
429
|
singleQuote: true,
|
|
494
430
|
bracketSpacing: false,
|
|
495
431
|
jsxBracketSameLine: false,
|
|
496
|
-
trailingComma: '
|
|
432
|
+
trailingComma: 'all',
|
|
497
433
|
tabWidth: normalizeSpaces(options),
|
|
498
434
|
useTabs: !options.space,
|
|
499
435
|
semi: options.semicolon !== false,
|
|
@@ -604,14 +540,27 @@ const gatherImportResolvers = options => {
|
|
|
604
540
|
return resolvers;
|
|
605
541
|
};
|
|
606
542
|
|
|
543
|
+
const parseOptions = async options => {
|
|
544
|
+
options = normalizeOptions(options);
|
|
545
|
+
const {options: foundOptions, prettierOptions} = await mergeWithFileConfig(options);
|
|
546
|
+
const {filePath, warnIgnored, ...eslintOptions} = buildConfig(foundOptions, prettierOptions);
|
|
547
|
+
return {
|
|
548
|
+
filePath,
|
|
549
|
+
warnIgnored,
|
|
550
|
+
isQuiet: options.quiet,
|
|
551
|
+
eslintOptions,
|
|
552
|
+
};
|
|
553
|
+
};
|
|
554
|
+
|
|
607
555
|
export {
|
|
556
|
+
parseOptions,
|
|
557
|
+
getIgnores,
|
|
558
|
+
mergeWithFileConfig,
|
|
559
|
+
|
|
560
|
+
// For tests
|
|
561
|
+
applyOverrides,
|
|
608
562
|
findApplicableOverrides,
|
|
609
563
|
mergeWithPrettierConfig,
|
|
610
564
|
normalizeOptions,
|
|
611
|
-
getIgnores,
|
|
612
|
-
mergeWithFileConfigs,
|
|
613
|
-
mergeWithFileConfig,
|
|
614
565
|
buildConfig,
|
|
615
|
-
applyOverrides,
|
|
616
|
-
mergeOptions,
|
|
617
566
|
};
|
package/lib/report.js
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import defineLazyProperty from 'define-lazy-prop';
|
|
2
|
+
import {ESLint} from 'eslint';
|
|
3
|
+
|
|
4
|
+
/** Merge multiple reports into a single report */
|
|
5
|
+
const mergeReports = reports => {
|
|
6
|
+
const report = {
|
|
7
|
+
results: [],
|
|
8
|
+
errorCount: 0,
|
|
9
|
+
warningCount: 0,
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
for (const currentReport of reports) {
|
|
13
|
+
report.results.push(...currentReport.results);
|
|
14
|
+
report.errorCount += currentReport.errorCount;
|
|
15
|
+
report.warningCount += currentReport.warningCount;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return report;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const processReport = (report, {isQuiet = false} = {}) => {
|
|
22
|
+
if (isQuiet) {
|
|
23
|
+
report = ESLint.getErrorResults(report);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const result = {
|
|
27
|
+
results: report,
|
|
28
|
+
...getReportStatistics(report),
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
defineLazyProperty(result, 'usedDeprecatedRules', () => {
|
|
32
|
+
const seenRules = new Set();
|
|
33
|
+
const rules = [];
|
|
34
|
+
|
|
35
|
+
for (const {usedDeprecatedRules} of report) {
|
|
36
|
+
for (const rule of usedDeprecatedRules) {
|
|
37
|
+
if (seenRules.has(rule.ruleId)) {
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
seenRules.add(rule.ruleId);
|
|
42
|
+
rules.push(rule);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return rules;
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
return result;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const getReportStatistics = results => {
|
|
53
|
+
const statistics = {
|
|
54
|
+
errorCount: 0,
|
|
55
|
+
warningCount: 0,
|
|
56
|
+
fixableErrorCount: 0,
|
|
57
|
+
fixableWarningCount: 0,
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
for (const result of results) {
|
|
61
|
+
statistics.errorCount += result.errorCount;
|
|
62
|
+
statistics.warningCount += result.warningCount;
|
|
63
|
+
statistics.fixableErrorCount += result.fixableErrorCount;
|
|
64
|
+
statistics.fixableWarningCount += result.fixableWarningCount;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return statistics;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const getIgnoredReport = filePath => ({
|
|
71
|
+
errorCount: 0,
|
|
72
|
+
warningCount: 0,
|
|
73
|
+
results: [
|
|
74
|
+
{
|
|
75
|
+
errorCount: 0,
|
|
76
|
+
warningCount: 0,
|
|
77
|
+
filePath,
|
|
78
|
+
messages: [],
|
|
79
|
+
},
|
|
80
|
+
],
|
|
81
|
+
isIgnored: true,
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
export {mergeReports, processReport, getIgnoredReport};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "xo",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.44.0",
|
|
4
4
|
"description": "JavaScript/TypeScript linter (ESLint wrapper) with great defaults",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": "xojs/xo",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"node": ">=12.20"
|
|
17
17
|
},
|
|
18
18
|
"scripts": {
|
|
19
|
-
"test": "
|
|
19
|
+
"test": "node cli.js && nyc ava"
|
|
20
20
|
},
|
|
21
21
|
"files": [
|
|
22
22
|
"config",
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"typescript"
|
|
53
53
|
],
|
|
54
54
|
"dependencies": {
|
|
55
|
-
"@eslint/eslintrc": "^0.
|
|
55
|
+
"@eslint/eslintrc": "^1.0.0",
|
|
56
56
|
"@typescript-eslint/eslint-plugin": "^4.29.0",
|
|
57
57
|
"@typescript-eslint/parser": "^4.29.0",
|
|
58
58
|
"arrify": "^3.0.0",
|
|
@@ -61,8 +61,8 @@
|
|
|
61
61
|
"define-lazy-prop": "^3.0.0",
|
|
62
62
|
"eslint": "^7.32.0",
|
|
63
63
|
"eslint-config-prettier": "^8.3.0",
|
|
64
|
-
"eslint-config-xo": "^0.
|
|
65
|
-
"eslint-config-xo-typescript": "^0.
|
|
64
|
+
"eslint-config-xo": "^0.38.0",
|
|
65
|
+
"eslint-config-xo-typescript": "^0.44.0",
|
|
66
66
|
"eslint-formatter-pretty": "^4.1.0",
|
|
67
67
|
"eslint-import-resolver-webpack": "^0.13.1",
|
|
68
68
|
"eslint-plugin-ava": "^12.0.0",
|
|
@@ -72,7 +72,7 @@
|
|
|
72
72
|
"eslint-plugin-node": "^11.1.0",
|
|
73
73
|
"eslint-plugin-prettier": "^3.4.0",
|
|
74
74
|
"eslint-plugin-promise": "^5.1.0",
|
|
75
|
-
"eslint-plugin-unicorn": "^
|
|
75
|
+
"eslint-plugin-unicorn": "^35.0.0",
|
|
76
76
|
"esm-utils": "^1.1.0",
|
|
77
77
|
"find-cache-dir": "^3.3.1",
|
|
78
78
|
"find-up": "^5.0.0",
|
|
@@ -87,9 +87,6 @@
|
|
|
87
87
|
"meow": "^10.1.1",
|
|
88
88
|
"micromatch": "^4.0.4",
|
|
89
89
|
"open-editor": "^3.0.0",
|
|
90
|
-
"p-filter": "^2.1.0",
|
|
91
|
-
"p-map": "^5.1.0",
|
|
92
|
-
"p-reduce": "^3.0.0",
|
|
93
90
|
"path-exists": "^4.0.0",
|
|
94
91
|
"prettier": "^2.3.2",
|
|
95
92
|
"semver": "^7.3.5",
|
|
@@ -106,20 +103,15 @@
|
|
|
106
103
|
"nyc": "^15.1.0",
|
|
107
104
|
"proxyquire": "^2.1.3",
|
|
108
105
|
"temp-write": "^5.0.0",
|
|
109
|
-
"webpack": "^5.
|
|
106
|
+
"webpack": "^5.49.0"
|
|
110
107
|
},
|
|
111
|
-
"
|
|
112
|
-
"
|
|
113
|
-
"
|
|
114
|
-
"
|
|
115
|
-
"
|
|
108
|
+
"xo": {
|
|
109
|
+
"ignores": [
|
|
110
|
+
"test/fixtures",
|
|
111
|
+
"test/temp",
|
|
112
|
+
"coverage"
|
|
116
113
|
]
|
|
117
114
|
},
|
|
118
|
-
"eslintIgnore": [
|
|
119
|
-
"test/fixtures",
|
|
120
|
-
"test/temp",
|
|
121
|
-
"coverage"
|
|
122
|
-
],
|
|
123
115
|
"ava": {
|
|
124
116
|
"files": [
|
|
125
117
|
"!test/temp"
|
package/readme.md
CHANGED
|
@@ -225,7 +225,7 @@ The [Prettier options](https://prettier.io/docs/en/options.html) will be read fr
|
|
|
225
225
|
- [semi](https://prettier.io/docs/en/options.html#semicolons): based on [semicolon](#semicolon) option
|
|
226
226
|
- [useTabs](https://prettier.io/docs/en/options.html#tabs): based on [space](#space) option
|
|
227
227
|
- [tabWidth](https://prettier.io/docs/en/options.html#tab-width): based on [space](#space) option
|
|
228
|
-
- [trailingComma](https://prettier.io/docs/en/options.html#trailing-commas): `
|
|
228
|
+
- [trailingComma](https://prettier.io/docs/en/options.html#trailing-commas): `all`
|
|
229
229
|
- [singleQuote](https://prettier.io/docs/en/options.html#quotes): `true`
|
|
230
230
|
- [bracketSpacing](https://prettier.io/docs/en/options.html#bracket-spacing): `false`
|
|
231
231
|
- [jsxBracketSameLine](https://prettier.io/docs/en/options.html#jsx-brackets): `false`
|