Update
This commit is contained in:
@ -1,30 +0,0 @@
|
||||
#!/usr/bin/env tsx
|
||||
import { promises as fs } from 'node:fs';
|
||||
import { camelCase } from 'lodash';
|
||||
|
||||
export async function buildLocalRules() {
|
||||
const files = (await fs.readdir('./src/rules'))
|
||||
.filter(file => file.endsWith('.ts'))
|
||||
.filter(file => file !== 'index.ts')
|
||||
.map(file => file.slice(0, -3));
|
||||
|
||||
const entryFile = /* js */ `
|
||||
import type { Rule } from 'eslint';
|
||||
import type { ESLintUtils } from '@typescript-eslint/utils';
|
||||
|
||||
${files.map(file => `import ${camelCase(file)} from './${file}';`).join('\n')}
|
||||
|
||||
export const rules: Record<
|
||||
string,
|
||||
Rule.RuleModule | ESLintUtils.RuleModule<string, unknown[]>
|
||||
> = {
|
||||
${files.map(file => `'${file}': ${camelCase(file)},`).join('\n ')}
|
||||
};
|
||||
`.trim();
|
||||
|
||||
await fs.writeFile('./src/rules/index.ts', entryFile + '\n');
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
buildLocalRules();
|
||||
}
|
@ -6,28 +6,28 @@
|
||||
"subject": "[meta] add `repository.directory` field"
|
||||
},
|
||||
"eslint-import-resolver-typescript": {
|
||||
"hash": "ca11f1c538714252ff058a8e1c680796ee5775d0",
|
||||
"date": "2024-06-01T03:27:29+00:00",
|
||||
"hash": "c9b5626ee69bd529c7e391e40928a4fb28dce179",
|
||||
"date": "2024-07-23T20:40:14+08:00",
|
||||
"committer": "GitHub",
|
||||
"subject": "chore(deps): update dependency eslint to ^8.57.0 (#287)"
|
||||
"subject": "chore: release eslint-import-resolver-typescript (#302)"
|
||||
},
|
||||
"eslint-plugin-jsx-a11y": {
|
||||
"hash": "0be7ea95f560c6afc6817d381054d914ebd0b2ca",
|
||||
"date": "2024-06-23T23:41:48-04:00",
|
||||
"hash": "cca288b73a39fa0932a57c02a7a88de68fc971fc",
|
||||
"date": "2024-07-22T02:39:43+01:00",
|
||||
"committer": "Jordan Harband",
|
||||
"subject": "[readme] remove deprecated travis ci badge; add github actions badge"
|
||||
"subject": "[readme] fix typo in shareable config section in readme"
|
||||
},
|
||||
"eslint-plugin-n": {
|
||||
"hash": "67bbfdf3c6862dcbfe455a4afbd83fa60f9d1ea4",
|
||||
"date": "2024-06-14T09:43:13+08:00",
|
||||
"hash": "5aad5f1c419b3143ffb9356bd299fc50dc576ee5",
|
||||
"date": "2024-07-26T10:04:35+08:00",
|
||||
"committer": "GitHub",
|
||||
"subject": "chore(master): release 17.9.0 (#299)"
|
||||
"subject": "chore(master): release 17.10.0 (#305)"
|
||||
},
|
||||
"eslint-plugin-react": {
|
||||
"hash": "3c1d5203438965b3999911520a930306f6e9c58f",
|
||||
"date": "2024-06-23T23:00:32-07:00",
|
||||
"hash": "983b88dd3cb5e07919517d3fde4085f60883ded7",
|
||||
"date": "2024-07-24T15:26:33-07:00",
|
||||
"committer": "Jordan Harband",
|
||||
"subject": "[Dev Deps] downgrade `eslint-remote-tester-repositories`"
|
||||
"subject": "[Tests] `no-array-index-key`: actually run valid tests"
|
||||
},
|
||||
"jsx-ast-utils": {
|
||||
"hash": "5943318eaf23764eec3ff397ebb969613d728a95",
|
||||
|
46
src/env.ts
Normal file
46
src/env.ts
Normal file
@ -0,0 +1,46 @@
|
||||
import type { Extends, Plugin } from '@aet/eslint-define-config';
|
||||
import * as fs from 'node:fs';
|
||||
import { resolve } from 'node:path';
|
||||
|
||||
export function checkEnv() {
|
||||
const rootDir = process.cwd();
|
||||
const plugins: Plugin[] = [];
|
||||
const extend: Extends[] = [];
|
||||
|
||||
const pkgJsonPath = resolve(rootDir, 'package.json');
|
||||
const pkgJson = fs.existsSync(pkgJsonPath)
|
||||
? JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8'))
|
||||
: {};
|
||||
|
||||
const deps = Object.keys({
|
||||
...pkgJson.dependencies,
|
||||
...pkgJson.devDependencies,
|
||||
...pkgJson.peerDependencies,
|
||||
});
|
||||
|
||||
const hasReact = deps.includes('react');
|
||||
if (hasReact) {
|
||||
plugins.push('react-hooks');
|
||||
}
|
||||
if (deps.includes('@vitejs/plugin-react')) {
|
||||
plugins.push('react-refresh');
|
||||
}
|
||||
|
||||
if (deps.includes('tailwindcss') && deps.includes('eslint-plugin-tailwindcss')) {
|
||||
plugins.push('tailwindcss');
|
||||
}
|
||||
|
||||
if (deps.includes('storybook') && deps.includes('eslint-plugin-storybook')) {
|
||||
extend.push('plugin:storybook/recommended');
|
||||
}
|
||||
|
||||
if (deps.includes('@tanstack/react-query')) {
|
||||
extend.push('plugin:@tanstack/eslint-plugin-query/recommended');
|
||||
}
|
||||
|
||||
return {
|
||||
react: hasReact,
|
||||
plugins,
|
||||
extends: extend,
|
||||
};
|
||||
}
|
76
src/index.ts
76
src/index.ts
@ -1,9 +1,8 @@
|
||||
/// <reference path="./modules.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 '@aet/eslint-define-config';
|
||||
import type { ESLintConfig, Extends, Plugin, Rules } from '@aet/eslint-define-config';
|
||||
// import findCacheDirectory from 'find-cache-dir';
|
||||
import { typescriptRules } from './presets/typescript';
|
||||
import { unicornRules } from './presets/unicorn';
|
||||
@ -15,6 +14,7 @@ import { graphqlRules } from './presets/graphql';
|
||||
import { localRules } from './presets/local';
|
||||
import { error, warn, off } from './constants';
|
||||
import { tailwindRules } from './presets/tailwind';
|
||||
import { checkEnv } from './env';
|
||||
|
||||
export { error, warn, off };
|
||||
|
||||
@ -74,12 +74,17 @@ export type InputConfig = Omit<ESLintConfig, 'rules'> & {
|
||||
* this is statically analyzed.
|
||||
*/
|
||||
customRuleFiles?: string | string[];
|
||||
|
||||
/**
|
||||
* Automatically detect project types, dependencies and deduct the plugins.
|
||||
*/
|
||||
auto?: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a ESLint config object.
|
||||
*
|
||||
* By default, it includes `["@typescript-eslint", "import", "prettier"]` configs.
|
||||
* By default, it includes `["@typescript-eslint", "import-x", "prettier", "unicorn"]` configs.
|
||||
* Additional bundled plugins include:
|
||||
*
|
||||
* 1. [`react`](https://github.com/jsx-eslint/eslint-plugin-react#list-of-supported-rules)
|
||||
@ -88,7 +93,8 @@ export type InputConfig = Omit<ESLintConfig, 'rules'> & {
|
||||
* 2. [`react-refresh`](https://github.com/ArnaudBarre/eslint-plugin-react-refresh)
|
||||
* 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)
|
||||
* 5. [`n`](https://github.com/eslint-community/eslint-plugin-n#-rules) (Node.js specific,
|
||||
* requires `minimatch`)
|
||||
* 6. [`jsdoc`](https://github.com/gajus/eslint-plugin-jsdoc#rules)
|
||||
*
|
||||
* Non bundled:
|
||||
@ -96,41 +102,49 @@ export type InputConfig = Omit<ESLintConfig, 'rules'> & {
|
||||
*/
|
||||
export function extendConfig(of: InputConfig = {}): ESLintConfig {
|
||||
const {
|
||||
plugins = [],
|
||||
auto,
|
||||
plugins: _plugins = [],
|
||||
settings,
|
||||
rules,
|
||||
extends: _extends,
|
||||
overrides,
|
||||
customRuleFiles,
|
||||
parserOptions,
|
||||
// @ts-expect-error
|
||||
localRules: _,
|
||||
...rest
|
||||
} = of;
|
||||
|
||||
const hasReact = plugins.includes('react');
|
||||
const hasReactRefresh = plugins.includes('react-refresh');
|
||||
const hasUnicorn = plugins.includes('unicorn');
|
||||
let hasReact = false;
|
||||
let plugins: Plugin[] = _plugins;
|
||||
let extend: Extends[] = ensureArray(_extends);
|
||||
|
||||
if (auto) {
|
||||
const env = checkEnv();
|
||||
hasReact = env.react;
|
||||
plugins = [..._plugins, ...env.plugins];
|
||||
extend = [...extend, ...env.extends];
|
||||
}
|
||||
|
||||
const hasJsDoc = plugins.includes('jsdoc');
|
||||
const hasGraphQL = plugins.includes('@graphql-eslint');
|
||||
const hasNext = ensureArray(_extends).some(name => name.includes(':@next/next'));
|
||||
const hasTailwind = ensureArray(_extends).some(name =>
|
||||
name.includes('plugin:tailwindcss/'),
|
||||
);
|
||||
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 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,
|
||||
parser: '@typescript-eslint/parser',
|
||||
plugins: unique('@typescript-eslint', 'import-x', 'rules', plugins),
|
||||
plugins: unique('@typescript-eslint', 'import-x', 'rules', 'unicorn', plugins),
|
||||
env: { node: true, browser: true, es2023: true },
|
||||
reportUnusedDisableDirectives: true,
|
||||
parserOptions: {
|
||||
project: true,
|
||||
...parserOptions,
|
||||
},
|
||||
extends: unique(
|
||||
'eslint:recommended',
|
||||
@ -139,13 +153,14 @@ export function extendConfig(of: InputConfig = {}): ESLintConfig {
|
||||
'plugin:import-x/errors',
|
||||
'plugin:import-x/typescript',
|
||||
hasReact && [
|
||||
'plugin:react/recommended',
|
||||
'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',
|
||||
_extends,
|
||||
extend as string[],
|
||||
),
|
||||
settings: {
|
||||
'import-x/parsers': {
|
||||
@ -156,9 +171,6 @@ export function extendConfig(of: InputConfig = {}): ESLintConfig {
|
||||
alwaysTryTypes: true,
|
||||
},
|
||||
},
|
||||
react: {
|
||||
version: 'detect',
|
||||
},
|
||||
...settings,
|
||||
},
|
||||
overrides: [
|
||||
@ -181,6 +193,12 @@ export function extendConfig(of: InputConfig = {}): ESLintConfig {
|
||||
'no-console': off,
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['*.tsx'],
|
||||
rules: {
|
||||
'@eslint-react/no-leaked-conditional-rendering': error,
|
||||
},
|
||||
},
|
||||
...(overrides ?? []),
|
||||
],
|
||||
rules: {
|
||||
@ -188,17 +206,11 @@ export function extendConfig(of: InputConfig = {}): ESLintConfig {
|
||||
...typescriptRules,
|
||||
...importRules,
|
||||
...localRules,
|
||||
...(hasReact && {
|
||||
...reactRules,
|
||||
'react/no-unknown-property': [
|
||||
error,
|
||||
{ ignore: hasNext ? ['css', 'next'] : ['css'] },
|
||||
],
|
||||
}),
|
||||
...(hasReactRefresh && {
|
||||
...(hasReact && reactRules),
|
||||
...(plugins.includes('react-refresh') && {
|
||||
'react-refresh/only-export-components': [warn, { allowConstantExport: true }],
|
||||
}),
|
||||
...(hasUnicorn && unicornRules),
|
||||
...unicornRules,
|
||||
...(hasJsDoc && jsDocRules),
|
||||
...(hasGraphQL && graphqlRules),
|
||||
...(hasTailwind && tailwindRules),
|
||||
|
@ -8,7 +8,6 @@ import type { Node, Property } from 'estree';
|
||||
|
||||
// https://github.com/gulpjs/interpret
|
||||
const transpilers = [
|
||||
'esbin/register',
|
||||
'esbuild-register',
|
||||
'ts-node/register/transpile-only',
|
||||
'@swc/register',
|
||||
|
@ -4,7 +4,7 @@ import restrictedGlobals from './_restrictedGlobals.json';
|
||||
|
||||
export const eslintRules: Partial<EslintRulesObject> = {
|
||||
'arrow-body-style': [error, 'as-needed'],
|
||||
'class-methods-use-this': off,
|
||||
'class-methods-use-this': warn,
|
||||
'func-style': [error, 'declaration', { allowArrowFunctions: true }],
|
||||
'no-async-promise-executor': off,
|
||||
'no-case-declarations': off,
|
||||
@ -31,7 +31,7 @@ export const eslintRules: Partial<EslintRulesObject> = {
|
||||
'no-template-curly-in-string': error,
|
||||
'no-var': error,
|
||||
'object-shorthand': [error, 'always', { ignoreConstructors: true }],
|
||||
'one-var': [error, { var: 'never', let: 'never' }],
|
||||
'one-var': [error, { var: 'never', let: 'never', const: 'never' }],
|
||||
'prefer-arrow-callback': error,
|
||||
'prefer-const': [error, { destructuring: 'all' }],
|
||||
'prefer-destructuring': [
|
||||
|
@ -2,8 +2,6 @@ import { error, off } from '../constants';
|
||||
import { ReactRulesObject } from '@aet/eslint-define-config/src/rules/react';
|
||||
|
||||
export const reactRules: Partial<ReactRulesObject> = {
|
||||
'react/display-name': off,
|
||||
'react/no-children-prop': error,
|
||||
'react/prop-types': off,
|
||||
'react/react-in-jsx-scope': off,
|
||||
'@eslint-react/no-missing-component-display-name': off,
|
||||
'@eslint-react/no-children-prop': error,
|
||||
};
|
||||
|
@ -4,12 +4,10 @@ const { name } = [require][0]('./package.json');
|
||||
const _resolveFilename = Module._resolveFilename;
|
||||
const alias = new Set([
|
||||
'eslint-import-resolver-typescript',
|
||||
'eslint-plugin-import',
|
||||
'eslint-plugin-jsx-a11y',
|
||||
'eslint-plugin-local',
|
||||
'eslint-plugin-n',
|
||||
'eslint-plugin-react-hooks',
|
||||
'eslint-plugin-react',
|
||||
'eslint-plugin-rules',
|
||||
]);
|
||||
|
||||
|
Reference in New Issue
Block a user