Skip to content

Commit

Permalink
Update to eslint v9 flat config and typescript v5 (#576)
Browse files Browse the repository at this point in the history
* chore: update to eslint v9 flat config and typescript v5

* revert jest setup file
  • Loading branch information
bmish authored Dec 6, 2024
1 parent 6a85bdd commit 083001e
Show file tree
Hide file tree
Showing 28 changed files with 1,398 additions and 1,054 deletions.
13 changes: 0 additions & 13 deletions .eslintignore

This file was deleted.

67 changes: 0 additions & 67 deletions .eslintrc.cjs

This file was deleted.

12 changes: 7 additions & 5 deletions bin/eslint-doc-generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@ import { run } from '../lib/cli.js';
import { generate } from '../lib/generator.js';

// eslint-disable-next-line unicorn/prefer-top-level-await -- TODO: use top-level await once updating TypeScript target to ES2022 (when dropping Node 14 support).
run(process.argv, (path, options) => generate(path, options)).catch((error) => {
if (error instanceof Error) {
console.error(error.message);
run(process.argv, (path, options) => generate(path, options)).catch(
(error: unknown) => {
if (error instanceof Error) {
console.error(error.message);
}
process.exitCode = 1;
}
process.exitCode = 1;
});
);
175 changes: 175 additions & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
// @ts-check

import js from '@eslint/js';
import eslintPluginN from 'eslint-plugin-n';
import eslintPluginJest from 'eslint-plugin-jest';
import eslintPluginUnicorn from 'eslint-plugin-unicorn';
import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended'; // eslint-disable-line import/extensions -- false positive
import * as eslintPluginImport from 'eslint-plugin-import';
import tseslint from 'typescript-eslint';

export default tseslint.config(
// Configs:
js.configs.recommended,
eslintPluginImport.flatConfigs
? eslintPluginImport.flatConfigs.recommended // TODO: use typescript config
: {},
eslintPluginJest.configs['flat/recommended'],
eslintPluginN.configs['flat/recommended'],
eslintPluginPrettierRecommended,
eslintPluginUnicorn.configs['flat/recommended'],
...tseslint.configs.strictTypeChecked,

// Individual rules:
{
rules: {
'n/no-missing-import': 'off', // bug with recognizing node: prefix https://github.com/mysticatea/eslint-plugin-node/issues/275

'prettier/prettier': [
'error',
{
singleQuote: true,
trailingComma: 'es5', // TODO: remove this and use default
},
],

// unicorn rules:
'require-unicode-regexp': 'error',
'unicorn/expiring-todo-comments': 'off',
'unicorn/import-style': 'off',
'unicorn/no-anonymous-default-export': 'off',
'unicorn/no-array-reduce': 'off',
'unicorn/no-nested-ternary': 'off',
'unicorn/no-useless-undefined': 'off', // We use a lot of `return undefined` to satisfy the `consistent-return` rule.
'unicorn/prefer-at': 'off',
'unicorn/prefer-string-raw': 'off',
'unicorn/prefer-string-replace-all': 'off',
'unicorn/prevent-abbreviations': 'off',

// typescript-eslint rules:
'@typescript-eslint/no-unnecessary-condition': 'off', // Dozens of places where the rule's `meta` property needs optional chaining get flagged by this.
'@typescript-eslint/no-unused-vars': 'off',
'@typescript-eslint/prefer-readonly': 'error',
'@typescript-eslint/require-array-sort-compare': 'error',

// Optional eslint rules:
'array-callback-return': 'error',
'block-scoped-var': 'error',
complexity: 'error',
'consistent-return': 'error',
curly: 'error',
'default-case': 'error',
eqeqeq: 'error',
'func-style': ['error', 'declaration'],
'new-parens': 'error',
'no-async-promise-executor': 'error',
'no-eval': 'error',
'no-extend-native': 'error',
'no-extra-bind': 'error',
'no-implicit-coercion': 'error',
'no-implied-eval': 'error',
'no-lone-blocks': 'error',
'no-multiple-empty-lines': 'error',
'no-new-func': 'error',
'no-new-wrappers': 'error',
'no-octal-escape': 'error',
'no-param-reassign': ['error', { props: true }],
'no-return-assign': 'error',
'no-return-await': 'error',
'no-self-compare': 'error',
'no-sequences': 'error',
'no-shadow-restricted-names': 'error',
'no-template-curly-in-string': 'error',
'no-throw-literal': 'error',
'no-unused-expressions': [
'error',
{ allowShortCircuit: true, allowTernary: true },
],
'no-use-before-define': ['error', 'nofunc'],
'no-useless-call': 'error',
'no-useless-catch': 'error',
'no-useless-computed-key': 'error',
'no-useless-concat': 'error',
'no-useless-constructor': 'error',
'no-useless-escape': 'error',
'no-useless-rename': 'error',
'no-useless-return': 'error',
'no-var': 'error',
'no-void': 'error',
'no-with': 'error',
'object-shorthand': 'error',
'prefer-const': 'error',
'prefer-numeric-literals': 'error',
'prefer-promise-reject-errors': 'error',
'prefer-rest-params': 'error',
'prefer-spread': 'error',
'prefer-template': 'error',
quotes: [
'error',
'single', // Must match quote style enforced by prettier.
// Disallow unnecessary template literals.
{ avoidEscape: true, allowTemplateLiterals: false },
],
radix: 'error',
'require-atomic-updates': 'error',
'require-await': 'error',
'spaced-comment': ['error', 'always', { markers: ['*', '!'] }],
'sort-vars': 'error',
yoda: 'error',

// import rules:
'import/default': 'off',
'import/export': 'error',
'import/extensions': ['error', 'always'],
'import/first': 'error',
'import/named': 'error',
'import/namespace': 'off',
'import/newline-after-import': 'error',
'import/no-absolute-path': 'error',
'import/no-cycle': 'off',
'import/no-deprecated': 'off',
'import/no-duplicates': 'error',
'import/no-dynamic-require': 'error',
'import/no-mutable-exports': 'error',
'import/no-named-as-default': 'off',
'import/no-named-as-default-member': 'off',
'import/no-named-default': 'error',
'import/no-self-import': 'error',
'import/no-unassigned-import': 'error',
'import/no-unresolved': 'off',
'import/no-unused-modules': 'error',
'import/no-useless-path-segments': 'error',
'import/no-webpack-loader-syntax': 'error',
},

// typescript-eslint parser options:
languageOptions: {
parserOptions: {
projectService: true,
tsconfigRootDir: import.meta.dirname,
},
},

linterOptions: {
reportUnusedDisableDirectives: 'error',
},
},

// Disabling type-checking for JS files:
{
files: ['**/*.js', '**/*.cjs'],
extends: [tseslint.configs.disableTypeChecked],
},

// Ignore files:
{
ignores: [
// compiled output
'dist/**',

// test
'coverage/**',
'test/fixtures/**',
],
}
);
12 changes: 6 additions & 6 deletions jest.config.cjs → jest.config.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import type { Config } from 'jest';
// https://kulshekhar.github.io/ts-jest/docs/guides/esm-support/
const { createDefaultEsmPreset } = require('ts-jest')
import { createDefaultEsmPreset } from 'ts-jest';

const defaultEsmPreset = createDefaultEsmPreset()
const defaultEsmPreset = createDefaultEsmPreset();

/** @type {import('ts-jest').JestConfigWithTsJest} */

const jestConfig = {
// https://kulshekhar.github.io/ts-jest/docs/guides/esm-support/
const config: Config = {
testEnvironment: 'node',
testMatch: ['<rootDir>/test/**/*-test.ts'],
setupFiles: ['<rootDir>/test/jest.setup.cjs'],
Expand All @@ -32,4 +32,4 @@ const jestConfig = {
},
};

module.exports = jestConfig;
export default config;
2 changes: 1 addition & 1 deletion lib/config-format.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ export const CONFIG_FORMATS = [
'prefix-name',
] as const;

export type ConfigFormat = typeof CONFIG_FORMATS[number];
export type ConfigFormat = (typeof CONFIG_FORMATS)[number];

export function configNameToDisplay(
configName: string,
Expand Down
2 changes: 1 addition & 1 deletion lib/config-list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ function generateConfigListMarkdown(
pluginPrefix
)}\``,
hasDescription ? description || '' : undefined,
].filter((col) => col !== undefined) as string[];
].filter((col) => col !== undefined);
}),
]),
{ align: 'l' } // Left-align headers.
Expand Down
8 changes: 4 additions & 4 deletions lib/generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,15 @@ function stringOrArrayToArrayWithFallback(
stringOrArray instanceof Array // eslint-disable-line unicorn/no-instanceof-array -- using Array.isArray() loses type information about the array.
? stringOrArray
: stringOrArray
? [stringOrArray]
: [];
? [stringOrArray]
: [];
const csvStringItem = asArray.find((item) => item.includes(','));
if (csvStringItem) {
throw new Error(
`Provide property as array, not a CSV string: ${csvStringItem}`
);
}
return asArray && asArray.length > 0 ? asArray : fallback;
return asArray.length > 0 ? asArray : fallback;
}

// eslint-disable-next-line complexity
Expand Down Expand Up @@ -144,7 +144,7 @@ export async function generate(path: string, options?: GenerateOptions) {
})
.filter(
// Filter out deprecated rules from being checked, displayed, or updated if the option is set.
([, rule]) => !ignoreDeprecatedRules || !rule.meta.deprecated
([, rule]) => !ignoreDeprecatedRules || !rule.meta?.deprecated
)
.sort(([a], [b]) => a.toLowerCase().localeCompare(b.toLowerCase()));

Expand Down
4 changes: 3 additions & 1 deletion lib/option-parsers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ export function parseConfigEmojiOptions(
const configsWithDefaultEmojiRemoved: string[] = [];
const configEmojis =
configEmoji?.flatMap((configEmojiItem) => {
const [config, emoji, ...extra] = configEmojiItem;
const [config, emoji, ...extra] = configEmojiItem as
| typeof configEmojiItem
| [configName: string, emoji: string, extra: string[]];

// Check for duplicate configs.
if (configsSeen.has(config)) {
Expand Down
2 changes: 1 addition & 1 deletion lib/package-json.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ export async function getPathWithExactFileNameCasing(path: string) {
return resolve(dir, dirent.name);
}
}
return undefined; // eslint-disable-line unicorn/no-useless-undefined
return undefined;
}

export async function getCurrentPackageVersion(): Promise<string> {
Expand Down
4 changes: 2 additions & 2 deletions lib/plugin-configs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export function getConfigsThatSetARule(
)
)
// Filter out ignored configs.
.filter(([configName]) => !ignoreConfig?.includes(configName))
.filter(([configName]) => !ignoreConfig.includes(configName))
.map(([configName]) => configName)
.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()))
);
Expand Down Expand Up @@ -97,7 +97,7 @@ export function findConfigEmoji(
emoji = `![badge-${configName}][]`;
} else {
// No fallback.
return undefined; // eslint-disable-line unicorn/no-useless-undefined
return undefined;
}
}

Expand Down
Loading

0 comments on commit 083001e

Please sign in to comment.