From 304c92646884bb3d1f6bd808cc3e56e1b1210460 Mon Sep 17 00:00:00 2001 From: devinrhode2 Date: Thu, 7 Oct 2021 23:21:54 -0500 Subject: [PATCH 1/5] Revert "Refactor (#585)" +unresolved conflicts This reverts commit 3859d0642da86b7ff0372154c6a0f266769e6d30. --- index.js | 183 ++++++++++++++++++++++++++++------------ lib/options-manager.js | 59 ++++++------- lib/report.js | 84 ------------------ package.json | 6 ++ test/options-manager.js | 32 +++---- 5 files changed, 180 insertions(+), 184 deletions(-) delete mode 100644 lib/report.js diff --git a/index.js b/index.js index 2675f9d1..e3757bff 100644 --- a/index.js +++ b/index.js @@ -1,92 +1,171 @@ +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 {omit, isEqual} from 'lodash-es'; import micromatch from 'micromatch'; import arrify from 'arrify'; +import pMap from 'p-map'; +import defineLazyProperty from 'define-lazy-prop'; import slash from 'slash'; import { - parseOptions, + normalizeOptions, getIgnores, mergeWithFileConfig, + buildConfig, } from './lib/options-manager.js'; -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); +/** 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; } - const eslint = new ESLint(eslintOptions); + return report; +}; - if (filePath && await eslint.isPathIgnored(filePath)) { - return getIgnoredReport(filePath); +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; } - const report = await lint(eslint); - return processReport(report, {isQuiet}); + return statistics; }; -const globFiles = async (patterns, options) => { - const {ignores, extensions, cwd} = (await mergeWithFileConfig(options)).options; +const processReport = (report, {isQuiet = false} = {}) => { + if (isQuiet) { + report = ESLint.getErrorResults(report); + } - patterns = patterns.length === 0 - ? [`**/*.{${extensions.join(',')}}`] - : arrify(patterns).map(pattern => slash(pattern)); + const result = { + results: report, + ...getReportStatistics(report), + }; - const files = await globby( - patterns, - {ignore: ignores, gitignore: true, absolute: true, cwd}, - ); + 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; +}; + +const runEslint = async (filePath, options, processorOptions) => { + const engine = new ESLint(omit(options, ['filePath', 'warnIgnored'])); + const filename = path.relative(options.cwd, filePath); - return files.filter(file => extensions.includes(path.extname(file).slice(1))); + if ( + micromatch.isMatch(filename, options.baseConfig.ignorePatterns) + || isGitIgnoredSync({cwd: options.cwd, ignore: options.baseConfig.ignorePatterns})(filePath) + || await engine.isPathIgnored(filePath) + ) { + return; + } + + const report = await engine.lintFiles([filePath]); + return processReport(report, processorOptions); }; +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 {filePath, eslintOptions} = await parseOptions(options); + const {options: foundOptions, prettierOptions} = mergeWithFileConfig(normalizeOptions(options)); + const {filePath, warnIgnored, ...eslintOptions} = buildConfig(foundOptions, prettierOptions); const engine = new ESLint(eslintOptions); return engine.calculateConfigForFile(filePath); }; -const lintText = async (string, options) => { - options = await parseOptions(options); - const {filePath, warnIgnored, eslintOptions} = options; - const {ignorePatterns} = eslintOptions.baseConfig; +const lintText = async (string, inputOptions = {}) => { + const {options: foundOptions, prettierOptions} = mergeWithFileConfig(normalizeOptions(inputOptions)); + const options = buildConfig(foundOptions, prettierOptions); - if (typeof filePath !== 'string' && !isEqual(getIgnores({}), ignorePatterns)) { + if (options.baseConfig.ignorePatterns && !isEqual(getIgnores({}), options.baseConfig.ignorePatterns) && typeof options.filePath !== 'string') { throw new Error('The `ignores` option requires the `filePath` option to be defined.'); } - return runEslint( - eslint => eslint.lintText(string, {filePath, warnIgnored}), - options, - ); -}; + const {filePath, warnIgnored, ...eslintOptions} = options; + const engine = new ESLint(eslintOptions); -const lintFile = async (filePath, options) => runEslint( - eslint => eslint.lintFiles([filePath]), - await parseOptions({...options, filePath}), -); + 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 lintFiles = async (patterns, options) => { - const files = await globFiles(patterns, options); + const report = await engine.lintText(string, {filePath, warnIgnored}); - const reports = await Promise.all( - files.map(filePath => lintFile(filePath, options)), - ); + return processReport(report, {isQuiet: inputOptions.quiet}); +}; - const report = mergeReports(reports.filter(({isIgnored}) => !isIgnored)); +const lintFiles = async (patterns, inputOptions = {}) => { + inputOptions = normalizeOptions(inputOptions); + inputOptions.cwd = path.resolve(inputOptions.cwd || process.cwd()); + + const files = await globFiles(patterns, mergeWithFileConfig(inputOptions).options); + + const reports = await pMap( + files, + async filePath => { + const {options: foundOptions, prettierOptions} = mergeWithFileConfig({ + ...inputOptions, + filePath, + }); + const options = buildConfig(foundOptions, prettierOptions); + return runEslint(filePath, options, {isQuiet: inputOptions.quiet}); + }, + ); - return report; + return mergeReports(reports.filter(Boolean)); }; const getFormatter = async name => { diff --git a/lib/options-manager.js b/lib/options-manager.js index 664cf423..b4c79d6e 100644 --- a/lib/options-manager.js +++ b/lib/options-manager.js @@ -8,7 +8,7 @@ import {findUpSync} from 'find-up'; import findCacheDir from 'find-cache-dir'; import prettier from 'prettier'; import semver from 'semver'; -import {cosmiconfig, defaultLoaders} from 'cosmiconfig'; +import {cosmiconfigSync, defaultLoaders} from 'cosmiconfig'; import micromatch from 'micromatch'; import JSON5 from 'json5'; import toAbsoluteGlob from 'to-absolute-glob'; @@ -29,8 +29,15 @@ import { } from './constants.js'; const {__dirname, json, require} = createEsmUtils(import.meta); +<<<<<<< HEAD const {normalizePackageName} = Legacy.naming; const resolveModule = Legacy.ModuleResolver.resolve; +======= +const pkg = json.loadSync('../package.json'); +const {outputJsonSync} = fsExtra; +const {normalizePackageName} = eslintrc.Legacy.naming; +const resolveModule = eslintrc.Legacy.ModuleResolver.resolve; +>>>>>>> parent of 3859d06 (Refactor (#585)) const resolveFrom = (moduleId, fromDirectory = process.cwd()) => resolveModule(moduleId, path.join(fromDirectory, '__placeholder__.js')); @@ -99,18 +106,18 @@ const isTypescript = file => TYPESCRIPT_EXTENSION.includes(path.extname(file).sl Find config for `lintText`. The config files are searched starting from `options.filePath` if defined or `options.cwd` otherwise. */ -const mergeWithFileConfig = async options => { +const mergeWithFileConfig = options => { options.cwd = path.resolve(options.cwd || process.cwd()); - const configExplorer = cosmiconfig(MODULE_NAME, {searchPlaces: CONFIG_FILES, loaders: {noExt: defaultLoaders['.json']}, stopDir: options.cwd}); - const pkgConfigExplorer = cosmiconfig('engines', {searchPlaces: ['package.json'], stopDir: options.cwd}); + const configExplorer = cosmiconfigSync(MODULE_NAME, {searchPlaces: CONFIG_FILES, loaders: {noExt: defaultLoaders['.json']}, stopDir: options.cwd}); + const pkgConfigExplorer = cosmiconfigSync('engines', {searchPlaces: ['package.json'], stopDir: options.cwd}); if (options.filePath) { options.filePath = path.resolve(options.cwd, options.filePath); } const searchPath = options.filePath || options.cwd; - const {config: xoOptions, filepath: xoConfigPath} = (await configExplorer.search(searchPath)) || {}; - const {config: enginesOptions} = (await pkgConfigExplorer.search(searchPath)) || {}; + const {config: xoOptions, filepath: xoConfigPath} = configExplorer.search(searchPath) || {}; + const {config: enginesOptions} = pkgConfigExplorer.search(searchPath) || {}; options = mergeOptions(options, xoOptions, enginesOptions); options.cwd = xoConfigPath && path.dirname(xoConfigPath) !== options.cwd ? path.resolve(options.cwd, path.dirname(xoConfigPath)) : options.cwd; @@ -119,17 +126,21 @@ const mergeWithFileConfig = async options => { ({options} = applyOverrides(options.filePath, options)); } - const prettierOptions = options.prettier ? await prettier.resolveConfig(searchPath, {editorconfig: true}) || {} : {}; + const prettierOptions = options.prettier ? prettier.resolveConfig.sync(searchPath, {editorconfig: true}) || {} : {}; if (options.filePath && isTypescript(options.filePath)) { - const tsConfigExplorer = cosmiconfig([], {searchPlaces: ['tsconfig.json'], loaders: {'.json': (_, content) => JSON5.parse(content)}}); - const {config: tsConfig, filepath: tsConfigPath} = (await tsConfigExplorer.search(options.filePath)) || {}; + const tsConfigExplorer = cosmiconfigSync([], {searchPlaces: ['tsconfig.json'], loaders: {'.json': (_, content) => JSON5.parse(content)}}); + const {config: tsConfig, filepath: tsConfigPath} = tsConfigExplorer.search(options.filePath) || {}; - options.tsConfigPath = await getTsConfigCachePath([options.filePath], options.tsConfigPath, options.cwd); + options.tsConfigPath = getTsConfigCachePath([options.filePath], options.tsConfigPath, options.cwd); options.ts = true; +<<<<<<< HEAD const config = makeTSConfig(tsConfig, tsConfigPath, [options.filePath]); await fs.mkdir(path.dirname(options.tsConfigPath), {recursive: true}); await fs.writeFile(options.tsConfigPath, JSON.stringify(config)); +======= + outputJsonSync(options.tsConfigPath, makeTSConfig(tsConfig, tsConfigPath, [options.filePath])); +>>>>>>> parent of 3859d06 (Refactor (#585)) } return {options, prettierOptions}; @@ -139,13 +150,10 @@ const mergeWithFileConfig = async options => { Generate a unique and consistent path for the temporary `tsconfig.json`. Hashing based on https://github.com/eslint/eslint/blob/cf38d0d939b62f3670cdd59f0143fd896fccd771/lib/cli-engine/lint-result-cache.js#L30 */ -const getTsConfigCachePath = async (files, tsConfigPath, cwd) => { - const {version} = await json.load('../package.json'); - return path.join( - cacheLocation(cwd), - `tsconfig.${murmur(`${version}_${nodeVersion}_${stringify({files: files.sort(), tsConfigPath})}`).result().toString(36)}.json`, - ); -}; +const getTsConfigCachePath = (files, tsConfigPath, cwd) => path.join( + cacheLocation(cwd), + `tsconfig.${murmur(`${pkg.version}_${nodeVersion}_${stringify({files: files.sort(), tsConfigPath})}`).result().toString(36)}.json`, +); const makeTSConfig = (tsConfig, tsConfigPath, files) => { const config = {files: files.filter(file => isTypescript(file))}; @@ -536,27 +544,14 @@ const gatherImportResolvers = options => { return resolvers; }; -const parseOptions = async options => { - options = normalizeOptions(options); - const {options: foundOptions, prettierOptions} = await mergeWithFileConfig(options); - const {filePath, warnIgnored, ...eslintOptions} = buildConfig(foundOptions, prettierOptions); - return { - filePath, - warnIgnored, - isQuiet: options.quiet, - eslintOptions, - }; -}; - export { - parseOptions, + normalizeOptions, getIgnores, mergeWithFileConfig, + buildConfig, // For tests applyOverrides, findApplicableOverrides, mergeWithPrettierConfig, - normalizeOptions, - buildConfig, }; diff --git a/lib/report.js b/lib/report.js deleted file mode 100644 index f6daf0fa..00000000 --- a/lib/report.js +++ /dev/null @@ -1,84 +0,0 @@ -import defineLazyProperty from 'define-lazy-prop'; -import {ESLint} from 'eslint'; - -/** 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; - } - - return report; -}; - -const processReport = (report, {isQuiet = false} = {}) => { - if (isQuiet) { - report = ESLint.getErrorResults(report); - } - - const result = { - results: report, - ...getReportStatistics(report), - }; - - 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; -}; - -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; - } - - return statistics; -}; - -const getIgnoredReport = filePath => ({ - errorCount: 0, - warningCount: 0, - results: [ - { - errorCount: 0, - warningCount: 0, - filePath, - messages: [], - }, - ], - isIgnored: true, -}); - -export {mergeReports, processReport, getIgnoredReport}; diff --git a/package.json b/package.json index 0f55e1c1..34a60d92 100644 --- a/package.json +++ b/package.json @@ -84,7 +84,13 @@ "meow": "^10.1.1", "micromatch": "^4.0.4", "open-editor": "^3.0.0", +<<<<<<< HEAD "prettier": "^2.4.1", +======= + "p-map": "^5.1.0", + "path-exists": "^4.0.0", + "prettier": "^2.3.2", +>>>>>>> parent of 3859d06 (Refactor (#585)) "semver": "^7.3.5", "slash": "^4.0.0", "to-absolute-glob": "^2.0.2", diff --git a/test/options-manager.js b/test/options-manager.js index 937245e6..66fdab74 100644 --- a/test/options-manager.js +++ b/test/options-manager.js @@ -493,51 +493,51 @@ test('findApplicableOverrides', t => { ]); }); -test('mergeWithFileConfig: use child if closest', async t => { +test('mergeWithFileConfig: use child if closest', t => { const cwd = path.resolve('fixtures', 'nested', 'child'); - const {options} = await manager.mergeWithFileConfig({cwd}); + const {options} = manager.mergeWithFileConfig({cwd}); const expected = {...childConfig.xo, extensions: DEFAULT_EXTENSION, ignores: DEFAULT_IGNORES, cwd}; t.deepEqual(options, expected); }); -test('mergeWithFileConfig: use parent if closest', async t => { +test('mergeWithFileConfig: use parent if closest', t => { const cwd = path.resolve('fixtures', 'nested'); - const {options} = await manager.mergeWithFileConfig({cwd}); + const {options} = manager.mergeWithFileConfig({cwd}); const expected = {...parentConfig.xo, extensions: DEFAULT_EXTENSION, ignores: DEFAULT_IGNORES, cwd}; t.deepEqual(options, expected); }); -test('mergeWithFileConfig: use parent if child is ignored', async t => { +test('mergeWithFileConfig: use parent if child is ignored', t => { const cwd = path.resolve('fixtures', 'nested'); const filePath = path.resolve(cwd, 'child-ignore', 'file.js'); - const {options} = await manager.mergeWithFileConfig({cwd, filePath}); + const {options} = manager.mergeWithFileConfig({cwd, filePath}); const expected = {...parentConfig.xo, extensions: DEFAULT_EXTENSION, ignores: DEFAULT_IGNORES, cwd, filePath}; t.deepEqual(options, expected); }); -test('mergeWithFileConfig: use child if child is empty', async t => { +test('mergeWithFileConfig: use child if child is empty', t => { const cwd = path.resolve('fixtures', 'nested', 'child-empty'); - const {options} = await manager.mergeWithFileConfig({cwd}); + const {options} = manager.mergeWithFileConfig({cwd}); t.deepEqual(options, {extensions: DEFAULT_EXTENSION, ignores: DEFAULT_IGNORES, cwd}); }); -test('mergeWithFileConfig: read engines from package.json', async t => { +test('mergeWithFileConfig: read engines from package.json', t => { const cwd = path.resolve('fixtures', 'engines'); - const {options} = await manager.mergeWithFileConfig({cwd}); + const {options} = manager.mergeWithFileConfig({cwd}); const expected = {nodeVersion: enginesConfig.engines.node, extensions: DEFAULT_EXTENSION, ignores: DEFAULT_IGNORES, cwd}; t.deepEqual(options, expected); }); -test('mergeWithFileConfig: XO engine options supersede package.json\'s', async t => { +test('mergeWithFileConfig: XO engine options supersede package.json\'s', t => { const cwd = path.resolve('fixtures', 'engines'); - const {options} = await manager.mergeWithFileConfig({cwd, nodeVersion: '>=8'}); + const {options} = manager.mergeWithFileConfig({cwd, nodeVersion: '>=8'}); const expected = {nodeVersion: '>=8', extensions: DEFAULT_EXTENSION, ignores: DEFAULT_IGNORES, cwd}; t.deepEqual(options, expected); }); -test('mergeWithFileConfig: XO engine options false supersede package.json\'s', async t => { +test('mergeWithFileConfig: XO engine options false supersede package.json\'s', t => { const cwd = path.resolve('fixtures', 'engines'); - const {options} = await manager.mergeWithFileConfig({cwd, nodeVersion: false}); + const {options} = manager.mergeWithFileConfig({cwd, nodeVersion: false}); const expected = {nodeVersion: false, extensions: DEFAULT_EXTENSION, ignores: DEFAULT_IGNORES, cwd}; t.deepEqual(options, expected); }); @@ -545,7 +545,7 @@ test('mergeWithFileConfig: XO engine options false supersede package.json\'s', a test('mergeWithFileConfig: typescript files', async t => { const cwd = path.resolve('fixtures', 'typescript', 'child'); const filePath = path.resolve(cwd, 'file.ts'); - const {options} = await manager.mergeWithFileConfig({cwd, filePath}); + const {options} = manager.mergeWithFileConfig({cwd, filePath}); const expected = { filePath, extensions: DEFAULT_EXTENSION, @@ -567,7 +567,7 @@ test('mergeWithFileConfig: typescript files', async t => { test('mergeWithFileConfig: tsx files', async t => { const cwd = path.resolve('fixtures', 'typescript', 'child'); const filePath = path.resolve(cwd, 'file.tsx'); - const {options} = await manager.mergeWithFileConfig({cwd, filePath}); + const {options} = manager.mergeWithFileConfig({cwd, filePath}); const expected = { filePath, extensions: DEFAULT_EXTENSION, From 6cd14cda8d548bb0f81cbe2922bf40e6ea8c369e Mon Sep 17 00:00:00 2001 From: devinrhode2 Date: Thu, 7 Oct 2021 23:22:53 -0500 Subject: [PATCH 2/5] resolve conflicts --- lib/options-manager.js | 12 +----------- package.json | 7 +------ 2 files changed, 2 insertions(+), 17 deletions(-) diff --git a/lib/options-manager.js b/lib/options-manager.js index b4c79d6e..fd08da85 100644 --- a/lib/options-manager.js +++ b/lib/options-manager.js @@ -29,15 +29,9 @@ import { } from './constants.js'; const {__dirname, json, require} = createEsmUtils(import.meta); -<<<<<<< HEAD +const pkg = json.loadSync('../package.json'); const {normalizePackageName} = Legacy.naming; const resolveModule = Legacy.ModuleResolver.resolve; -======= -const pkg = json.loadSync('../package.json'); -const {outputJsonSync} = fsExtra; -const {normalizePackageName} = eslintrc.Legacy.naming; -const resolveModule = eslintrc.Legacy.ModuleResolver.resolve; ->>>>>>> parent of 3859d06 (Refactor (#585)) const resolveFrom = (moduleId, fromDirectory = process.cwd()) => resolveModule(moduleId, path.join(fromDirectory, '__placeholder__.js')); @@ -134,13 +128,9 @@ const mergeWithFileConfig = options => { options.tsConfigPath = getTsConfigCachePath([options.filePath], options.tsConfigPath, options.cwd); options.ts = true; -<<<<<<< HEAD const config = makeTSConfig(tsConfig, tsConfigPath, [options.filePath]); await fs.mkdir(path.dirname(options.tsConfigPath), {recursive: true}); await fs.writeFile(options.tsConfigPath, JSON.stringify(config)); -======= - outputJsonSync(options.tsConfigPath, makeTSConfig(tsConfig, tsConfigPath, [options.filePath])); ->>>>>>> parent of 3859d06 (Refactor (#585)) } return {options, prettierOptions}; diff --git a/package.json b/package.json index 34a60d92..0c1f45f5 100644 --- a/package.json +++ b/package.json @@ -84,13 +84,8 @@ "meow": "^10.1.1", "micromatch": "^4.0.4", "open-editor": "^3.0.0", -<<<<<<< HEAD - "prettier": "^2.4.1", -======= "p-map": "^5.1.0", - "path-exists": "^4.0.0", - "prettier": "^2.3.2", ->>>>>>> parent of 3859d06 (Refactor (#585)) + "prettier": "^2.4.1", "semver": "^7.3.5", "slash": "^4.0.0", "to-absolute-glob": "^2.0.2", From dc5688f8cd5404fb2b64e4636830eaf47575c48c Mon Sep 17 00:00:00 2001 From: devinrhode2 Date: Thu, 7 Oct 2021 23:23:21 -0500 Subject: [PATCH 3/5] Revert "Correctly use `ignores` config, Lint `xo` with `xo` (#584)" This reverts commit 48baacc6ab46a66d88cbdeaa3b0e67f66d5c3c44. --- index.js | 3 +- lib/options-manager.js | 7 ++-- package.json | 17 +++++--- test/fixtures/nested-ignores/a.js | 1 - test/fixtures/nested-ignores/b.js | 1 - test/fixtures/nested-ignores/child/a.js | 1 - test/fixtures/nested-ignores/child/b.js | 1 - .../nested-ignores/child/package.json | 8 ---- test/fixtures/nested-ignores/package.json | 8 ---- test/ignores.js | 40 ------------------- 10 files changed, 16 insertions(+), 71 deletions(-) delete mode 100644 test/fixtures/nested-ignores/a.js delete mode 100644 test/fixtures/nested-ignores/b.js delete mode 100644 test/fixtures/nested-ignores/child/a.js delete mode 100644 test/fixtures/nested-ignores/child/b.js delete mode 100644 test/fixtures/nested-ignores/child/package.json delete mode 100644 test/fixtures/nested-ignores/package.json delete mode 100644 test/ignores.js diff --git a/index.js b/index.js index e3757bff..d13017e2 100644 --- a/index.js +++ b/index.js @@ -13,6 +13,7 @@ import { getIgnores, mergeWithFileConfig, buildConfig, + mergeOptions, } from './lib/options-manager.js'; /** Merge multiple reports into a single report */ @@ -151,7 +152,7 @@ const lintFiles = async (patterns, inputOptions = {}) => { inputOptions = normalizeOptions(inputOptions); inputOptions.cwd = path.resolve(inputOptions.cwd || process.cwd()); - const files = await globFiles(patterns, mergeWithFileConfig(inputOptions).options); + const files = await globFiles(patterns, mergeOptions(inputOptions)); const reports = await pMap( files, diff --git a/lib/options-manager.js b/lib/options-manager.js index fd08da85..4a959d35 100644 --- a/lib/options-manager.js +++ b/lib/options-manager.js @@ -535,13 +535,12 @@ const gatherImportResolvers = options => { }; export { + findApplicableOverrides, + mergeWithPrettierConfig, normalizeOptions, getIgnores, mergeWithFileConfig, buildConfig, - - // For tests applyOverrides, - findApplicableOverrides, - mergeWithPrettierConfig, + mergeOptions, }; diff --git a/package.json b/package.json index 0c1f45f5..2b20b827 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "node": ">=12.20" }, "scripts": { - "test": "node cli.js && nyc ava" + "test": "eslint --quiet . --ext .js,.cjs && nyc ava" }, "files": [ "config", @@ -102,13 +102,18 @@ "temp-write": "^5.0.0", "webpack": "^5.56.0" }, - "xo": { - "ignores": [ - "test/fixtures", - "test/temp", - "coverage" + "eslintConfig": { + "extends": [ + "eslint-config-xo", + "./config/plugins.cjs", + "./config/overrides.cjs" ] }, + "eslintIgnore": [ + "test/fixtures", + "test/temp", + "coverage" + ], "ava": { "files": [ "!test/temp" diff --git a/test/fixtures/nested-ignores/a.js b/test/fixtures/nested-ignores/a.js deleted file mode 100644 index b00bfec5..00000000 --- a/test/fixtures/nested-ignores/a.js +++ /dev/null @@ -1 +0,0 @@ -console.log('semicolon') diff --git a/test/fixtures/nested-ignores/b.js b/test/fixtures/nested-ignores/b.js deleted file mode 100644 index b00bfec5..00000000 --- a/test/fixtures/nested-ignores/b.js +++ /dev/null @@ -1 +0,0 @@ -console.log('semicolon') diff --git a/test/fixtures/nested-ignores/child/a.js b/test/fixtures/nested-ignores/child/a.js deleted file mode 100644 index b00bfec5..00000000 --- a/test/fixtures/nested-ignores/child/a.js +++ /dev/null @@ -1 +0,0 @@ -console.log('semicolon') diff --git a/test/fixtures/nested-ignores/child/b.js b/test/fixtures/nested-ignores/child/b.js deleted file mode 100644 index b00bfec5..00000000 --- a/test/fixtures/nested-ignores/child/b.js +++ /dev/null @@ -1 +0,0 @@ -console.log('semicolon') diff --git a/test/fixtures/nested-ignores/child/package.json b/test/fixtures/nested-ignores/child/package.json deleted file mode 100644 index f0a313fe..00000000 --- a/test/fixtures/nested-ignores/child/package.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "xo": { - "ignores": [ - "b.js", - "**/b.js" - ] - } -} diff --git a/test/fixtures/nested-ignores/package.json b/test/fixtures/nested-ignores/package.json deleted file mode 100644 index f852068c..00000000 --- a/test/fixtures/nested-ignores/package.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "xo": { - "ignores": [ - "a.js", - "**/a.js" - ] - } -} diff --git a/test/ignores.js b/test/ignores.js deleted file mode 100644 index d6f98bb9..00000000 --- a/test/ignores.js +++ /dev/null @@ -1,40 +0,0 @@ -import path from 'node:path'; -import test from 'ava'; -import createEsmUtils from 'esm-utils'; -import {globby} from 'globby'; -import xo from '../index.js'; - -const {__dirname} = createEsmUtils(import.meta); - -test('Should pickup "ignores" config', async t => { - const cwd = path.join(__dirname, 'fixtures/nested-ignores'); - - t.deepEqual( - await globby(['**/*.js'], {cwd}), - ['a.js', 'b.js', 'child/a.js', 'child/b.js'], - 'Should has 4 js files.', - ); - - // Should not match - // `a.js` (ignored by config in current directory) - // `child/a.js` (ignored by config in current directory) - // `child/b.js` (ignored by config in child directory) - const result = await xo.lintFiles('.', {cwd}); - const files = result.results.map(({filePath}) => filePath); - t.deepEqual(files, [path.join(cwd, 'b.js')], 'Should only report on `b.js`.'); -}); - -test('Should ignore "ignores" config in parent', async t => { - const cwd = path.join(__dirname, 'fixtures/nested-ignores/child'); - - t.deepEqual( - await globby(['**/*.js'], {cwd}), - ['a.js', 'b.js'], - 'Should has 2 js files.', - ); - - // Should only match `a.js` even it's ignored in parent - const result = await xo.lintFiles('.', {cwd}); - const files = result.results.map(({filePath}) => filePath); - t.deepEqual(files, [path.join(cwd, 'a.js')], 'Should only report on `a.js`.'); -}); From d3233515dc2abb44cfe5f45a26dbf5f81ca50ceb Mon Sep 17 00:00:00 2001 From: devinrhode2 Date: Thu, 7 Oct 2021 23:28:28 -0500 Subject: [PATCH 4/5] Revert "Simplify `lintFiles` (#583)"+unresolved conflicts This reverts commit e2e715dbff660187d432a6bdad6c3da435f80194. --- index.js | 57 +++++++-------- lib/options-manager.js | 84 +++++++++++++++++++++- package.json | 7 ++ test/options-manager.js | 153 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 270 insertions(+), 31 deletions(-) diff --git a/index.js b/index.js index d13017e2..538f6b35 100644 --- a/index.js +++ b/index.js @@ -2,16 +2,21 @@ import process from 'node:process'; import path from 'node:path'; import {ESLint} from 'eslint'; import {globby, isGitIgnoredSync} from 'globby'; -import {omit, isEqual} from 'lodash-es'; +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, getIgnores, mergeWithFileConfig, + mergeWithFileConfigs, buildConfig, mergeOptions, } from './lib/options-manager.js'; @@ -82,19 +87,10 @@ const processReport = (report, {isQuiet = false} = {}) => { return result; }; -const runEslint = async (filePath, options, processorOptions) => { - const engine = new ESLint(omit(options, ['filePath', 'warnIgnored'])); - const filename = path.relative(options.cwd, filePath); +const runEslint = async (paths, options, processorOptions) => { + const engine = new ESLint(options); - if ( - micromatch.isMatch(filename, options.baseConfig.ignorePatterns) - || isGitIgnoredSync({cwd: options.cwd, ignore: options.baseConfig.ignorePatterns})(filePath) - || await engine.isPathIgnored(filePath) - ) { - return; - } - - const report = await engine.lintFiles([filePath]); + const report = await engine.lintFiles(await pFilter(paths, async path => !(await engine.isPathIgnored(path)))); return processReport(report, processorOptions); }; @@ -149,24 +145,25 @@ const lintText = async (string, inputOptions = {}) => { }; const lintFiles = async (patterns, inputOptions = {}) => { - inputOptions = normalizeOptions(inputOptions); inputOptions.cwd = path.resolve(inputOptions.cwd || process.cwd()); - - const files = await globFiles(patterns, mergeOptions(inputOptions)); - - const reports = await pMap( - files, - async filePath => { - const {options: foundOptions, prettierOptions} = mergeWithFileConfig({ - ...inputOptions, - filePath, - }); - const options = buildConfig(foundOptions, prettierOptions); - return runEslint(filePath, options, {isQuiet: inputOptions.quiet}); - }, - ); - - return mergeReports(reports.filter(Boolean)); + 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 getFormatter = async name => { diff --git a/lib/options-manager.js b/lib/options-manager.js index 4a959d35..b8cea120 100644 --- a/lib/options-manager.js +++ b/lib/options-manager.js @@ -3,18 +3,30 @@ import process from 'node:process'; import os from 'node:os'; import path from 'node:path'; import arrify from 'arrify'; +<<<<<<< HEAD import {mergeWith, flow, pick} from 'lodash-es'; import {findUpSync} from 'find-up'; +======= +import {mergeWith, groupBy, flow, pick} from 'lodash-es'; +import pathExists from 'path-exists'; +import findUp from 'find-up'; +>>>>>>> parent of e2e715d (Simplify `lintFiles` (#583)) import findCacheDir from 'find-cache-dir'; import prettier from 'prettier'; import semver from 'semver'; -import {cosmiconfigSync, defaultLoaders} from 'cosmiconfig'; +import {cosmiconfig, cosmiconfigSync, defaultLoaders} from 'cosmiconfig'; +import pReduce from 'p-reduce'; import micromatch from 'micromatch'; import JSON5 from 'json5'; import toAbsoluteGlob from 'to-absolute-glob'; import stringify from 'json-stable-stringify-without-jsonify'; import murmur from 'imurmurhash'; +<<<<<<< HEAD import {Legacy} from '@eslint/eslintrc'; +======= +import isPathInside from 'is-path-inside'; +import eslintrc from '@eslint/eslintrc'; +>>>>>>> parent of e2e715d (Simplify `lintFiles` (#583)) import createEsmUtils from 'esm-utils'; import { DEFAULT_IGNORES, @@ -30,8 +42,14 @@ import { const {__dirname, json, require} = createEsmUtils(import.meta); const pkg = json.loadSync('../package.json'); +<<<<<<< HEAD const {normalizePackageName} = Legacy.naming; const resolveModule = Legacy.ModuleResolver.resolve; +======= +const {outputJson, outputJsonSync} = fsExtra; +const {normalizePackageName} = eslintrc.Legacy.naming; +const resolveModule = eslintrc.Legacy.ModuleResolver.resolve; +>>>>>>> parent of e2e715d (Simplify `lintFiles` (#583)) const resolveFrom = (moduleId, fromDirectory = process.cwd()) => resolveModule(moduleId, path.join(fromDirectory, '__placeholder__.js')); @@ -136,6 +154,69 @@ const mergeWithFileConfig = options => { return {options, prettierOptions}; }; +/** +Find config for each files found by `lintFiles`. +The config files are searched starting from each files. +*/ +const mergeWithFileConfigs = async (files, options, configFiles) => { + configFiles = configFiles.sort((a, b) => b.filepath.split(path.sep).length - a.filepath.split(path.sep).length); + const tsConfigs = {}; + + const groups = [...(await pReduce(files, async (configs, file) => { + const pkgConfigExplorer = cosmiconfig('engines', {searchPlaces: ['package.json'], stopDir: options.cwd}); + + const {config: xoOptions, filepath: xoConfigPath} = findApplicableConfig(file, configFiles) || {}; + const {config: enginesOptions, filepath: enginesConfigPath} = await pkgConfigExplorer.search(file) || {}; + + let fileOptions = mergeOptions(options, xoOptions, enginesOptions); + fileOptions.cwd = xoConfigPath && path.dirname(xoConfigPath) !== fileOptions.cwd ? path.resolve(fileOptions.cwd, path.dirname(xoConfigPath)) : fileOptions.cwd; + + const {hash, options: optionsWithOverrides} = applyOverrides(file, fileOptions); + fileOptions = optionsWithOverrides; + + const prettierOptions = fileOptions.prettier ? await prettier.resolveConfig(file, {editorconfig: true}) || {} : {}; + + let tsConfigPath; + if (isTypescript(file)) { + let tsConfig; + const tsConfigExplorer = cosmiconfig([], {searchPlaces: ['tsconfig.json'], loaders: {'.json': (_, content) => JSON5.parse(content)}}); + ({config: tsConfig, filepath: tsConfigPath} = await tsConfigExplorer.search(file) || {}); + + fileOptions.tsConfigPath = tsConfigPath; + tsConfigs[tsConfigPath || ''] = tsConfig; + fileOptions.ts = true; + } + + const cacheKey = stringify({xoConfigPath, enginesConfigPath, prettierOptions, hash, tsConfigPath: fileOptions.tsConfigPath, ts: fileOptions.ts}); + const cachedGroup = configs.get(cacheKey); + + configs.set(cacheKey, { + files: [file, ...(cachedGroup ? cachedGroup.files : [])], + options: cachedGroup ? cachedGroup.options : fileOptions, + prettierOptions, + }); + + return configs; + }, new Map())).values()]; + + await Promise.all(Object.entries(groupBy(groups.filter(({options}) => Boolean(options.ts)), group => group.options.tsConfigPath || '')).map( + ([tsConfigPath, groups]) => { + const files = groups.flatMap(group => group.files); + const cachePath = getTsConfigCachePath(files, tsConfigPath, options.cwd); + + for (const group of groups) { + group.options.tsConfigPath = cachePath; + } + + return outputJson(cachePath, makeTSConfig(tsConfigs[tsConfigPath], tsConfigPath, files)); + }, + )); + + return groups; +}; + +const findApplicableConfig = (file, configFiles) => configFiles.find(({filepath}) => isPathInside(file, path.dirname(filepath))); + /** Generate a unique and consistent path for the temporary `tsconfig.json`. Hashing based on https://github.com/eslint/eslint/blob/cf38d0d939b62f3670cdd59f0143fd896fccd771/lib/cli-engine/lint-result-cache.js#L30 @@ -539,6 +620,7 @@ export { mergeWithPrettierConfig, normalizeOptions, getIgnores, + mergeWithFileConfigs, mergeWithFileConfig, buildConfig, applyOverrides, diff --git a/package.json b/package.json index 2b20b827..abd8b758 100644 --- a/package.json +++ b/package.json @@ -84,8 +84,15 @@ "meow": "^10.1.1", "micromatch": "^4.0.4", "open-editor": "^3.0.0", + "p-filter": "^2.1.0", "p-map": "^5.1.0", +<<<<<<< HEAD "prettier": "^2.4.1", +======= + "p-reduce": "^3.0.0", + "path-exists": "^4.0.0", + "prettier": "^2.3.2", +>>>>>>> parent of e2e715d (Simplify `lintFiles` (#583)) "semver": "^7.3.5", "slash": "^4.0.0", "to-absolute-glob": "^2.0.2", diff --git a/test/options-manager.js b/test/options-manager.js index 66fdab74..e95fa334 100644 --- a/test/options-manager.js +++ b/test/options-manager.js @@ -586,6 +586,159 @@ test('mergeWithFileConfig: tsx files', async t => { }); }); +test('mergeWithFileConfigs: nested configs with prettier', async t => { + const cwd = path.resolve('fixtures', 'nested-configs'); + const paths = [ + 'no-semicolon.js', + 'child/semicolon.js', + 'child-override/two-spaces.js', + 'child-override/child-prettier-override/semicolon.js', + ].map(file => path.resolve(cwd, file)); + const result = await manager.mergeWithFileConfigs(paths, {cwd}, [ + { + filepath: path.resolve(cwd, 'child-override', 'child-prettier-override', 'package.json'), + config: {overrides: [{files: 'semicolon.js', prettier: true}]}, + }, + {filepath: path.resolve(cwd, 'package.json'), config: {semicolon: true}}, + { + filepath: path.resolve(cwd, 'child-override', 'package.json'), + config: {overrides: [{files: 'two-spaces.js', space: 4}]}, + }, + {filepath: path.resolve(cwd, 'child', 'package.json'), config: {semicolon: false}}, + ]); + + t.deepEqual(result, [ + { + files: [path.resolve(cwd, 'no-semicolon.js')], + options: { + semicolon: true, + cwd, + extensions: DEFAULT_EXTENSION, + ignores: DEFAULT_IGNORES, + }, + prettierOptions: {}, + }, + { + files: [path.resolve(cwd, 'child/semicolon.js')], + options: { + semicolon: false, + cwd: path.resolve(cwd, 'child'), + extensions: DEFAULT_EXTENSION, + ignores: DEFAULT_IGNORES, + }, + prettierOptions: {}, + }, + { + files: [path.resolve(cwd, 'child-override/two-spaces.js')], + options: { + space: 4, + rules: {}, + settings: {}, + globals: [], + envs: [], + plugins: [], + extends: [], + cwd: path.resolve(cwd, 'child-override'), + extensions: DEFAULT_EXTENSION, + ignores: DEFAULT_IGNORES, + }, + prettierOptions: {}, + }, + { + files: [path.resolve(cwd, 'child-override/child-prettier-override/semicolon.js')], + options: { + prettier: true, + rules: {}, + settings: {}, + globals: [], + envs: [], + plugins: [], + extends: [], + cwd: path.resolve(cwd, 'child-override', 'child-prettier-override'), + extensions: DEFAULT_EXTENSION, + ignores: DEFAULT_IGNORES, + }, + prettierOptions: {endOfLine: 'lf', semi: false, useTabs: true}, + }, + ]); +}); + +test('mergeWithFileConfigs: typescript files', async t => { + const cwd = path.resolve('fixtures', 'typescript'); + const paths = ['two-spaces.tsx', 'child/extra-semicolon.ts', 'child/sub-child/four-spaces.ts'].map(file => path.resolve(cwd, file)); + const configFiles = [ + {filepath: path.resolve(cwd, 'child/sub-child/package.json'), config: {space: 2}}, + {filepath: path.resolve(cwd, 'package.json'), config: {space: 4}}, + {filepath: path.resolve(cwd, 'child/package.json'), config: {semicolon: false}}, + ]; + const result = await manager.mergeWithFileConfigs(paths, {cwd}, configFiles); + + t.deepEqual(omit(result[0], 'options.tsConfigPath'), { + files: [path.resolve(cwd, 'two-spaces.tsx')], + options: { + space: 4, + cwd, + extensions: DEFAULT_EXTENSION, + ignores: DEFAULT_IGNORES, + ts: true, + }, + prettierOptions: {}, + }); + t.deepEqual(await readJson(result[0].options.tsConfigPath), { + files: [path.resolve(cwd, 'two-spaces.tsx')], + compilerOptions: { + newLine: 'lf', + noFallthroughCasesInSwitch: true, + noImplicitReturns: true, + noUnusedLocals: true, + noUnusedParameters: true, + strict: true, + target: 'es2018', + }, + }); + + t.deepEqual(omit(result[1], 'options.tsConfigPath'), { + files: [path.resolve(cwd, 'child/extra-semicolon.ts')], + options: { + semicolon: false, + cwd: path.resolve(cwd, 'child'), + extensions: DEFAULT_EXTENSION, + ignores: DEFAULT_IGNORES, + ts: true, + }, + prettierOptions: {}, + }); + + t.deepEqual(omit(result[2], 'options.tsConfigPath'), { + files: [path.resolve(cwd, 'child/sub-child/four-spaces.ts')], + options: { + space: 2, + cwd: path.resolve(cwd, 'child/sub-child'), + extensions: DEFAULT_EXTENSION, + ignores: DEFAULT_IGNORES, + ts: true, + }, + prettierOptions: {}, + }); + + // Verify that we use the same temporary tsconfig.json for both files group sharing the same original tsconfig.json even if they have different xo config + t.is(result[1].options.tsConfigPath, result[2].options.tsConfigPath); + t.deepEqual(await readJson(result[1].options.tsConfigPath), { + extends: path.resolve(cwd, 'child/tsconfig.json'), + files: [path.resolve(cwd, 'child/extra-semicolon.ts'), path.resolve(cwd, 'child/sub-child/four-spaces.ts')], + include: [ + slash(path.resolve(cwd, 'child/**/*.ts')), + slash(path.resolve(cwd, 'child/**/*.tsx')), + ], + }); + + const secondResult = await manager.mergeWithFileConfigs(paths, {cwd}, configFiles); + + // Verify that on each run the options.tsConfigPath is consistent to preserve ESLint cache + t.is(result[0].options.tsConfigPath, secondResult[0].options.tsConfigPath); + t.is(result[1].options.tsConfigPath, secondResult[1].options.tsConfigPath); +}); + test('applyOverrides', t => { t.deepEqual( manager.applyOverrides( From 8dc8ac13790e74f4c8256d6f8419fb63a8f57819 Mon Sep 17 00:00:00 2001 From: devinrhode2 Date: Thu, 7 Oct 2021 23:28:32 -0500 Subject: [PATCH 5/5] resolve conflicts+add back in fs-extra Some old code was using fs-extra, so had to bring back in Once memory regression is resolved, this can be uninstalled again --- lib/options-manager.js | 20 +++----------------- package.json | 8 ++------ 2 files changed, 5 insertions(+), 23 deletions(-) diff --git a/lib/options-manager.js b/lib/options-manager.js index b8cea120..0836dfe6 100644 --- a/lib/options-manager.js +++ b/lib/options-manager.js @@ -2,15 +2,10 @@ import {existsSync, promises as fs} from 'node:fs'; import process from 'node:process'; import os from 'node:os'; import path from 'node:path'; +import fsExtra from 'fs-extra'; import arrify from 'arrify'; -<<<<<<< HEAD -import {mergeWith, flow, pick} from 'lodash-es'; -import {findUpSync} from 'find-up'; -======= import {mergeWith, groupBy, flow, pick} from 'lodash-es'; -import pathExists from 'path-exists'; -import findUp from 'find-up'; ->>>>>>> parent of e2e715d (Simplify `lintFiles` (#583)) +import {findUpSync} from 'find-up'; import findCacheDir from 'find-cache-dir'; import prettier from 'prettier'; import semver from 'semver'; @@ -21,12 +16,8 @@ import JSON5 from 'json5'; import toAbsoluteGlob from 'to-absolute-glob'; import stringify from 'json-stable-stringify-without-jsonify'; import murmur from 'imurmurhash'; -<<<<<<< HEAD import {Legacy} from '@eslint/eslintrc'; -======= import isPathInside from 'is-path-inside'; -import eslintrc from '@eslint/eslintrc'; ->>>>>>> parent of e2e715d (Simplify `lintFiles` (#583)) import createEsmUtils from 'esm-utils'; import { DEFAULT_IGNORES, @@ -42,14 +33,9 @@ import { const {__dirname, json, require} = createEsmUtils(import.meta); const pkg = json.loadSync('../package.json'); -<<<<<<< HEAD +const {outputJson} = fsExtra; const {normalizePackageName} = Legacy.naming; const resolveModule = Legacy.ModuleResolver.resolve; -======= -const {outputJson, outputJsonSync} = fsExtra; -const {normalizePackageName} = eslintrc.Legacy.naming; -const resolveModule = eslintrc.Legacy.ModuleResolver.resolve; ->>>>>>> parent of e2e715d (Simplify `lintFiles` (#583)) const resolveFrom = (moduleId, fromDirectory = process.cwd()) => resolveModule(moduleId, path.join(fromDirectory, '__placeholder__.js')); diff --git a/package.json b/package.json index abd8b758..c7f428d5 100644 --- a/package.json +++ b/package.json @@ -75,6 +75,7 @@ "esm-utils": "^2.0.0", "find-cache-dir": "^3.3.2", "find-up": "^6.1.0", + "fs-extra": "^10.0.0", "get-stdin": "^9.0.0", "globby": "^12.0.2", "imurmurhash": "^0.1.4", @@ -86,13 +87,8 @@ "open-editor": "^3.0.0", "p-filter": "^2.1.0", "p-map": "^5.1.0", -<<<<<<< HEAD - "prettier": "^2.4.1", -======= "p-reduce": "^3.0.0", - "path-exists": "^4.0.0", - "prettier": "^2.3.2", ->>>>>>> parent of e2e715d (Simplify `lintFiles` (#583)) + "prettier": "^2.4.1", "semver": "^7.3.5", "slash": "^4.0.0", "to-absolute-glob": "^2.0.2",