This commit is contained in:
Alex
2023-12-20 12:23:05 -05:00
parent 02fe9f4799
commit 3ec7c342ba
18 changed files with 1732 additions and 700 deletions

View File

@ -1,15 +1,34 @@
/// <reference path="./types.d.ts" />
import './redirect';
import fs from 'node:fs';
import type { Rule } from 'eslint';
import type { ESLintUtils } from '@typescript-eslint/utils';
import type { ESLintConfig, Rules } from 'eslint-define-config';
import findCacheDirectory from 'find-cache-dir';
import { typescriptRules } from './presets/typescript';
import { unicornRules } from './presets/unicorn';
import { eslintRules } from './presets/eslint';
import { reactRules } from './presets/react';
import { importRules } from './presets/import';
import { jsDocRules } from './presets/jsdoc';
import { graphqlRules } from './presets/graphql';
import { localRules } from './presets/local';
import { error, warn, off } from './constants';
export { error, warn, off };
const unique = <T>(arr: T[]): T[] => [...new Set(arr)];
declare global {
interface Array<T> {
filter(
predicate: BooleanConstructor,
): Exclude<T, null | undefined | false | '' | 0>[];
}
}
const unique = (...arr: (false | undefined | string | string[])[]): string[] => [
...new Set(arr.flat(1).filter(Boolean)),
];
const ensureArray = <T>(value?: T | T[]): T[] =>
value == null ? [] : Array.isArray(value) ? value : [value];
@ -46,8 +65,26 @@ type Config = Omit<ESLintConfig, 'rules'> & {
* @see [Rules](https://eslint.org/docs/latest/user-guide/configuring/rules)
*/
rules?: RuleOptions;
/**
*/
customRules?: {
rule: () => Promise<{
default: Rule.RuleModule | ESLintUtils.RuleModule<string, unknown[]>;
}>;
options?: RuleLevel;
}[];
};
export function defineCustomRule<Options extends readonly unknown[]>(
rule: () => Promise<{
default: Rule.RuleModule | ESLintUtils.RuleModule<string, Options>;
}>,
options?: Options,
) {
return { rule, options };
}
/**
* Returns a ESLint config object.
*
@ -59,6 +96,10 @@ type Config = Omit<ESLintConfig, 'rules'> & {
* 3. [jsx-a11y](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y#supported-rules)
* 4. [unicorn](https://github.com/sindresorhus/eslint-plugin-unicorn#rules)
* 5. [n](https://github.com/eslint-community/eslint-plugin-n#-rules) (Node.js specific)
* 6. [jsdoc](https://github.com/gajus/eslint-plugin-jsdoc#rules)
*
* Non bundled:
* 1. [graphql](https://the-guild.dev/graphql/eslint/rules)
*/
export function extendConfig({
plugins,
@ -66,37 +107,46 @@ export function extendConfig({
rules,
extends: _extends,
overrides,
customRules,
...rest
}: Config = {}): ESLintConfig {
const hasReact = plugins?.includes('react');
const hasReactRefresh = plugins?.includes('react-refresh');
const hasUnicorn = plugins?.includes('unicorn');
const hasJsDoc = plugins?.includes('jsdoc');
const hasGraphQL = plugins?.includes('@graphql-eslint');
const hasNext = ensureArray(_extends).some(name => name.includes(':@next/next'));
const ruleDir = false ?? findCacheDirectory({ name: '_eslint-rules' });
if (ruleDir) {
fs.rmSync(ruleDir, { recursive: true, force: true });
fs.mkdirSync(ruleDir, { recursive: true });
}
const result: Config = {
root: true,
parser: '@typescript-eslint/parser',
plugins: unique(['@typescript-eslint', 'import', 'rules', ...(plugins ?? [])]),
plugins: unique('@typescript-eslint', 'import', 'rules', plugins),
env: { node: true, browser: true, es2023: true },
reportUnusedDisableDirectives: true,
parserOptions: {
project: true,
},
extends: unique([
extends: unique(
'eslint:recommended',
'prettier',
'plugin:@typescript-eslint/recommended-type-checked',
'plugin:import/errors',
'plugin:import/typescript',
...(hasReact
? [
'plugin:react/recommended',
'plugin:react-hooks/recommended',
'plugin:jsx-a11y/recommended',
]
: []),
...(_extends ?? []),
]),
hasReact && [
'plugin:react/recommended',
'plugin:react-hooks/recommended',
'plugin:jsx-a11y/recommended',
],
hasJsDoc && 'plugin:jsdoc/recommended-typescript',
hasGraphQL && 'plugin:@graphql-eslint/recommended',
_extends,
),
settings: {
'import/parsers': {
'@typescript-eslint/parser': ['.ts', '.tsx', '.mts', '.cts'],
@ -137,6 +187,7 @@ export function extendConfig({
...eslintRules,
...typescriptRules,
...importRules,
...localRules,
...(hasReact && {
...reactRules,
'react/no-unknown-property': [
@ -148,8 +199,8 @@ export function extendConfig({
'react-refresh/only-export-components': [warn, { allowConstantExport: true }],
}),
...(hasUnicorn && unicornRules),
'rules/no-import-dot': error,
'rules/restrict-template-expressions': error,
...(hasJsDoc && jsDocRules),
...(hasGraphQL && graphqlRules),
...rules,
},
...rest,