This commit is contained in:
Alex
2024-07-30 23:00:25 -04:00
parent 2853da4344
commit 3ac5f91988
18 changed files with 281 additions and 171 deletions

View File

@ -3,12 +3,12 @@
"env": { "env": {
"node": true, "node": true,
"browser": true, "browser": true,
"es6": true "es6": true,
}, },
"extends": ["eslint:recommended", "prettier"], "extends": ["eslint:recommended", "prettier"],
"parserOptions": { "parserOptions": {
"sourceType": "module", "sourceType": "module",
"ecmaVersion": "latest" "ecmaVersion": "latest",
}, },
"rules": { "rules": {
"no-restricted-imports": [ "no-restricted-imports": [
@ -24,14 +24,14 @@
"object.hasown", "object.hasown",
"object.values", "object.values",
"string.prototype.matchall", "string.prototype.matchall",
"has" "has",
] ],
} },
], ],
"arrow-body-style": ["error", "as-needed"], "arrow-body-style": ["error", "as-needed"],
"class-methods-use-this": [ "class-methods-use-this": [
"warn", "warn",
{ "exceptMethods": ["toString", "shouldComponentUpdate"] } { "exceptMethods": ["toString", "shouldComponentUpdate"] },
], ],
"complexity": ["warn", { "max": 100 }], "complexity": ["warn", { "max": 100 }],
"curly": ["error", "multi-line", "consistent"], "curly": ["error", "multi-line", "consistent"],
@ -50,13 +50,13 @@
"prefer-const": ["error", { "destructuring": "all" }], "prefer-const": ["error", { "destructuring": "all" }],
"prefer-destructuring": [ "prefer-destructuring": [
"warn", "warn",
{ "AssignmentExpression": { "array": false, "object": false } } { "AssignmentExpression": { "array": false, "object": false } },
], ],
"prefer-rest-params": "warn", "prefer-rest-params": "warn",
"prefer-spread": "warn", "prefer-spread": "warn",
"quote-props": ["error", "as-needed"], "quote-props": ["error", "as-needed"],
"spaced-comment": ["error", "always", { "markers": ["/"] }], "spaced-comment": ["error", "always", { "markers": ["/"] }],
"sort-imports": ["warn", { "ignoreDeclarationSort": true }], "sort-imports": ["warn", { "ignoreDeclarationSort": true }],
"yoda": ["error", "never", { "exceptRange": true }] "yoda": ["error", "never", { "exceptRange": true }],
} },
} }

24
dist/index.d.ts vendored
View File

@ -1,12 +1,19 @@
// Generated by dts-bundle-generator v9.4.0 // Generated by dts-bundle-generator v9.4.0
import { ESLintConfig, Rules } from '@aet/eslint-define-config'; import { ESLintConfig, KnownExtends, Rules, Settings } from '@aet/eslint-define-config';
import { ESLintUtils } from '@typescript-eslint/utils'; import { ESLintUtils } from '@typescript-eslint/utils';
import { Rule } from 'eslint'; import { Rule } from 'eslint';
import { Merge, SetRequired } from 'type-fest';
export declare const error = "error"; export declare const error = "error";
export declare const warn = "warn"; export declare const warn = "warn";
export declare const off = "off"; export declare const off = "off";
export declare const graphql: Middleware;
export declare const jsdoc: Middleware;
export declare const storybook: Middleware;
export declare const react: Middleware;
export declare const reactRefresh: Middleware;
export declare const tailwind: Middleware;
export type RuleLevel = "error" | "warn" | "off" | 0 | 1 | 2; export type RuleLevel = "error" | "warn" | "off" | 0 | 1 | 2;
export type RuleEntry<Options> = RuleLevel | [ export type RuleEntry<Options> = RuleLevel | [
RuleLevel, RuleLevel,
@ -32,6 +39,7 @@ export interface CustomRule {
}>; }>;
options?: RuleLevel; options?: RuleLevel;
} }
export type Middleware = (config: MiddlewareConfig, helpers: MiddlewareFunctions) => void;
/** /**
* ESLint Configuration. * ESLint Configuration.
* @see [ESLint Configuration](https://eslint.org/docs/latest/user-guide/configuring/) * @see [ESLint Configuration](https://eslint.org/docs/latest/user-guide/configuring/)
@ -53,6 +61,16 @@ export type InputConfig = Omit<ESLintConfig, "rules"> & {
*/ */
auto?: boolean; auto?: boolean;
}; };
export type OptionalObjectKey<T> = Exclude<{
[Key in keyof T]: undefined | any[] extends T[Key] ? Key : undefined | Record<any, any> extends T[Key] ? Key : never;
}[keyof T], undefined>;
export type MiddlewareConfig = Merge<SetRequired<ESLintConfig, OptionalObjectKey<ESLintConfig>>, {
extends: KnownExtends[];
}>;
export interface MiddlewareFunctions {
addRules(rules: Partial<RuleOptions>): void;
addSettings(settings: Partial<Settings>): void;
}
/** /**
* Returns a ESLint config object. * Returns a ESLint config object.
* *
@ -72,6 +90,8 @@ export type InputConfig = Omit<ESLintConfig, "rules"> & {
* Non bundled: * Non bundled:
* 1. [`graphql`](https://the-guild.dev/graphql/eslint/rules) * 1. [`graphql`](https://the-guild.dev/graphql/eslint/rules)
*/ */
export declare function extendConfig(of?: InputConfig): ESLintConfig; export declare function extendConfig(of?: InputConfig & {
middlewares: Middleware[];
}): ESLintConfig;
export {}; export {};

4
dist/package.json vendored
View File

@ -1,6 +1,6 @@
{ {
"name": "@aet/eslint-rules", "name": "@aet/eslint-rules",
"version": "1.0.1-beta.10", "version": "1.0.1-beta.11",
"license": "UNLICENSED", "license": "UNLICENSED",
"peerDependencies": { "peerDependencies": {
"eslint": "^8.57.0", "eslint": "^8.57.0",
@ -8,7 +8,7 @@
}, },
"dependencies": { "dependencies": {
"@nolyfill/is-core-module": "^1.0.39", "@nolyfill/is-core-module": "^1.0.39",
"@aet/eslint-define-config": "0.1.0-beta.10", "@aet/eslint-define-config": "^0.1.0-beta.15",
"@eslint-community/eslint-utils": "^4.4.0", "@eslint-community/eslint-utils": "^4.4.0",
"@tanstack/eslint-plugin-query": "^5.51.15", "@tanstack/eslint-plugin-query": "^5.51.15",
"@types/eslint": "^8.56.11", "@types/eslint": "^8.56.11",

View File

@ -7,7 +7,7 @@
}, },
"private": true, "private": true,
"devDependencies": { "devDependencies": {
"@aet/eslint-define-config": "^0.1.0-beta.10", "@aet/eslint-define-config": "^0.1.0-beta.15",
"@babel/core": "^7.24.9", "@babel/core": "^7.24.9",
"@babel/plugin-transform-flow-strip-types": "^7.24.7", "@babel/plugin-transform-flow-strip-types": "^7.24.7",
"@babel/preset-env": "^7.25.0", "@babel/preset-env": "^7.25.0",
@ -43,6 +43,7 @@
"picocolors": "^1.0.1", "picocolors": "^1.0.1",
"prettier": "^3.3.3", "prettier": "^3.3.3",
"prop-types": "^15.8.1", "prop-types": "^15.8.1",
"type-fest": "^4.23.0",
"typescript": "^5.5.4" "typescript": "^5.5.4"
}, },
"prettier": { "prettier": {

19
pnpm-lock.yaml generated
View File

@ -22,8 +22,8 @@ importers:
.: .:
devDependencies: devDependencies:
'@aet/eslint-define-config': '@aet/eslint-define-config':
specifier: ^0.1.0-beta.10 specifier: ^0.1.0-beta.15
version: 0.1.0-beta.10 version: 0.1.0-beta.15
'@babel/core': '@babel/core':
specifier: ^7.24.9 specifier: ^7.24.9
version: 7.24.9 version: 7.24.9
@ -129,6 +129,9 @@ importers:
prop-types: prop-types:
specifier: ^15.8.1 specifier: ^15.8.1
version: 15.8.1 version: 15.8.1
type-fest:
specifier: ^4.23.0
version: 4.23.0
typescript: typescript:
specifier: ^5.5.4 specifier: ^5.5.4
version: 5.5.4 version: 5.5.4
@ -139,8 +142,8 @@ packages:
resolution: {integrity: sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==} resolution: {integrity: sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
'@aet/eslint-define-config@0.1.0-beta.10': '@aet/eslint-define-config@0.1.0-beta.15':
resolution: {integrity: sha512-YTm+DdRvCPMMN+R3PZxJsBLYwUscxIpBhlpo2hSS/KEXtOiNUTGPIdzUERFkdNA1PayYfCDwh4dquKX3IZ0uwQ==} resolution: {integrity: sha512-WQuQyKU4V4RSZi0ShPpBE0LB8+evUjLr34T9XLWDTFJBrVkD6tJXdj8eQlzEWkp8ZxQrPGbYfkegwGHQ1NdLXg==}
engines: {node: '>=18.0.0', npm: '>=9.0.0'} engines: {node: '>=18.0.0', npm: '>=9.0.0'}
'@ampproject/remapping@2.2.1': '@ampproject/remapping@2.2.1':
@ -1935,6 +1938,10 @@ packages:
resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==}
engines: {node: '>=10'} engines: {node: '>=10'}
type-fest@4.23.0:
resolution: {integrity: sha512-ZiBujro2ohr5+Z/hZWHESLz3g08BBdrdLMieYFULJO+tWc437sn8kQsWLJoZErY8alNhxre9K4p3GURAG11n+w==}
engines: {node: '>=16'}
typescript@5.5.4: typescript@5.5.4:
resolution: {integrity: sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==} resolution: {integrity: sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==}
engines: {node: '>=14.17'} engines: {node: '>=14.17'}
@ -2022,7 +2029,7 @@ snapshots:
'@aashutoshrathi/word-wrap@1.2.6': {} '@aashutoshrathi/word-wrap@1.2.6': {}
'@aet/eslint-define-config@0.1.0-beta.10': {} '@aet/eslint-define-config@0.1.0-beta.15': {}
'@ampproject/remapping@2.2.1': '@ampproject/remapping@2.2.1':
dependencies: dependencies:
@ -4018,6 +4025,8 @@ snapshots:
type-fest@0.20.2: {} type-fest@0.20.2: {}
type-fest@4.23.0: {}
typescript@5.5.4: {} typescript@5.5.4: {}
undici-types@5.26.5: {} undici-types@5.26.5: {}

View File

@ -23,5 +23,4 @@ pull() {
pull import-js eslint-import-resolver-typescript pull import-js eslint-import-resolver-typescript
pull jsx-eslint eslint-plugin-jsx-a11y pull jsx-eslint eslint-plugin-jsx-a11y
pull eslint-community eslint-plugin-n pull eslint-community eslint-plugin-n
pull jsx-eslint eslint-plugin-react
pull jsx-eslint jsx-ast-utils pull jsx-eslint jsx-ast-utils

View File

@ -18,10 +18,10 @@
"subject": "[readme] fix typo in shareable config section in readme" "subject": "[readme] fix typo in shareable config section in readme"
}, },
"eslint-plugin-n": { "eslint-plugin-n": {
"hash": "5aad5f1c419b3143ffb9356bd299fc50dc576ee5", "hash": "6744257b43560181412a76eadeb7de564b886ad4",
"date": "2024-07-26T10:04:35+08:00", "date": "2024-07-26T11:46:54+01:00",
"committer": "GitHub", "committer": "GitHub",
"subject": "chore(master): release 17.10.0 (#305)" "subject": "chore(master): release 17.10.1 (#319)"
}, },
"eslint-plugin-react": { "eslint-plugin-react": {
"hash": "983b88dd3cb5e07919517d3fde4085f60883ded7", "hash": "983b88dd3cb5e07919517d3fde4085f60883ded7",

View File

@ -1,46 +1,39 @@
import type { Extends, Plugin } from '@aet/eslint-define-config';
import * as fs from 'node:fs'; import * as fs from 'node:fs';
import { resolve } from 'node:path'; import { resolve } from 'node:path';
import { Middleware, storybook } from './index';
import { react, reactRefresh } from './presets/react';
import { tailwind } from './presets/tailwind';
import { reactQuery } from './presets/misc';
export function checkEnv() { export function* checkEnv(): Generator<Middleware> {
const rootDir = process.cwd(); const rootDir = process.cwd();
const plugins: Plugin[] = [];
const extend: Extends[] = [];
const pkgJsonPath = resolve(rootDir, 'package.json'); const pkgJsonPath = resolve(rootDir, 'package.json');
const pkgJson = fs.existsSync(pkgJsonPath) const pkgJson = fs.existsSync(pkgJsonPath)
? JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8')) ? JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8'))
: {}; : {};
const deps = Object.keys({ const deps = new Set(
...pkgJson.dependencies, Object.keys({
...pkgJson.devDependencies, ...pkgJson.dependencies,
...pkgJson.peerDependencies, ...pkgJson.devDependencies,
}); ...pkgJson.peerDependencies,
}),
);
const hasReact = deps.includes('react'); if (deps.has('react')) {
if (hasReact) { yield react;
plugins.push('react-hooks');
} }
if (deps.includes('@vitejs/plugin-react')) { if (deps.has('@vitejs/plugin-react') && deps.has('eslint-plugin-react-refresh')) {
plugins.push('react-refresh'); yield reactRefresh;
} }
if (deps.has('tailwindcss') && deps.has('eslint-plugin-tailwindcss')) {
if (deps.includes('tailwindcss') && deps.includes('eslint-plugin-tailwindcss')) { yield tailwind;
plugins.push('tailwindcss');
} }
if (deps.has('storybook') && deps.has('eslint-plugin-storybook')) {
if (deps.includes('storybook') && deps.includes('eslint-plugin-storybook')) { yield storybook;
extend.push('plugin:storybook/recommended');
} }
if (deps.has('@tanstack/react-query') && deps.has('@tanstack/eslint-plugin-query')) {
if (deps.includes('@tanstack/react-query')) { yield reactQuery;
extend.push('plugin:@tanstack/eslint-plugin-query/recommended');
} }
return {
react: hasReact,
plugins,
extends: extend,
};
} }

View File

@ -1,21 +1,31 @@
/// <reference path="./modules.d.ts" /> /// <reference path="./modules.d.ts" />
import './redirect'; import './redirect';
import { uniq } from 'lodash';
import type { Merge, SetRequired } from 'type-fest';
import type { Rule } from 'eslint'; import type { Rule } from 'eslint';
import type { ESLintUtils } from '@typescript-eslint/utils'; import type { ESLintUtils } from '@typescript-eslint/utils';
import type { ESLintConfig, Extends, Plugin, Rules } from '@aet/eslint-define-config'; import type {
// import findCacheDirectory from 'find-cache-dir'; ESLintConfig,
import { typescriptRules } from './presets/typescript'; Extends,
import { unicornRules } from './presets/unicorn'; KnownExtends,
Plugin,
Rules,
Settings,
} from '@aet/eslint-define-config';
import { importTypeScript } from './presets/typescript';
import { unicorn } from './presets/unicorn';
import { eslintRules } from './presets/eslint'; import { eslintRules } from './presets/eslint';
import { reactRules } from './presets/react'; import { local } from './presets/local';
import { importRules } from './presets/import-x';
import { jsDocRules } from './presets/jsdoc';
import { graphqlRules } from './presets/graphql';
import { localRules } from './presets/local';
import { error, warn, off } from './constants'; import { error, warn, off } from './constants';
import { tailwindRules } from './presets/tailwind';
import { checkEnv } from './env'; import { checkEnv } from './env';
export { graphql } from './presets/graphql';
export { jsdoc } from './presets/jsdoc';
export { storybook } from './presets/misc';
export { react, reactRefresh } from './presets/react';
export { tailwind } from './presets/tailwind';
export { error, warn, off }; export { error, warn, off };
declare global { declare global {
@ -57,6 +67,8 @@ export interface CustomRule {
options?: RuleLevel; options?: RuleLevel;
} }
export type Middleware = (config: MiddlewareConfig, helpers: MiddlewareFunctions) => void;
/** /**
* ESLint Configuration. * ESLint Configuration.
* @see [ESLint Configuration](https://eslint.org/docs/latest/user-guide/configuring/) * @see [ESLint Configuration](https://eslint.org/docs/latest/user-guide/configuring/)
@ -81,6 +93,27 @@ export type InputConfig = Omit<ESLintConfig, 'rules'> & {
auto?: boolean; auto?: boolean;
}; };
type OptionalObjectKey<T> = Exclude<
{
[Key in keyof T]: undefined | any[] extends T[Key]
? Key
: undefined | Record<any, any> extends T[Key]
? Key
: never;
}[keyof T],
undefined
>;
type MiddlewareConfig = Merge<
SetRequired<ESLintConfig, OptionalObjectKey<ESLintConfig>>,
{ extends: KnownExtends[] }
>;
interface MiddlewareFunctions {
addRules(rules: Partial<RuleOptions>): void;
addSettings(settings: Partial<Settings>): void;
}
/** /**
* Returns a ESLint config object. * Returns a ESLint config object.
* *
@ -100,124 +133,75 @@ export type InputConfig = Omit<ESLintConfig, 'rules'> & {
* Non bundled: * Non bundled:
* 1. [`graphql`](https://the-guild.dev/graphql/eslint/rules) * 1. [`graphql`](https://the-guild.dev/graphql/eslint/rules)
*/ */
export function extendConfig(of: InputConfig = {}): ESLintConfig { export function extendConfig(
of: InputConfig & {
middlewares: Middleware[];
} = {
middlewares: [],
},
): ESLintConfig {
const { const {
auto, auto = true,
plugins: _plugins = [], plugins: _plugins = [],
settings, settings = {},
rules, rules,
extends: _extends, extends: _extends,
overrides, overrides,
customRuleFiles, customRuleFiles,
parserOptions, parserOptions,
middlewares: _middlewares = [],
// @ts-expect-error // @ts-expect-error
localRules: _, localRules: _,
...rest ...rest
} = of; } = of;
let hasReact = false; let plugins: Plugin[] = [..._plugins];
let plugins: Plugin[] = _plugins;
let extend: Extends[] = ensureArray(_extends); let extend: Extends[] = ensureArray(_extends);
if (auto) { const middlewares: Middleware[] = uniq([
const env = checkEnv(); importTypeScript,
hasReact = env.react; unicorn,
plugins = [..._plugins, ...env.plugins]; local,
extend = [...extend, ...env.extends]; ...(auto ? checkEnv() : []),
} ..._middlewares,
]);
const hasJsDoc = plugins.includes('jsdoc'); const result: MiddlewareConfig = {
const hasGraphQL = plugins.includes('@graphql-eslint');
const hasTailwind = extend.some(name => name.includes('plugin:tailwindcss/'));
// const ruleDir = false; // ?? findCacheDirectory({ name: '_eslint-rules' });
// if (ruleDir) {
// fs.rmSync(ruleDir, { recursive: true, force: true });
// fs.mkdirSync(ruleDir, { recursive: true });
// }
const result: InputConfig = {
root: true, root: true,
parser: '@typescript-eslint/parser', plugins: unique('rules', plugins),
plugins: unique('@typescript-eslint', 'import-x', 'rules', 'unicorn', plugins),
env: { node: true, browser: true, es2023: true }, env: { node: true, browser: true, es2023: true },
reportUnusedDisableDirectives: true, reportUnusedDisableDirectives: true,
parserOptions: { parserOptions: {
project: true, project: true,
...parserOptions, ...parserOptions,
}, },
extends: unique( ignorePatterns: [],
'eslint:recommended', globals: {},
'prettier', extends: ['eslint:recommended', 'prettier', ...(extend as string[])],
'plugin:@typescript-eslint/recommended-type-checked', settings,
'plugin:import-x/errors',
'plugin:import-x/typescript',
hasReact && [
'plugin:@eslint-react/recommended-legacy',
'plugin:@eslint-react/dom-legacy',
'plugin:react-hooks/recommended',
'plugin:jsx-a11y/recommended',
],
hasJsDoc && 'plugin:jsdoc/recommended-typescript',
hasGraphQL && 'plugin:@graphql-eslint/recommended',
extend as string[],
),
settings: {
'import-x/parsers': {
'@typescript-eslint/parser': ['.ts', '.tsx', '.mts', '.cts'],
},
'import-x/resolver': {
typescript: {
alwaysTryTypes: true,
},
},
...settings,
},
overrides: [ overrides: [
{ { files: ['repl.ts', 'scripts/**/*.ts'], rules: { 'no-console': off } },
files: ['.eslintrc.js', '.eslintrc.cjs', '*.config.js', 'index.js'],
extends: ['plugin:@typescript-eslint/disable-type-checked'],
rules: {
'rules/restrict-template-expressions': off,
},
},
{
files: ['*.d.ts'],
rules: {
'@typescript-eslint/consistent-type-imports': off,
},
},
{
files: ['repl.ts', 'scripts/**/*.ts'],
rules: {
'no-console': off,
},
},
{
files: ['*.tsx'],
rules: {
'@eslint-react/no-leaked-conditional-rendering': error,
},
},
...(overrides ?? []), ...(overrides ?? []),
], ],
rules: { rules: { ...eslintRules, ...rules },
...eslintRules,
...typescriptRules,
...importRules,
...localRules,
...(hasReact && reactRules),
...(plugins.includes('react-refresh') && {
'react-refresh/only-export-components': [warn, { allowConstantExport: true }],
}),
...unicornRules,
...(hasJsDoc && jsDocRules),
...(hasGraphQL && graphqlRules),
...(hasTailwind && tailwindRules),
...rules,
},
...rest, ...rest,
}; };
const functions: MiddlewareFunctions = {
addRules(newRules) {
Object.assign(result.rules, newRules);
},
addSettings(newSettings) {
Object.assign(result.settings, newSettings);
},
};
for (const fn of middlewares) {
fn(result, functions);
}
result.plugins = unique(result.plugins);
result.extends = unique(result.extends);
return result; return result;
} }

View File

@ -1,4 +1,11 @@
import { GraphQLRulesObject } from '@aet/eslint-define-config/src/rules/graphql-eslint'; import { GraphQLRulesObject } from '@aet/eslint-define-config/src/rules/graphql-eslint';
import type { Middleware } from '../index';
// https://the-guild.dev/graphql/eslint/rules // https://the-guild.dev/graphql/eslint/rules
export const graphqlRules: Partial<GraphQLRulesObject> = {}; const graphqlRules: Partial<GraphQLRulesObject> = {};
export const graphql: Middleware = (config, { addRules }) => {
config.plugins.push('@graphql-eslint');
config.extends.push('plugin:@graphql-eslint/recommended');
addRules(graphqlRules);
};

View File

@ -1,8 +0,0 @@
import { error, off } from '../constants';
import { ImportXRulesObject } from '@aet/eslint-define-config/src/rules/import-x';
export const importRules: Partial<ImportXRulesObject> = {
'import-x/export': off,
'import-x/no-duplicates': error,
'import-x/order': [error, { groups: ['builtin', 'external'] }],
};

View File

@ -1,3 +1,10 @@
import { JSDocRulesObject } from '@aet/eslint-define-config/src/rules/jsdoc'; import { JSDocRulesObject } from '@aet/eslint-define-config/src/rules/jsdoc';
import type { Middleware } from '../index';
export const jsDocRules: Partial<JSDocRulesObject> = {}; const jsdocRules: Partial<JSDocRulesObject> = {};
export const jsdoc: Middleware = (config, { addRules }) => {
config.plugins.push('jsdoc');
config.extends.push('plugin:jsdoc/recommended-typescript');
addRules(jsdocRules);
};

View File

@ -1,7 +1,11 @@
import type { LocalRuleOptions } from '..'; import type { LocalRuleOptions, Middleware } from '../index';
import { error } from '../constants'; import { error } from '../constants';
export const localRules: Partial<LocalRuleOptions> = { const localRules: Partial<LocalRuleOptions> = {
'rules/no-import-dot': error, 'rules/no-import-dot': error,
'rules/restrict-template-expressions': error, 'rules/restrict-template-expressions': error,
}; };
export const local: Middleware = (_, { addRules }) => {
addRules(localRules);
};

9
src/presets/misc.ts Normal file
View File

@ -0,0 +1,9 @@
import type { Middleware } from '../index';
export const storybook: Middleware = config => {
config.extends.push('plugin:storybook/recommended');
};
export const reactQuery: Middleware = config => {
config.extends.push('plugin:@tanstack/eslint-plugin-query/recommended');
};

View File

@ -1,7 +1,35 @@
import { error, off } from '../constants'; import type { Middleware } from '../index';
import { error, off, warn } from '../constants';
import { ReactRulesObject } from '@aet/eslint-define-config/src/rules/react'; import { ReactRulesObject } from '@aet/eslint-define-config/src/rules/react';
import { ReactRefreshRulesObject } from '@aet/eslint-define-config/src/rules/react-refresh';
export const reactRules: Partial<ReactRulesObject> = { const reactRules: Partial<ReactRulesObject> = {
'@eslint-react/no-missing-component-display-name': off, '@eslint-react/no-missing-component-display-name': off,
'@eslint-react/no-children-prop': error, '@eslint-react/no-children-prop': error,
}; };
export const react: Middleware = (config, { addRules }) => {
config.plugins.push('@eslint-react/eslint-plugin', 'react-hooks');
config.extends.push(
'plugin:@eslint-react/recommended-legacy',
'plugin:@eslint-react/dom-legacy',
'plugin:react-hooks/recommended',
'plugin:jsx-a11y/recommended',
);
config.overrides.push({
files: ['*.tsx'],
rules: {
'@eslint-react/no-leaked-conditional-rendering': error,
},
});
addRules(reactRules);
};
const refreshRules: Partial<ReactRefreshRulesObject> = {
'react-refresh/only-export-components': [warn, { allowConstantExport: true }],
};
export const reactRefresh: Middleware = (config, { addRules }) => {
config.plugins.push('react-refresh');
addRules(refreshRules);
};

View File

@ -1,5 +1,12 @@
import type { Middleware } from '../index';
import { off } from '../constants'; import { off } from '../constants';
import type { TailwindRulesObject } from '@aet/eslint-define-config/src/rules/tailwind';
export const tailwindRules = { const tailwindRules: Partial<TailwindRulesObject> = {
'tailwindcss/no-custom-classname': off, 'tailwindcss/no-custom-classname': off,
} as const; } as const;
export const tailwind: Middleware = (config, { addRules }) => {
config.extends.push('plugin:tailwindcss/recommended');
addRules(tailwindRules);
};

View File

@ -1,7 +1,15 @@
import { error, off, warn } from '../constants'; import { error, off, warn } from '../constants';
import type { TypeScriptRulesObject } from '@aet/eslint-define-config/src/rules/typescript-eslint'; import type { TypeScriptRulesObject } from '@aet/eslint-define-config/src/rules/typescript-eslint';
import type { ImportXRulesObject } from '@aet/eslint-define-config/src/rules/import-x';
import type { Middleware } from '../index';
export const typescriptRules: Partial<TypeScriptRulesObject> = { const importRules: Partial<ImportXRulesObject> = {
'import-x/export': off,
'import-x/no-duplicates': error,
'import-x/order': [error, { groups: ['builtin', 'external'] }],
};
const typescriptRules: Partial<TypeScriptRulesObject> = {
'@typescript-eslint/ban-ts-comment': [ '@typescript-eslint/ban-ts-comment': [
error, error,
{ {
@ -37,3 +45,39 @@ export const typescriptRules: Partial<TypeScriptRulesObject> = {
'@typescript-eslint/triple-slash-reference': off, '@typescript-eslint/triple-slash-reference': off,
'@typescript-eslint/unbound-method': off, '@typescript-eslint/unbound-method': off,
}; };
export const importTypeScript: Middleware = (config, { addRules, addSettings }) => {
config.parser = '@typescript-eslint/parser';
config.plugins.push('@typescript-eslint', 'import-x');
config.extends.push(
'plugin:@typescript-eslint/recommended-type-checked',
'plugin:import-x/errors',
'plugin:import-x/typescript',
);
addSettings({
'import-x/parsers': {
'@typescript-eslint/parser': ['.ts', '.tsx', '.mts', '.cts'],
},
'import-x/resolver': {
typescript: true,
},
});
config.overrides.push(
{
files: ['.eslintrc.js', '.eslintrc.cjs', '*.config.js', 'index.js'],
extends: ['plugin:@typescript-eslint/disable-type-checked'],
rules: {
'rules/restrict-template-expressions': off,
},
},
{
files: ['*.d.ts'],
rules: {
'@typescript-eslint/consistent-type-imports': off,
},
},
);
addRules(importRules);
addRules(typescriptRules);
};

View File

@ -1,10 +1,11 @@
import type { Middleware } from '../index';
import { error, warn } from '../constants'; import { error, warn } from '../constants';
import { UnicornRulesObject } from '@aet/eslint-define-config/src/rules/unicorn'; import { UnicornRulesObject } from '@aet/eslint-define-config/src/rules/unicorn';
const suggest = (suggest: string) => ({ suggest, fix: false }); const suggest = (suggest: string) => ({ suggest, fix: false });
// https://github.com/sindresorhus/eslint-plugin-unicorn/tree/28e7498ad06679bb92343db53bb40a7b5ba2990a // https://github.com/sindresorhus/eslint-plugin-unicorn/tree/28e7498ad06679bb92343db53bb40a7b5ba2990a
export const unicornRules: Partial<UnicornRulesObject> = { const unicornRules: Partial<UnicornRulesObject> = {
'unicorn/better-regex': error, 'unicorn/better-regex': error,
'unicorn/consistent-function-scoping': warn, 'unicorn/consistent-function-scoping': warn,
'unicorn/escape-case': error, 'unicorn/escape-case': error,
@ -69,3 +70,8 @@ export const unicornRules: Partial<UnicornRulesObject> = {
], ],
'unicorn/template-indent': warn, 'unicorn/template-indent': warn,
}; };
export const unicorn: Middleware = (config, { addRules }) => {
config.plugins.push('unicorn');
addRules(unicornRules);
};