@shayanthenerd/eslint-config
Version:
A modern, flexible ESLint configuration for enforcing best practices and maintaining a consistent coding style
437 lines • 19.3 kB
text/typescript
import { JavascriptRules, PluginRules, RuleOptions } from "./eslintRules.mjs";
import { VueOptions } from "./options/vue.mjs";
import { ZodOptions } from "./options/zod.mjs";
import { NuxtOptions } from "./options/nuxt.mjs";
import { TestOptions } from "./options/test.mjs";
import { ReactOptions } from "./options/react.mjs";
import { BaselineOptions } from "./options/baseline.mjs";
import { MarkdownOptions } from "./options/markdown.mjs";
import { TailwindOptions } from "./options/tailwind.mjs";
import { StylisticOptions } from "./options/stylistic.mjs";
import { TypescriptOptions } from "./options/typescript.mjs";
import { Linter } from "eslint";
//#region src/types/index.d.ts
type ConfigOverrides = Pick<Linter.Config, 'name' | 'files' | 'ignores' | 'plugins' | 'settings' | 'languageOptions'>;
interface ConfigWithOverrides<ConfigRules extends Linter.RulesRecord> {
/**
* Override the current configuration object.
*
* The properties of this object are merged with and take precedence over the properties of the default configuration object.
*
* @see [eslint-flat-config-utils: `mergeConfigs`](https://jsr.io/@antfu/eslint-flat-config-utils/doc/~/mergeConfigs)
*/
overrides?: ConfigOverrides & {
/** The rules to override in the current configuration object. */
rules?: ConfigRules;
};
}
/** The options passed to the `defineConfig` function. */
interface Options {
/**
* Automatically enable configurations based on the detected dependencies, dev-dependencies, etc. in the _package.json_ file.
*
* Set to `'verbose'` to log the detected dependencies.
*
* Use the `packageDir` option to specify the path to the _package.json_ file.
*
* @default true
*/
autoDetectDeps?: boolean | 'verbose';
/**
* Specify the runtime environment.
*
* This is used by
* - `configs.baseline` option (disabled when `env` is set to a value other than `'browser'`)
* - [ESLint: Specifying Globals](https://eslint.org/docs/latest/use/configure/language-options#using-configuration-files)
* - [perfectionist/sort-imports: `env` option](https://perfectionist.dev/rules/sort-imports#environment)
*
* @default 'browser'
*/
env?: 'bun' | 'deno' | 'node' | 'browser';
/**
* Path to the _.gitignore_ file (relative to the current working directory).
*
* ESLint will ignore files and directories found in your _.gitignore_ file. Set to `false` to disable this behavior.
*
* It will fall back to the default value if set to an empty string (`''`).
*
* @default '.gitignore'
*
* @see [ESLint Ignore: Including GitIgnore Files](https://eslint.org/docs/latest/use/configure/ignore#include-gitignore-files)
*/
gitignore?: false | string;
/**
* Path to directory of the _package.json_ file (relative to the current working directory).
*
* This is used by
* - `autoDetectDeps` option
* - [import-x/no-extraneous-dependencies: `packageDir` option](https://github.com/un-ts/eslint-plugin-import-x/blob/master/docs/rules/no-extraneous-dependencies.md#packagedir)
* - [storybook/no-uninstalled-addons: `packageJsonLocation` option](https://github.com/storybookjs/storybook/blob/next/code/lib/eslint-plugin/docs/rules/no-uninstalled-addons.md#packagejsonlocation)
*
* It will fall back to the default value if set to an empty string (`''`).
*
* @default '.'
*/
packageDir?: string;
/**
* The path and the name of the root TypeScript config file.
*
* This is used by
* - [better-tailwindcss: `tsconfig` option](https://github.com/schoero/eslint-plugin-better-tailwindcss/blob/main/docs/settings/settings.md#tsconfig)
* - [perfectionist/sort-imports: `tsconfig` option](https://perfectionist.dev/rules/sort-imports#tsconfig)
*
* @default false // `{ rootDir: options.packageDir ?? '.', filename: 'tsconfig.json' }` if TypeScript integration is enabled
*/
tsConfig?: false | {
/**
* The directory of the root TypeScript config file.
*
* It will fall back to the default value if set to an empty string (`''`).
*
* @default options.packageDir ?? '.'
*/
rootDir?: string;
/**
* The name of the root TypeScript config file.
*
* It will fall back to the default value if set to an empty string (`''`).
*
* @default 'tsconfig.json'
*/
filename?: string;
};
/*** Project ***/
/**
* Configuration options applied to all files. Individual configurations will override these.
*
* @default
* {
* basePath: '.',
* languageOptions: {
* parserOptions: {},
* sourceType: 'module',
* ecmaVersion: 'latest',
* },
* linterOptions: {
* noInlineConfig: false,
* reportUnusedInlineConfigs: 'warn',
* reportUnusedDisableDirectives: 'warn'
* }
* name: 'shayanthenerd/project',
* }
*/
project?: {
/**
* The base path for resolving `files` and `ignores` patterns.
*
* Glob patterns in the configuration objects will be resolved relative to this path.
*
* It will fall back to the default value if set to an empty string (`''`).
*
* @default '.'
*
* @see [ESLint Configuration: Specifying Base Path](https://eslint.org/docs/latest/use/configure/configuration-files#specifying-base-path)
*/
basePath?: string;
/**
* Specify global variables.
*
* @default
* {
* astro: false, // `true` if `configs.astro` is enabled
* audioWorklet: false, // `true` if `env` is set to `browser`
* browser: true, // `true` if `env` is set to `browser`
* bun: false, // `true` if `env` is set to `bun`
* commonjs: false,
* deno: false, // `true` if `env` is set to `deno`
* node: true,
* nodeBuiltin: false, // `true` if `env` is set to `node`
* serviceworker: false, // `true` if `env` is set to `browser`
* sharedWorker: false, // `true` if `env` is set to `browser`
* vitest: false,
* vue: false, // `true` if `configs.vue` is enabled
* webextension: false, // `true` if `env` is set to `browser`
* worker: true,
* custom: {},
* }
*
* @see [Language Options: Specifying Globals](https://eslint.org/docs/latest/use/configure/language-options#using-configuration-files)
*/
globals?: {
astro?: boolean;
audioWorklet?: boolean;
browser?: boolean;
bun?: boolean;
commonjs?: boolean;
deno?: boolean;
node?: boolean;
nodeBuiltin?: boolean;
serviceworker?: boolean;
sharedWorker?: boolean;
vitest?: boolean;
vue?: boolean;
webextension?: boolean;
worker?: boolean;
custom?: Linter.LanguageOptions['globals'];
};
/**
* Patterns that ESLint should ignore globally. These patterns are resolved relative to the current working directory.
*
* @see [ESLint Configuration: Globally Ignoring Files](https://eslint.org/docs/latest/use/configure/configuration-files#globally-ignoring-files-with-ignores)
*/
ignores?: string[];
/**
* Specify the linting process.
*
* @see [ESLint Configuration: Linter Options](https://eslint.org/docs/latest/use/configure/configuration-files#configuring-linter-options)
*/
linterOptions?: {
/**
* Disallow inline (comment) configurations and disable-directives.
*
* @default false
*
* @see [ESLint Configuration: Disabling Inline Configuration](https://eslint.org/docs/latest/use/configure/configuration-files#disabling-inline-configuration)
*/
noInlineConfig?: Linter.LintOptions['allowInlineConfig'];
/**
* A severity string indicating if and how unused inline configs should be tracked and reported.
*
* @default 'warn'
*
* @see [ESLint Configuration: Reporting Unused Inline Configs](https://eslint.org/docs/latest/use/configure/configuration-files#reporting-unused-inline-configs)
*/
reportUnusedInlineConfigs?: Linter.StringSeverity;
/**
* A severity string indicating if and how unused disable and enable directives should be tracked and reported.
*
* @default 'warn'
*
* @see [ESLint Configuration: Reporting Unused Disable Directives](https://eslint.org/docs/latest/use/configure/configuration-files#reporting-unused-disable-directives)
*/
reportUnusedDisableDirectives?: Linter.StringSeverity;
};
/**
* A name for the configuration object. This is used in error messages and [config inspector](https://github.com/eslint/config-inspector) to help identify which configuration object is being used.
*
* It will fall back to the default value if set to an empty string (`''`).
*
* @default 'shayanthenerd/eslint-config'
*
* @see [ESLint Configuration: Naming Conventions](https://eslint.org/docs/latest/use/configure/configuration-files#configuration-naming-conventions)
*/
name?: string;
/**
* The available rules.
*
* @see [ESLint Configuration: Rules](https://eslint.org/docs/latest/use/configure/configuration-files#configuring-rules)
*/
rules?: Linter.RulesRecord;
/**
* Settings shared across all rules. Use this to specify information that should be available to every rule.
*
* @see [ESLint Configuration: Shared Settings](https://eslint.org/docs/latest/use/configure/configuration-files#configuring-shared-settings)
*/
settings?: Linter.Config['settings'];
};
/*** Configs ***/
/**
* Enable, disable, or customize the configurations.
*
* `autoDetectDeps` can enable configurations that are disabled by default. However, explicitly enabling or disabling a configuration takes precedence over `autoDetectDeps`.
*/
configs?: {
/**
* Use [eslint-plugin-astro](https://ota-meshi.github.io/eslint-plugin-astro) and [eslint-plugin-jsx-a11y](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y) to enforce Astro best practices and accessibility guidelines.
*
* @default false // `true` if "astro" is detected in the dependencies when `autoDetectDeps` is enabled
*/
astro?: boolean | ConfigWithOverrides<PluginRules<'astro'>>;
/**
* Use [eslint-plugin-baseline-js](https://github.com/3ru/eslint-plugin-baseline-js), [css/use-baseline](https://github.com/eslint/css/blob/main/docs/rules/use-baseline.md#options), [@html-eslint/use-baseline](https://html-eslint.org/docs/rules/use-baseline#options), and [@html-eslint/react/use-baseline](https://github.com/eslint/css/blob/main/docs/rules/use-baseline.md#options) to enforce the use of baseline features.
*
* @default true // `false` if `env` is set to a value other than `'browser'`
*/
baseline?: boolean | BaselineOptions;
/**
* Customize JavaScript (core) rules and options.
*
* This configuration cannot be disabled.
*/
javascript?: ConfigWithOverrides<JavascriptRules> & {
/**
* Enforce a maximum depth that blocks can be nested to reduce code complexity.
*
* @default 3
*
* @see [max-depth](https://eslint.org/docs/latest/rules/max-depth)
*/
maxDepth?: Exclude<RuleOptions<'max-depth'>, Record<string, unknown>>;
/**
* Enforce a maximum depth that callbacks can be nested to increase code clarity.
*
* @default 3
*
* @see [max-nested-callbacks](https://eslint.org/docs/latest/rules/max-nested-callbacks)
*/
maxNestedCallbacks?: Exclude<RuleOptions<'max-nested-callbacks'>, Record<string, unknown>>;
};
/**
* Use [@eslint/css](https://github.com/eslint/css) to enforce CSS best practices and identify mistakes.
*
* @default false
*/
css?: boolean | ConfigWithOverrides<PluginRules<'css'>>;
/**
* Use [@html-eslint/eslint-plugin](https://html-eslint.org) to enforce SEO and accessibility best practices, as well as some stylistic rules.
*
* @default false
*/
html?: boolean | (ConfigWithOverrides<PluginRules<'@html-eslint'>> & {
/**
* Enforce consistent naming convention for `id` attribute values.
*
* @default 'snake_case'
*
* @see [@html-eslint/id-naming-convention](https://html-eslint.org/docs/rules/id-naming-convention)
*/
idNamingConvention?: Exclude<RuleOptions<'@html-eslint/id-naming-convention'>, 'regex'>;
});
/**
* Use [eslint-plugin-import-x](https://github.com/un-ts/eslint-plugin-import-x) to organize imports and exports, and detect related issues.
*
* @default true
*/
importX?: boolean | ConfigWithOverrides<PluginRules<'import-x'>>;
/**
* Use [@eslint/markdown](https://github.com/eslint/markdown) to enforce best practices for Markdown files.
*
* @default true
*/
markdown?: boolean | MarkdownOptions;
/**
* Use [@next/eslint-plugin-next](https://github.com/vercel/next.js/tree/HEAD/packages/eslint-plugin-next) to enforce Next.js best practices and catch common mistakes.
*
* @default false // `true` if "next" is detected in the dependencies when `autoDetectDeps` is enabled
*/
next?: boolean | ConfigWithOverrides<PluginRules<'next'>>;
/**
* Use [eslint-plugin-n](https://github.com/eslint-community/eslint-plugin-n) to enforce Node.js best practices and catch common mistakes.
*
* Some rules depend on the specified Node.js version. Visit the documentation for [version-resolution options and project-specific configurations](https://github.com/eslint-community/eslint-plugin-n#configured-nodejs-version-range).
*
* @default true
*/
node?: boolean | ConfigWithOverrides<PluginRules<'n'>>;
/**
* Use [@nuxt/eslint-plugin](https://eslint.nuxt.com/packages/plugin) and [nuxt-link-checker (ESLint plugin)](https://nuxtseo.com/docs/link-checker/guides/eslint) to enforce Nuxt best practices and catch broken links.
*
* Enforce best practices and the use of Nuxt-specific components over their counterparts. For example, `<NuxtLink>` must be used instead of `<a>`, and `<NuxtTime>` instead of `<time>`.
*
* @default false // `true` if "nuxt" is detected in the dependencies when `autoDetectDeps` is enabled
*/
nuxt?: boolean | NuxtOptions;
/**
* Use [eslint-plugin-package-json](https://github.com/JoshuaKGoldberg/eslint-plugin-package-json) to ensure _package.json_ files are consistent, readable, and valid.
*
* @default true
*/
packageJson?: boolean | ConfigWithOverrides<PluginRules<'package-json'>>;
/**
* Use [eslint-plugin-perfectionist](https://perfectionist.dev) to sort imports, exports, maps, union types, etc.
*
* @default true
*/
perfectionist?: boolean | (ConfigWithOverrides<PluginRules<'perfectionist'>> & {
/**
* The type of sorting.
*
* @default 'line-length'
*
* @see [Perfectionist Settings: `type` option](https://perfectionist.dev/guide/getting-started#settings)
*/
sortType?: Exclude<RuleOptions<'perfectionist/sort-imports'>['type'], 'type-import-first'>;
});
/**
* Use [eslint-plugin-promise](https://github.com/eslint-community/eslint-plugin-promise) to enforce best practices for JavaScript promises.
*
* @default true
*/
promise?: boolean | ConfigWithOverrides<PluginRules<'promise'>>;
/**
* Use [@eslint-react/eslint-plugin](https://eslint-react.xyz), [eslint-plugin-jsx-a11y](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y), and [@html-eslint/eslint-plugin-react](https://html-eslint.org/docs/react/getting-started) to enforce React best practices and accessibility guidelines.
*
* @default false // `true` if "react" is detected in the dependencies when `autoDetectDeps` is enabled
*/
react?: boolean | ReactOptions;
/**
* Use [@stylistic/eslint-plugin](https://eslint.style) to enforce stylistic rules such as indentation, line length, spacing, quotes, semicolons, etc.
*
* @default true
*/
stylistic?: boolean | StylisticOptions;
/**
* Use [eslint-plugin-better-tailwindcss](https://github.com/schoero/eslint-plugin-better-tailwindcss) to sort Tailwind classes, check for unused or conflicting ones, and enforce best practices.
*
* @default false
*/
tailwind?: false | TailwindOptions;
/**
* Configuration options for the testing tools.
*/
test?: TestOptions;
/**
* Use [@typescript-eslint](https://typescript-eslint.io) to enforce TypeScript-specific rules.
*
* Setting this to `false` doesn't prevent ESLint from linting TypeScript files.
*
* This allows
* - [eslint-plugin-import-x](https://github.com/un-ts/eslint-plugin-import-x) to better understand imports from TypeScript files such as ".ts", ".tsx", etc.
* - [eslint-plugin-vue](https://eslint.vuejs.org) to enforce TypeScript-specific rules in the `<script setup lang="ts">` of Vue SFCs.
*
* @default false // `true` if "typescript" is detected in the dependencies when `autoDetectDeps` is enabled
*/
typescript?: boolean | TypescriptOptions;
/**
* Use [eslint-plugin-unicorn](https://github.com/sindresorhus/eslint-plugin-unicorn) to enforce general best practices and catch common mistakes.
*
* @default true
*/
unicorn?: boolean | ConfigWithOverrides<PluginRules<'unicorn'>> & {
/**
* Enforce a consistent style for different types of functions.
*
* Object properties and functions that don't match a specified role are ignored.
*
* New entries are merged with the defaults and take precedence over them.
*
* @default
* {
* callbacks: 'arrow-function',
* defaultExport: 'declaration',
* namedExports: 'declaration',
* namedFunctions: 'declaration',
* reassignedVariables: 'arrow-function',
* typedVariables: 'arrow-function',
* }
*
* @see [unicorn/consistent-function-style](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/consistent-function-style.md)
*/
functionStyle?: Partial<RuleOptions<'unicorn/consistent-function-style'>>;
};
/**
* Use [eslint-plugin-vue](https://eslint.vuejs.org) to enforce Vue best practices, accessibility guidelines, stylistic rules, and identify mistakes.
*
* @default false // `true` if "vue" is detected in the dependencies when `autoDetectDeps` is enabled
*/
vue?: boolean | VueOptions;
/**
* Use [eslint-plugin-zod](https://github.com/marcalexiei/eslint-zod/tree/main/plugins/eslint-plugin-zod) or [eslint-plugin-zod-mini](https://github.com/marcalexiei/eslint-zod/tree/main/plugins/eslint-plugin-zod-mini) to enforce best practices for defining Zod schemas.
*
* @default false // `true` if "zod" is detected in the dependencies when `autoDetectDeps` is enabled
*/
zod?: boolean | ZodOptions;
};
}
//#endregion
export type { ConfigWithOverrides, Options };