Skip to content

Commit

Permalink
Revert xojs#584 memory regression
Browse files Browse the repository at this point in the history
+Refactor (xojs#585)
+Correctly use `ignores` config, Lint `xo` with `xo` (xojs#584)
+Simplify `lintFiles` (xojs#583)
  • Loading branch information
fisker authored and devinrhode2 committed Oct 8, 2021
1 parent 2670d3d commit 3d10431
Show file tree
Hide file tree
Showing 12 changed files with 256 additions and 401 deletions.
183 changes: 53 additions & 130 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,169 +1,92 @@
import process from 'node:process';
import path from 'node:path';
import {ESLint} from 'eslint';
import {globby, isGitIgnoredSync} from 'globby';
import {isEqual} from 'lodash-es';
import micromatch from 'micromatch';
import arrify from 'arrify';
import pReduce from 'p-reduce';
import pMap from 'p-map';
import {cosmiconfig, defaultLoaders} from 'cosmiconfig';
import defineLazyProperty from 'define-lazy-prop';
import pFilter from 'p-filter';
import slash from 'slash';
import {CONFIG_FILES, MODULE_NAME, DEFAULT_IGNORES} from './lib/constants.js';
import {
normalizeOptions,
parseOptions,
getIgnores,
mergeWithFileConfig,
mergeWithFileConfigs,
buildConfig,
mergeOptions,
} from './lib/options-manager.js';

/** Merge multiple reports into a single report */
const mergeReports = reports => {
const report = {
results: [],
errorCount: 0,
warningCount: 0,
};

for (const currentReport of reports) {
report.results.push(...currentReport.results);
report.errorCount += currentReport.errorCount;
report.warningCount += currentReport.warningCount;
import {mergeReports, processReport, getIgnoredReport} from './lib/report.js';

const runEslint = async (lint, options) => {
const {filePath, eslintOptions, isQuiet} = options;
const {cwd, baseConfig: {ignorePatterns}} = eslintOptions;

if (
filePath
&& (
micromatch.isMatch(path.relative(cwd, filePath), ignorePatterns)
|| isGitIgnoredSync({cwd, ignore: ignorePatterns})(filePath)
)
) {
return getIgnoredReport(filePath);
}

return report;
};
const eslint = new ESLint(eslintOptions);

const getReportStatistics = results => {
const statistics = {
errorCount: 0,
warningCount: 0,
fixableErrorCount: 0,
fixableWarningCount: 0,
};

for (const result of results) {
statistics.errorCount += result.errorCount;
statistics.warningCount += result.warningCount;
statistics.fixableErrorCount += result.fixableErrorCount;
statistics.fixableWarningCount += result.fixableWarningCount;
if (filePath && await eslint.isPathIgnored(filePath)) {
return getIgnoredReport(filePath);
}

return statistics;
const report = await lint(eslint);
return processReport(report, {isQuiet});
};

const processReport = (report, {isQuiet = false} = {}) => {
if (isQuiet) {
report = ESLint.getErrorResults(report);
}

const result = {
results: report,
...getReportStatistics(report),
};
const globFiles = async (patterns, options) => {
const {ignores, extensions, cwd} = (await mergeWithFileConfig(options)).options;

defineLazyProperty(result, 'usedDeprecatedRules', () => {
const seenRules = new Set();
const rules = [];

for (const {usedDeprecatedRules} of report) {
for (const rule of usedDeprecatedRules) {
if (seenRules.has(rule.ruleId)) {
continue;
}

seenRules.add(rule.ruleId);
rules.push(rule);
}
}

return rules;
});

return result;
};
patterns = patterns.length === 0
? [`**/*.{${extensions.join(',')}}`]
: arrify(patterns).map(pattern => slash(pattern));

const runEslint = async (paths, options, processorOptions) => {
const engine = new ESLint(options);
const files = await globby(
patterns,
{ignore: ignores, gitignore: true, absolute: true, cwd},
);

const report = await engine.lintFiles(await pFilter(paths, async path => !(await engine.isPathIgnored(path))));
return processReport(report, processorOptions);
return files.filter(file => extensions.includes(path.extname(file).slice(1)));
};

const globFiles = async (patterns, {ignores, extensions, cwd}) => (
await globby(
patterns.length === 0 ? [`**/*.{${extensions.join(',')}}`] : arrify(patterns).map(pattern => slash(pattern)),
{ignore: ignores, gitignore: true, absolute: true, cwd},
)).filter(file => extensions.includes(path.extname(file).slice(1)));

const getConfig = async options => {
const {options: foundOptions, prettierOptions} = mergeWithFileConfig(normalizeOptions(options));
const {filePath, warnIgnored, ...eslintOptions} = buildConfig(foundOptions, prettierOptions);
const {filePath, eslintOptions} = await parseOptions(options);
const engine = new ESLint(eslintOptions);
return engine.calculateConfigForFile(filePath);
};

const lintText = async (string, inputOptions = {}) => {
const {options: foundOptions, prettierOptions} = mergeWithFileConfig(normalizeOptions(inputOptions));
const options = buildConfig(foundOptions, prettierOptions);
const lintText = async (string, options) => {
options = await parseOptions(options);
const {filePath, warnIgnored, eslintOptions} = options;
const {ignorePatterns} = eslintOptions.baseConfig;

if (options.baseConfig.ignorePatterns && !isEqual(getIgnores({}), options.baseConfig.ignorePatterns) && typeof options.filePath !== 'string') {
if (typeof filePath !== 'string' && !isEqual(getIgnores({}), ignorePatterns)) {
throw new Error('The `ignores` option requires the `filePath` option to be defined.');
}

const {filePath, warnIgnored, ...eslintOptions} = options;
const engine = new ESLint(eslintOptions);
return runEslint(
eslint => eslint.lintText(string, {filePath, warnIgnored}),
options,
);
};

if (filePath) {
const filename = path.relative(options.cwd, filePath);

if (
micromatch.isMatch(filename, options.baseConfig.ignorePatterns)
|| isGitIgnoredSync({cwd: options.cwd, ignore: options.baseConfig.ignorePatterns})(filePath)
|| await engine.isPathIgnored(filePath)
) {
return {
errorCount: 0,
warningCount: 0,
results: [{
errorCount: 0,
filePath: filename,
messages: [],
warningCount: 0,
}],
};
}
}
const lintFile = async (filePath, options) => runEslint(
eslint => eslint.lintFiles([filePath]),
await parseOptions({...options, filePath}),
);

const report = await engine.lintText(string, {filePath, warnIgnored});
const lintFiles = async (patterns, options) => {
const files = await globFiles(patterns, options);

return processReport(report, {isQuiet: inputOptions.quiet});
};
const reports = await Promise.all(
files.map(filePath => lintFile(filePath, options)),
);

const lintFiles = async (patterns, inputOptions = {}) => {
inputOptions.cwd = path.resolve(inputOptions.cwd || process.cwd());
const configExplorer = cosmiconfig(MODULE_NAME, {searchPlaces: CONFIG_FILES, loaders: {noExt: defaultLoaders['.json']}, stopDir: inputOptions.cwd});

const configFiles = (await Promise.all(
(await globby(
CONFIG_FILES.map(configFile => `**/${configFile}`),
{ignore: DEFAULT_IGNORES, gitignore: true, absolute: true, cwd: inputOptions.cwd},
)).map(configFile => configExplorer.load(configFile)),
)).filter(Boolean);

const paths = configFiles.length > 0
? await pReduce(
configFiles,
async (paths, {filepath, config}) =>
[...paths, ...(await globFiles(patterns, {...mergeOptions(inputOptions, config), cwd: path.dirname(filepath)}))],
[])
: await globFiles(patterns, mergeOptions(inputOptions));

return mergeReports(await pMap(await mergeWithFileConfigs([...new Set(paths)], inputOptions, configFiles), async ({files, options, prettierOptions}) => runEslint(files, buildConfig(options, prettierOptions), {isQuiet: options.quiet})));
const report = mergeReports(reports.filter(({isIgnored}) => !isIgnored));

return report;
};

const getFormatter = async name => {
Expand Down
Loading

0 comments on commit 3d10431

Please sign in to comment.