Skip to content

Commit

Permalink
fix: implement fixes to work with eslint 8.57.0 (#228)
Browse files Browse the repository at this point in the history
  • Loading branch information
cprussin committed Feb 29, 2024
1 parent 5c67daa commit 3288ba1
Show file tree
Hide file tree
Showing 6 changed files with 111 additions and 130 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/nodejs.yml
Expand Up @@ -19,7 +19,7 @@ jobs:
fail-fast: false
matrix:
node-version: [12.x, 14.x, 16.x, 18.x, 19.x, 20.x]
eslint-version: [7, "8.40", 8]
eslint-version: [7, "8.40", "8.55", 8]
jest-version: [27, 28, 29]
jest-watch-typeahead-version: [1, 2]
exclude:
Expand Down
92 changes: 30 additions & 62 deletions src/runner/runESLint.js
@@ -1,30 +1,25 @@
const { ESLint } = require('eslint');
const eslint = require('eslint');
const getESLintOptions = require('../utils/getESLintOptions');

let FlatESLint;
let shouldUseFlatConfig;
const { ESLint } = eslint;
let { loadESLint } = eslint;

try {
// Use a dynamic require here rather than a global require because this
// import path does not exist in eslint v7 which this library still
// supports
//
// ESlint exposes the new FlatESLint API under `eslint/use-at-your-own-risk` by
// using it's [export configuration](https://tinyurl.com/2s45zh9b). However,
// the `import/no-unresolved` rule is [not aware of
// `exports`](https://tinyurl.com/469djpx3) and causes a false error here. So,
// let's ignore that rule for this import.
//
// eslint-disable-next-line global-require, import/no-unresolved
const eslintExperimental = require('eslint/use-at-your-own-risk');
FlatESLint = eslintExperimental.FlatESLint;
shouldUseFlatConfig = eslintExperimental.shouldUseFlatConfig;
} catch {
/* no-op */
}

if (shouldUseFlatConfig === undefined) {
shouldUseFlatConfig = () => Promise.resolve(false);
// loadESLint and ESLint.configType were added in eslint v8.57.0. The block
// below is some compat code to make this library work with flat config and
// versions of eslint prior to 8.57.0.
if (!loadESLint) {
try {
const {
FlatESLint,
shouldUseFlatConfig,
// eslint-disable-next-line global-require, import/no-unresolved
} = require('eslint/use-at-your-own-risk');
FlatESLint.configType = 'flat';
loadESLint = async () =>
(await shouldUseFlatConfig?.()) ? FlatESLint : ESLint;
} catch {
/* no-op */
}
}

/*
Expand Down Expand Up @@ -131,53 +126,26 @@ function removeUndefinedFromObject(object) {
);
}

const getESLintConstructor = async () => {
if (await shouldUseFlatConfig()) {
return FlatESLint;
}

return ESLint;
};

// Remove options that are not constructor args.
const getESLintConstructorArgs = async cliOptions => {
// these are not constructor args for either the legacy or the flat ESLint
// api
const { fixDryRun, format, maxWarnings, quiet, ...legacyConstructorArgs } =
cliOptions;

if (await shouldUseFlatConfig()) {
// these options are supported by the legacy ESLint api but aren't
// supported by the ESLintFlat api
const {
extensions,
ignorePath,
rulePaths,
resolvePluginsRelativeTo,
useEslintrc,
overrideConfig,
...flatConstructorArgs
} = legacyConstructorArgs;
return flatConstructorArgs;
}

return legacyConstructorArgs;
};

let cachedValues;
const getCachedValues = async (config, extraOptions) => {
if (!cachedValues) {
const { cliOptions: baseCliOptions } = getESLintOptions(config);
const ESLintConstructor = (await loadESLint?.()) ?? ESLint;

const { cliOptions: baseCliOptions } = getESLintOptions(
ESLintConstructor.configType,
config,
);
const cliOptions = {
...baseCliOptions,
fix: getComputedFixValue(baseCliOptions),
...removeUndefinedFromObject(extraOptions),
};

const ESLintConstructor = await getESLintConstructor();
const cli = new ESLintConstructor(
await getESLintConstructorArgs(cliOptions),
);
// Remove options that are not constructor args.
const { fixDryRun, format, maxWarnings, quiet, ...constructorArgs } =
cliOptions;

const cli = new ESLintConstructor(constructorArgs);

cachedValues = {
isPathIgnored: cli.isPathIgnored.bind(cli),
Expand Down
4 changes: 2 additions & 2 deletions src/utils/__tests__/normalizeConfig.test.js
@@ -1,7 +1,7 @@
const normalizeConfig = require('../normalizeConfig');

const normalizeCLIOptions = cliOptions =>
normalizeConfig({ cliOptions }).cliOptions;
const normalizeCLIOptions = (cliOptions, configType) =>
normalizeConfig(configType, { cliOptions }).cliOptions;

it('ignores unknown options', () => {
expect(normalizeCLIOptions({ other: true })).not.toMatchObject({
Expand Down
6 changes: 3 additions & 3 deletions src/utils/getESLintOptions.js
Expand Up @@ -3,14 +3,14 @@ const normalizeConfig = require('./normalizeConfig');

const explorer = cosmiconfigSync('jest-runner-eslint');

const getESLintOptions = config => {
const getESLintOptions = (configType, config) => {
const result = explorer.search(config.rootDir);

if (result) {
return normalizeConfig(result.config);
return normalizeConfig(configType, result.config);
}

return normalizeConfig({});
return normalizeConfig(configType, {});
};

module.exports = getESLintOptions;
63 changes: 38 additions & 25 deletions src/utils/normalizeConfig.js
Expand Up @@ -21,11 +21,6 @@ const BASE_CONFIG = {
cacheLocation: {
default: '.eslintcache',
},
ext: {
name: 'extensions',
default: ['.js'],
transform: asArray,
},
fix: {
default: false,
},
Expand All @@ -35,18 +30,10 @@ const BASE_CONFIG = {
format: {
default: undefined,
},
ignorePath: {
default: null,
},
maxWarnings: {
default: -1,
transform: asInt,
},
noEslintrc: {
name: 'useEslintrc',
default: false,
transform: negate,
},
noIgnore: {
name: 'ignore',
default: false,
Expand All @@ -60,16 +47,36 @@ const BASE_CONFIG = {
quiet: {
default: false,
},
resolvePluginsRelativeTo: {
default: undefined,
config: {
name: 'overrideConfigFile',
default: null,
},
};

const LEGACY_CONFIG = {
...BASE_CONFIG,
ext: {
name: 'extensions',
default: ['.js'],
transform: asArray,
},
ignorePath: {
default: null,
},
rulesdir: {
name: 'rulePaths',
default: [],
transform: asArray,
},
config: {
name: 'overrideConfigFile',
resolvePluginsRelativeTo: {
default: undefined,
},
noEslintrc: {
name: 'useEslintrc',
default: false,
transform: negate,
},
reportUnusedDisableDirectives: {
default: null,
},
env: {
Expand Down Expand Up @@ -98,22 +105,28 @@ const BASE_CONFIG = {
default: [],
transform: asArray,
},
reportUnusedDisableDirectives: {
default: null,
},
rules: {
name: 'overrideConfig.rules',
default: {},
},
};

const normalizeCliOptions = rawConfig => {
return Object.keys(BASE_CONFIG).reduce((config, key) => {
const FLAT_CONFIG = {
...BASE_CONFIG,
reportUnusedDisableDirectives: {
name: 'overrideConfig.linterOptions.reportUnusedDisableDirectives',
default: false,
},
};

const normalizeCliOptions = (configType, rawConfig) => {
const configConfig = configType === 'flat' ? FLAT_CONFIG : LEGACY_CONFIG;
return Object.keys(configConfig).reduce((config, key) => {
const {
name = key,
transform = identity,
default: defaultValue,
} = BASE_CONFIG[key];
} = configConfig[key];

const value = rawConfig[key] !== undefined ? rawConfig[key] : defaultValue;

Expand All @@ -123,10 +136,10 @@ const normalizeCliOptions = rawConfig => {
}, {});
};

const normalizeConfig = config => {
const normalizeConfig = (configType, config) => {
return {
...config,
cliOptions: normalizeCliOptions(config.cliOptions || {}),
cliOptions: normalizeCliOptions(configType, config.cliOptions || {}),
};
};

Expand Down

0 comments on commit 3288ba1

Please sign in to comment.