Update
This commit is contained in:
@ -1,10 +1,12 @@
|
||||
import * as fs from 'node:fs';
|
||||
import { resolve } from 'node:path';
|
||||
import { Middleware, storybook } from './index';
|
||||
import { storybook } from './index';
|
||||
import { react, reactRefresh } from './presets/react';
|
||||
import { tailwind } from './presets/tailwind';
|
||||
import { jsdoc } from './presets/jsdoc';
|
||||
import { reactQuery } from './presets/misc';
|
||||
import { testingLibrary } from './presets/testing-library';
|
||||
import type { Middleware } from './middleware';
|
||||
|
||||
const middlewares = {
|
||||
react,
|
||||
@ -13,6 +15,7 @@ const middlewares = {
|
||||
storybook,
|
||||
reactQuery,
|
||||
testingLibrary,
|
||||
jsdoc,
|
||||
};
|
||||
|
||||
export const envs: {
|
||||
|
34
src/index.ts
34
src/index.ts
@ -1,18 +1,11 @@
|
||||
/// <reference path="./modules.d.ts" />
|
||||
import './redirect';
|
||||
import { uniq } from 'lodash';
|
||||
import type { Merge, SetRequired } from 'type-fest';
|
||||
import type { Rule } from 'eslint';
|
||||
import type { ESLintUtils } from '@typescript-eslint/utils';
|
||||
import type {
|
||||
ESLintConfig,
|
||||
Extends,
|
||||
KnownExtends,
|
||||
Plugin,
|
||||
Rules,
|
||||
Settings,
|
||||
} from '@aet/eslint-define-config';
|
||||
import type { ESLintConfig, Extends, Plugin, Rules } from '@aet/eslint-define-config';
|
||||
|
||||
import type { Middleware, MiddlewareConfig, MiddlewareFunctions } from './middleware';
|
||||
import { importTypeScript } from './presets/typescript';
|
||||
import { unicorn } from './presets/unicorn';
|
||||
import { eslintRules } from './presets/eslint';
|
||||
@ -67,8 +60,6 @@ export interface CustomRule {
|
||||
options?: RuleLevel;
|
||||
}
|
||||
|
||||
export type Middleware = (config: MiddlewareConfig, helpers: MiddlewareFunctions) => void;
|
||||
|
||||
/**
|
||||
* ESLint Configuration.
|
||||
* @see [ESLint Configuration](https://eslint.org/docs/latest/user-guide/configuring/)
|
||||
@ -94,27 +85,6 @@ export type InputConfig = Omit<ESLintConfig, 'rules'> & {
|
||||
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.
|
||||
*
|
||||
|
@ -1,6 +1,6 @@
|
||||
import type { ESLint } from 'eslint';
|
||||
import * as fs from 'node:fs';
|
||||
import { resolve, basename, extname } from 'node:path';
|
||||
import { basename, extname, resolve } from 'node:path';
|
||||
import { glob } from 'fast-glob';
|
||||
import { parseModule } from 'esprima';
|
||||
import query from 'esquery';
|
||||
|
30
src/middleware.ts
Normal file
30
src/middleware.ts
Normal file
@ -0,0 +1,30 @@
|
||||
import type { Merge, SetRequired } from 'type-fest';
|
||||
import type { ESLintConfig, KnownExtends, Settings } from '@aet/eslint-define-config';
|
||||
import type { RuleOptions } from './index';
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
export type Middleware = (config: MiddlewareConfig, helpers: MiddlewareFunctions) => void;
|
||||
|
||||
export function defineMiddleware(middleware: Middleware): Middleware {
|
||||
return middleware;
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
import { error, warn, off } from '../constants';
|
||||
import { EslintRulesObject } from '@aet/eslint-define-config/src/rules/eslint';
|
||||
import { type EslintRulesObject } from '@aet/eslint-define-config/src/rules/eslint';
|
||||
import { error, off, warn } from '../constants';
|
||||
import restrictedGlobals from './_restrictedGlobals.json';
|
||||
|
||||
export const eslintRules: Partial<EslintRulesObject> = {
|
||||
|
@ -1,11 +1,11 @@
|
||||
import { GraphQLRulesObject } from '@aet/eslint-define-config/src/rules/graphql-eslint';
|
||||
import type { Middleware } from '../index';
|
||||
import type { GraphQLRulesObject } from '@aet/eslint-define-config/src/rules/graphql-eslint';
|
||||
import { defineMiddleware } from '../middleware';
|
||||
|
||||
// https://the-guild.dev/graphql/eslint/rules
|
||||
const graphqlRules: Partial<GraphQLRulesObject> = {};
|
||||
|
||||
export const graphql: Middleware = (config, { addRules }) => {
|
||||
export const graphql = defineMiddleware((config, { addRules }) => {
|
||||
config.plugins.push('@graphql-eslint');
|
||||
config.extends.push('plugin:@graphql-eslint/recommended');
|
||||
addRules(graphqlRules);
|
||||
};
|
||||
});
|
||||
|
@ -1,10 +1,13 @@
|
||||
import { JSDocRulesObject } from '@aet/eslint-define-config/src/rules/jsdoc';
|
||||
import type { Middleware } from '../index';
|
||||
import type { JSDocRulesObject } from '@aet/eslint-define-config/src/rules/jsdoc';
|
||||
import { defineMiddleware } from '../middleware';
|
||||
import { off } from '../constants';
|
||||
|
||||
const jsdocRules: Partial<JSDocRulesObject> = {};
|
||||
const jsdocRules: Partial<JSDocRulesObject> = {
|
||||
'jsdoc/require-jsdoc': off,
|
||||
};
|
||||
|
||||
export const jsdoc: Middleware = (config, { addRules }) => {
|
||||
export const jsdoc = defineMiddleware((config, { addRules }) => {
|
||||
config.plugins.push('jsdoc');
|
||||
config.extends.push('plugin:jsdoc/recommended-typescript');
|
||||
addRules(jsdocRules);
|
||||
};
|
||||
});
|
||||
|
@ -1,11 +1,12 @@
|
||||
import type { LocalRuleOptions, Middleware } from '../index';
|
||||
import type { LocalRuleOptions } from '../index';
|
||||
import { error } from '../constants';
|
||||
import { defineMiddleware } from '../middleware';
|
||||
|
||||
const localRules: Partial<LocalRuleOptions> = {
|
||||
'rules/no-import-dot': error,
|
||||
'rules/restrict-template-expressions': error,
|
||||
};
|
||||
|
||||
export const local: Middleware = (_, { addRules }) => {
|
||||
export const local = defineMiddleware((_, { addRules }) => {
|
||||
addRules(localRules);
|
||||
};
|
||||
});
|
||||
|
@ -1,9 +1,9 @@
|
||||
import type { Middleware } from '../index';
|
||||
import { defineMiddleware } from '../middleware';
|
||||
|
||||
export const storybook: Middleware = config => {
|
||||
export const storybook = defineMiddleware(config => {
|
||||
config.extends.push('plugin:storybook/recommended');
|
||||
};
|
||||
});
|
||||
|
||||
export const reactQuery: Middleware = config => {
|
||||
export const reactQuery = defineMiddleware(config => {
|
||||
config.extends.push('plugin:@tanstack/eslint-plugin-query/recommended');
|
||||
};
|
||||
});
|
||||
|
@ -1,14 +1,14 @@
|
||||
import type { Middleware } from '../index';
|
||||
import type { ReactRulesObject } from '@aet/eslint-define-config/src/rules/react';
|
||||
import type { ReactRefreshRulesObject } from '@aet/eslint-define-config/src/rules/react-refresh';
|
||||
import { error, off, warn } from '../constants';
|
||||
import { ReactRulesObject } from '@aet/eslint-define-config/src/rules/react';
|
||||
import { ReactRefreshRulesObject } from '@aet/eslint-define-config/src/rules/react-refresh';
|
||||
import { defineMiddleware } from '../middleware';
|
||||
|
||||
const reactRules: Partial<ReactRulesObject> = {
|
||||
'@eslint-react/no-missing-component-display-name': off,
|
||||
'@eslint-react/no-children-prop': error,
|
||||
};
|
||||
|
||||
export const react: Middleware = (config, { addRules }) => {
|
||||
export const react = defineMiddleware((config, { addRules }) => {
|
||||
config.plugins.push('@eslint-react/eslint-plugin', 'react-hooks');
|
||||
config.extends.push(
|
||||
'plugin:@eslint-react/recommended-legacy',
|
||||
@ -23,13 +23,13 @@ export const react: Middleware = (config, { addRules }) => {
|
||||
},
|
||||
});
|
||||
addRules(reactRules);
|
||||
};
|
||||
});
|
||||
|
||||
const refreshRules: Partial<ReactRefreshRulesObject> = {
|
||||
'react-refresh/only-export-components': [warn, { allowConstantExport: true }],
|
||||
};
|
||||
|
||||
export const reactRefresh: Middleware = (config, { addRules }) => {
|
||||
export const reactRefresh = defineMiddleware((config, { addRules }) => {
|
||||
config.plugins.push('react-refresh');
|
||||
addRules(refreshRules);
|
||||
};
|
||||
});
|
||||
|
@ -1,12 +1,12 @@
|
||||
import type { Middleware } from '../index';
|
||||
import { off } from '../constants';
|
||||
import type { TailwindRulesObject } from '@aet/eslint-define-config/src/rules/tailwind';
|
||||
import { defineMiddleware } from '../middleware';
|
||||
import { off } from '../constants';
|
||||
|
||||
const tailwindRules: Partial<TailwindRulesObject> = {
|
||||
'tailwindcss/no-custom-classname': off,
|
||||
} as const;
|
||||
|
||||
export const tailwind: Middleware = (config, { addRules }) => {
|
||||
export const tailwind = defineMiddleware((config, { addRules }) => {
|
||||
config.extends.push('plugin:tailwindcss/recommended');
|
||||
addRules(tailwindRules);
|
||||
};
|
||||
});
|
||||
|
@ -1,12 +1,12 @@
|
||||
import type { Middleware } from '../index';
|
||||
import { TestingLibraryRulesObject } from '@aet/eslint-define-config/src/rules/testing-library';
|
||||
import type { TestingLibraryRulesObject } from '@aet/eslint-define-config/src/rules/testing-library';
|
||||
import { defineMiddleware } from '../middleware';
|
||||
|
||||
const testingLibraryRules: Partial<TestingLibraryRulesObject> = {};
|
||||
|
||||
export const testingLibrary: Middleware = (config, { addRules }) => {
|
||||
export const testingLibrary = defineMiddleware((config, { addRules }) => {
|
||||
config.overrides.push({
|
||||
files: ['**/*.(spec|test).{ts,tsx}'],
|
||||
plugins: ['plugin:testing-library/react'],
|
||||
});
|
||||
addRules(testingLibraryRules);
|
||||
};
|
||||
});
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { error, off, warn } from '../constants';
|
||||
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';
|
||||
import { defineMiddleware } from '../middleware';
|
||||
|
||||
const importRules: Partial<ImportXRulesObject> = {
|
||||
'import-x/export': off,
|
||||
@ -45,7 +45,7 @@ const typescriptRules: Partial<TypeScriptRulesObject> = {
|
||||
'@typescript-eslint/unbound-method': off,
|
||||
};
|
||||
|
||||
export const importTypeScript: Middleware = (config, { addRules, addSettings }) => {
|
||||
export const importTypeScript = defineMiddleware((config, { addRules, addSettings }) => {
|
||||
config.parser = '@typescript-eslint/parser';
|
||||
config.plugins.push('@typescript-eslint', 'import-x');
|
||||
config.extends.push(
|
||||
@ -66,6 +66,7 @@ export const importTypeScript: Middleware = (config, { addRules, addSettings })
|
||||
files: ['.eslintrc.js', '.eslintrc.cjs', '*.config.js', 'index.js'],
|
||||
extends: ['plugin:@typescript-eslint/disable-type-checked'],
|
||||
rules: {
|
||||
'@typescript-eslint/no-require-imports': off,
|
||||
'rules/restrict-template-expressions': off,
|
||||
},
|
||||
},
|
||||
@ -79,4 +80,4 @@ export const importTypeScript: Middleware = (config, { addRules, addSettings })
|
||||
|
||||
addRules(importRules);
|
||||
addRules(typescriptRules);
|
||||
};
|
||||
});
|
||||
|
@ -1,32 +1,43 @@
|
||||
import type { Middleware } from '../index';
|
||||
/* eslint-disable unicorn/string-content */
|
||||
import type { UnicornRulesObject } from '@aet/eslint-define-config/src/rules/unicorn';
|
||||
import { defineMiddleware } from '../middleware';
|
||||
import { error, warn } from '../constants';
|
||||
import { UnicornRulesObject } from '@aet/eslint-define-config/src/rules/unicorn';
|
||||
|
||||
const suggest = (suggest: string) => ({ suggest, fix: false });
|
||||
|
||||
// https://github.com/sindresorhus/eslint-plugin-unicorn/tree/28e7498ad06679bb92343db53bb40a7b5ba2990a
|
||||
const unicornRules: Partial<UnicornRulesObject> = {
|
||||
'unicorn/better-regex': error,
|
||||
'unicorn/consistent-destructuring': warn,
|
||||
'unicorn/consistent-function-scoping': warn,
|
||||
'unicorn/escape-case': error,
|
||||
'unicorn/no-array-for-each': warn,
|
||||
'unicorn/no-array-method-this-argument': error,
|
||||
'unicorn/no-array-push-push': warn,
|
||||
'unicorn/no-await-in-promise-methods': error,
|
||||
'unicorn/no-console-spaces': warn,
|
||||
'unicorn/no-for-loop': warn,
|
||||
'unicorn/no-instanceof-array': error,
|
||||
'unicorn/no-invalid-fetch-options': error,
|
||||
'unicorn/no-invalid-remove-event-listener': error,
|
||||
'unicorn/no-lonely-if': warn,
|
||||
'unicorn/no-negation-in-equality-check': error,
|
||||
'unicorn/no-new-buffer': error,
|
||||
'unicorn/no-single-promise-in-promise-methods': error,
|
||||
'unicorn/no-static-only-class': error,
|
||||
'unicorn/no-typeof-undefined': error,
|
||||
// 'unicorn/no-unused-properties': warn,
|
||||
'unicorn/no-unnecessary-await': error,
|
||||
'unicorn/no-unnecessary-polyfills': error,
|
||||
'unicorn/no-unreadable-array-destructuring': warn,
|
||||
'unicorn/no-useless-fallback-in-spread': error,
|
||||
'unicorn/no-useless-promise-resolve-reject': error,
|
||||
'unicorn/no-useless-spread': error,
|
||||
'unicorn/no-useless-switch-case': error,
|
||||
|
||||
// https://github.com/prettier/eslint-config-prettier/issues/51
|
||||
// 'unicorn/number-literal-case': error,
|
||||
'unicorn/no-useless-undefined': error,
|
||||
'unicorn/no-zero-fractions': error,
|
||||
'unicorn/number-literal-case': error,
|
||||
'unicorn/prefer-array-find': error,
|
||||
'unicorn/prefer-array-flat': error,
|
||||
'unicorn/prefer-array-flat-map': error,
|
||||
'unicorn/prefer-array-some': error,
|
||||
'unicorn/prefer-at': error,
|
||||
@ -35,23 +46,32 @@ const unicornRules: Partial<UnicornRulesObject> = {
|
||||
'unicorn/prefer-default-parameters': warn,
|
||||
'unicorn/prefer-dom-node-dataset': error,
|
||||
'unicorn/prefer-dom-node-remove': error,
|
||||
'unicorn/prefer-dom-node-text-content': warn,
|
||||
'unicorn/prefer-export-from': [error, { ignoreUsedVariables: false }],
|
||||
'unicorn/prefer-includes': error,
|
||||
'unicorn/prefer-json-parse-buffer': warn,
|
||||
'unicorn/prefer-keyboard-event-key': warn,
|
||||
'unicorn/prefer-logical-operator-over-ternary': warn,
|
||||
'unicorn/prefer-math-trunc': error,
|
||||
'unicorn/prefer-math-trunc': warn,
|
||||
'unicorn/prefer-modern-dom-apis': error,
|
||||
'unicorn/prefer-modern-math-apis': error,
|
||||
'unicorn/prefer-negative-index': error,
|
||||
'unicorn/prefer-node-protocol': error,
|
||||
'unicorn/prefer-object-from-entries': error,
|
||||
'unicorn/prefer-optional-catch-binding': error,
|
||||
'unicorn/prefer-prototype-methods': error,
|
||||
'unicorn/prefer-reflect-apply': error,
|
||||
'unicorn/prefer-regexp-test': error,
|
||||
'unicorn/prefer-set-has': warn,
|
||||
'unicorn/prefer-set-size': error,
|
||||
'unicorn/prefer-string-raw': error,
|
||||
'unicorn/prefer-string-slice': error,
|
||||
'unicorn/prefer-string-starts-ends-with': warn,
|
||||
'unicorn/prefer-string-trim-start-end': error,
|
||||
'unicorn/prefer-switch': warn,
|
||||
'unicorn/prefer-ternary': warn,
|
||||
'unicorn/relative-url-style': warn,
|
||||
'unicorn/require-number-to-fixed-digits-argument': error,
|
||||
'unicorn/string-content': [
|
||||
warn,
|
||||
{
|
||||
@ -71,7 +91,7 @@ const unicornRules: Partial<UnicornRulesObject> = {
|
||||
'unicorn/template-indent': warn,
|
||||
};
|
||||
|
||||
export const unicorn: Middleware = (config, { addRules }) => {
|
||||
config.plugins.push('unicorn');
|
||||
export const unicorn = defineMiddleware((config, { addRules }) => {
|
||||
config.extends.push('plugin:unicorn/recommended');
|
||||
addRules(unicornRules);
|
||||
};
|
||||
});
|
||||
|
@ -1,12 +1,12 @@
|
||||
// https://github.com/typescript-eslint/typescript-eslint/blob/75c128856b1ce05a4fec799bfa6de03b3dab03d0/packages/eslint-plugin/src/rules/restrict-template-expressions.ts
|
||||
import * as ts from 'typescript';
|
||||
import { ESLintUtils, type TSESTree, AST_NODE_TYPES } from '@typescript-eslint/utils';
|
||||
import { AST_NODE_TYPES, ESLintUtils, type TSESTree } from '@typescript-eslint/utils';
|
||||
import {
|
||||
getConstrainedTypeAtLocation,
|
||||
getTypeName,
|
||||
isTypeAnyType,
|
||||
isTypeFlagSet,
|
||||
isTypeNeverType,
|
||||
getConstrainedTypeAtLocation,
|
||||
} from '@typescript-eslint/type-utils';
|
||||
import { getParserServices } from '@typescript-eslint/utils/eslint-utils';
|
||||
|
||||
@ -55,7 +55,7 @@ export default createRule<Option[], MessageId>({
|
||||
defaultOptions: [defaultOption],
|
||||
create(context, [options]) {
|
||||
const services = getParserServices(context);
|
||||
const checker = services.program!.getTypeChecker();
|
||||
const checker = services.program.getTypeChecker();
|
||||
const allowed = new Set(options.allow);
|
||||
|
||||
const { StringLike, NumberLike, BigIntLike, BooleanLike, Null, Undefined } =
|
||||
|
Reference in New Issue
Block a user