@coderwyd/eslint-config
Version:
Donny's ESLint config
1,693 lines (1,666 loc) • 51.8 kB
JavaScript
import process from "node:process";
import createCommand from "eslint-plugin-command/config";
import pluginComments from "@eslint-community/eslint-plugin-eslint-comments";
import pluginAntfu from "eslint-plugin-antfu";
import pluginDeMorgan from "eslint-plugin-de-morgan";
import pluginNode from "eslint-plugin-n";
import pluginPerfectionist from "eslint-plugin-perfectionist";
import pluginUnicorn from "eslint-plugin-unicorn";
import pluginUnusedImports from "eslint-plugin-unused-imports";
import { fileURLToPath } from "node:url";
import { getPackageInfoSync, isPackageExists } from "local-pkg";
import globals from "globals";
import prettierRules from "eslint-config-prettier";
import { configs } from "eslint-plugin-regexp";
//#region src/configs/command.ts
function command() {
return [{
...createCommand(),
name: "coderwyd/command/rules"
}];
}
//#endregion
//#region src/configs/comments.ts
function comments() {
return [{
name: "coderwyd/eslint-comments/rules",
plugins: { "eslint-comments": pluginComments },
rules: {
"eslint-comments/no-aggregating-enable": "error",
"eslint-comments/no-duplicate-disable": "error",
"eslint-comments/no-unlimited-disable": "error",
"eslint-comments/no-unused-enable": "error"
}
}];
}
//#endregion
//#region src/configs/de-morgan.ts
function deMorgan() {
return [{
name: "coderwyd/de-morgan/rules",
plugins: { "de-morgan": pluginDeMorgan },
rules: {
"de-morgan/no-negated-conjunction": "error",
"de-morgan/no-negated-disjunction": "error"
}
}];
}
//#endregion
//#region src/constants/glob.ts
const GLOB_SRC_EXT = "?([cm])[jt]s?(x)";
const GLOB_SRC = "**/*.?([cm])[jt]s?(x)";
const GLOB_TS = "**/*.?([cm])ts";
const GLOB_DTS = "**/*.d.?([cm])ts";
const GLOB_TSX = "**/*.?([cm])tsx";
const GLOB_VUE = "**/*.vue";
const GLOB_ASTRO_TS = "**/*.astro/*.ts";
const GLOB_SVELTE = "**/*.svelte";
const GLOB_JSON = "**/*.json";
const GLOB_JSON5 = "**/*.json5";
const GLOB_JSONC = "**/*.jsonc";
const GLOB_MARKDOWN = "**/*.md";
const GLOB_YAML = "**/*.y?(a)ml";
const GLOB_MARKDOWN_CODE = `${GLOB_MARKDOWN}/${GLOB_SRC}`;
const GLOB_TESTS = [
`**/__tests__/**/*.${GLOB_SRC_EXT}`,
`**/*.spec.${GLOB_SRC_EXT}`,
`**/*.test.${GLOB_SRC_EXT}`,
`**/*.bench.${GLOB_SRC_EXT}`,
`**/*.benchmark.${GLOB_SRC_EXT}`
];
const GLOB_EXCLUDE = [
"**/node_modules",
"**/dist",
"**/package-lock.json",
"**/yarn.lock",
"**/pnpm-lock.yaml",
"**/bun.lockb",
"**/output",
"**/coverage",
"**/temp",
"**/.temp",
"**/tmp",
"**/.tmp",
"**/.history",
"**/.vitepress/cache",
"**/.nuxt",
"**/.next",
"**/.svelte-kit",
"**/.vercel",
"**/.changeset",
"**/.idea",
"**/.cache",
"**/.output",
"**/.vite-inspect",
"**/.yarn",
"**/vite.config.*.timestamp-*",
"**/CHANGELOG*.md",
"**/*.min.*",
"**/LICENSE*",
"**/__snapshots__",
"**/auto-import?(s).d.ts",
"**/components.d.ts"
];
//#endregion
//#region src/configs/ignores.ts
function ignores(userIgnores = []) {
return [{
ignores: [...GLOB_EXCLUDE, ...userIgnores],
name: "coderwyd/ignores"
}];
}
//#endregion
//#region src/shared/index.ts
const scopeUrl = fileURLToPath(new URL(".", import.meta.url));
const isCwdInScope = isPackageExists("@coderwyd/eslint-config");
/**
* Combine array and non-array configs into a single array.
*/
async function combine(...configs$1) {
const resolved = await Promise.all(configs$1);
return resolved.flat();
}
/**
* Rename plugin prefixes in a rule object.
* Accepts a map of prefixes to rename.
*
* @example
* ```ts
* import { renameRules } from '@coderwyd/eslint-config'
*
* export default [{
* rules: renameRules(
* {
* '@typescript-eslint/indent': 'error'
* },
* { '@typescript-eslint': 'ts' }
* )
* }]
* ```
*/
function renameRules(rules, map) {
return Object.fromEntries(Object.entries(rules).map(([key, value]) => {
for (const [from, to] of Object.entries(map)) if (key.startsWith(`${from}/`)) return [to + key.slice(from.length), value];
return [key, value];
}));
}
/**
* Rename plugin names a flat configs array
*
* @example
* ```ts
* import { renamePluginInConfigs } from '@antfu/eslint-config'
* import someConfigs from './some-configs'
*
* export default renamePluginInConfigs(someConfigs, {
* '@typescript-eslint': 'ts',
* 'import-x': 'import',
* })
* ```
*/
function renamePluginInConfigs(configs$1, map) {
return configs$1.map((i) => {
const clone = { ...i };
if (clone.rules) clone.rules = renameRules(clone.rules, map);
if (clone.plugins) clone.plugins = Object.fromEntries(Object.entries(clone.plugins).map(([key, value]) => {
if (key in map) return [map[key], value];
return [key, value];
}));
return clone;
});
}
function getVueVersion() {
const pkg = getPackageInfoSync("vue", { paths: [process.cwd()] });
if (pkg && typeof pkg.version === "string" && !Number.isNaN(+pkg.version[0])) return +pkg.version[0];
return 3;
}
function toArray(value) {
return Array.isArray(value) ? value : [value];
}
async function interopDefault(m) {
const resolved = await m;
return resolved.default || resolved;
}
function isPackageInScope(name) {
return isPackageExists(name, { paths: [scopeUrl] });
}
async function ensurePackages(packages) {
if (process.env.CI || process.stdout.isTTY === false || isCwdInScope === false) return;
const nonExistingPackages = packages.filter((i) => !isPackageInScope(i));
if (nonExistingPackages.length === 0) return;
const { default: prompts } = await import("prompts");
const { result } = await prompts([{
message: `${nonExistingPackages.length === 1 ? "Package is" : "Packages are"} required for this config: ${nonExistingPackages.join(", ")}. Do you want to install them?`,
name: "result",
type: "confirm"
}]);
if (result) await import("@antfu/install-pkg").then((i) => i.installPackage(nonExistingPackages, { dev: true }));
}
function resolveSubOptions(options, key) {
return typeof options[key] === "boolean" ? {} : options[key] || {};
}
function getOverrides(options, key) {
const subOptions = resolveSubOptions(options, key);
return { ..."overrides" in subOptions && subOptions.overrides ? subOptions.overrides : {} };
}
function isInEditorEnv() {
if (process.env.CI) return false;
if (isInGitHooksOrLintStaged()) return false;
return !!(process.env.VSCODE_PID || process.env.VSCODE_CWD || process.env.JETBRAINS_IDE || process.env.VIM || process.env.NVIM || false);
}
function isInGitHooksOrLintStaged() {
return !!(process.env.GIT_PARAMS || process.env.VSCODE_GIT_COMMAND || process.env.npm_lifecycle_script?.startsWith("lint-staged") || process.env.npm_lifecycle_script?.startsWith("nano-staged") || false);
}
//#endregion
//#region src/configs/imports.ts
async function imports() {
const pluginImport = await interopDefault(import("./dist-DYrxmIwK.js"));
return [{
name: "coderwyd/imports/rules",
plugins: {
antfu: pluginAntfu,
import: pluginImport
},
rules: {
"antfu/import-dedupe": "error",
"antfu/no-import-dist": "error",
"antfu/no-import-node-modules-by-path": "error",
"import/consistent-type-specifier-style": ["error", "prefer-top-level"],
"import/first": "error",
"import/newline-after-import": ["error", { count: 1 }],
"import/no-duplicates": "error",
"import/no-mutable-exports": "error",
"import/no-named-default": "error"
}
}];
}
//#endregion
//#region src/configs/javascript.ts
function javascript(options = {}) {
const { isInEditor: isInEditor$1 = false, overrides = {} } = options;
return [{
languageOptions: {
ecmaVersion: 2022,
globals: {
...globals.browser,
...globals.es2021,
...globals.node,
document: "readonly",
navigator: "readonly",
window: "readonly"
},
parserOptions: {
ecmaFeatures: { jsx: true },
ecmaVersion: 2022,
sourceType: "module"
},
sourceType: "module"
},
linterOptions: { reportUnusedDisableDirectives: true },
name: "coderwyd/javascript/setup"
}, {
name: "coderwyd/javascript/rules",
plugins: { "unused-imports": pluginUnusedImports },
rules: {
"accessor-pairs": ["error", {
enforceForClassMembers: true,
setWithoutGet: true
}],
"antfu/no-top-level-await": "error",
"antfu/top-level-function": "error",
"array-callback-return": "error",
"block-scoped-var": "error",
"constructor-super": "error",
"default-case-last": "error",
"dot-notation": ["error", { allowKeywords: true }],
eqeqeq: ["error", "smart"],
"for-direction": "error",
"getter-return": "error",
"new-cap": ["error", {
capIsNew: false,
newIsCap: true,
properties: true
}],
"no-alert": "error",
"no-array-constructor": "error",
"no-async-promise-executor": "error",
"no-caller": "error",
"no-case-declarations": "error",
"no-class-assign": "error",
"no-compare-neg-zero": "error",
"no-cond-assign": ["error", "always"],
"no-console": ["error", { allow: ["warn", "error"] }],
"no-const-assign": "error",
"no-constant-binary-expression": "error",
"no-constant-condition": "error",
"no-control-regex": "error",
"no-debugger": "error",
"no-delete-var": "error",
"no-dupe-args": "error",
"no-dupe-class-members": "error",
"no-dupe-keys": "error",
"no-duplicate-case": "error",
"no-empty": ["error", { allowEmptyCatch: true }],
"no-empty-character-class": "error",
"no-empty-pattern": "error",
"no-eval": "error",
"no-ex-assign": "error",
"no-extend-native": "error",
"no-extra-bind": "error",
"no-extra-boolean-cast": "error",
"no-fallthrough": "error",
"no-func-assign": "error",
"no-global-assign": "error",
"no-implied-eval": "error",
"no-import-assign": "error",
"no-invalid-regexp": "error",
"no-irregular-whitespace": "error",
"no-iterator": "error",
"no-labels": ["error", {
allowLoop: false,
allowSwitch: false
}],
"no-lone-blocks": "error",
"no-loss-of-precision": "error",
"no-misleading-character-class": "error",
"no-multi-str": "error",
"no-new": "error",
"no-new-func": "error",
"no-new-native-nonconstructor": "error",
"no-new-wrappers": "error",
"no-obj-calls": "error",
"no-object-constructor": "error",
"no-octal": "error",
"no-octal-escape": "error",
"no-proto": "error",
"no-prototype-builtins": "error",
"no-redeclare": ["error", { builtinGlobals: false }],
"no-regex-spaces": "error",
"no-restricted-globals": [
"error",
{
message: "Use `globalThis` instead.",
name: "global"
},
{
message: "Use `globalThis` instead.",
name: "self"
}
],
"no-restricted-properties": [
"error",
{
message: "Use `Object.getPrototypeOf` or `Object.setPrototypeOf` instead.",
property: "__proto__"
},
{
message: "Use `Object.defineProperty` instead.",
property: "__defineGetter__"
},
{
message: "Use `Object.defineProperty` instead.",
property: "__defineSetter__"
},
{
message: "Use `Object.getOwnPropertyDescriptor` instead.",
property: "__lookupGetter__"
},
{
message: "Use `Object.getOwnPropertyDescriptor` instead.",
property: "__lookupSetter__"
}
],
"no-restricted-syntax": [
"error",
"TSEnumDeclaration[const=true]",
"TSExportAssignment"
],
"no-self-assign": ["error", { props: true }],
"no-self-compare": "error",
"no-sequences": "error",
"no-shadow-restricted-names": "error",
"no-sparse-arrays": "error",
"no-template-curly-in-string": "error",
"no-this-before-super": "error",
"no-throw-literal": "error",
"no-undef": "error",
"no-undef-init": "error",
"no-unexpected-multiline": "error",
"no-unmodified-loop-condition": "error",
"no-unneeded-ternary": ["error", { defaultAssignment: false }],
"no-unreachable": "error",
"no-unreachable-loop": "error",
"no-unsafe-finally": "error",
"no-unsafe-negation": "error",
"no-unused-expressions": ["error", {
allowShortCircuit: true,
allowTaggedTemplates: true,
allowTernary: true
}],
"no-unused-vars": "off",
"no-use-before-define": ["error", {
classes: false,
functions: false,
variables: true
}],
"no-useless-backreference": "error",
"no-useless-call": "error",
"no-useless-catch": "error",
"no-useless-computed-key": "error",
"no-useless-constructor": "error",
"no-useless-rename": "error",
"no-useless-return": "error",
"no-var": "error",
"no-with": "error",
"object-shorthand": [
"error",
"always",
{
avoidQuotes: true,
ignoreConstructors: false
}
],
"one-var": ["error", { initialized: "never" }],
"prefer-arrow-callback": ["error", {
allowNamedFunctions: false,
allowUnboundThis: true
}],
"prefer-const": ["error", {
destructuring: "all",
ignoreReadBeforeAssign: true
}],
"prefer-exponentiation-operator": "error",
"prefer-regex-literals": ["error", { disallowRedundantWrapping: true }],
"prefer-rest-params": "error",
"prefer-spread": "error",
"prefer-template": "error",
"require-await": "error",
"require-yield": "error",
"symbol-description": "error",
"unicode-bom": ["error", "never"],
"unused-imports/no-unused-imports": isInEditor$1 ? "off" : "error",
"unused-imports/no-unused-vars": ["error", {
args: "after-used",
argsIgnorePattern: "^_",
ignoreRestSiblings: true,
vars: "all",
varsIgnorePattern: "^_"
}],
"use-isnan": ["error", {
enforceForIndexOf: true,
enforceForSwitchCase: true
}],
"valid-typeof": ["error", { requireStringLiterals: true }],
"vars-on-top": "error",
yoda: ["error", "never"],
...overrides
}
}];
}
//#endregion
//#region src/configs/jsdoc.ts
async function jsdoc() {
return [{
name: "coderwyd/jsdoc/rules",
plugins: { jsdoc: await interopDefault(import("eslint-plugin-jsdoc")) },
rules: {
"jsdoc/check-access": "warn",
"jsdoc/check-param-names": "warn",
"jsdoc/check-property-names": "warn",
"jsdoc/check-types": "warn",
"jsdoc/empty-tags": "warn",
"jsdoc/implements-on-classes": "warn",
"jsdoc/no-defaults": "warn",
"jsdoc/no-multi-asterisks": "warn",
"jsdoc/require-param-name": "warn",
"jsdoc/require-property": "warn",
"jsdoc/require-property-description": "warn",
"jsdoc/require-property-name": "warn",
"jsdoc/require-returns-check": "warn",
"jsdoc/require-returns-description": "warn",
"jsdoc/require-yields-check": "warn"
}
}];
}
//#endregion
//#region src/configs/jsonc.ts
async function jsonc(options = {}) {
const { files = [
GLOB_JSON,
GLOB_JSON5,
GLOB_JSONC
], overrides = {} } = options || {};
const [pluginJsonc, parserJsonc] = await Promise.all([interopDefault(import("eslint-plugin-jsonc")), interopDefault(import("jsonc-eslint-parser"))]);
return [{
name: "coderwyd/jsonc/setup",
plugins: { jsonc: pluginJsonc }
}, {
files,
languageOptions: { parser: parserJsonc },
name: "coderwyd/jsonc/rules",
rules: {
"jsonc/no-bigint-literals": "error",
"jsonc/no-binary-expression": "error",
"jsonc/no-binary-numeric-literals": "error",
"jsonc/no-dupe-keys": "error",
"jsonc/no-escape-sequence-in-identifier": "error",
"jsonc/no-floating-decimal": "error",
"jsonc/no-hexadecimal-numeric-literals": "error",
"jsonc/no-infinity": "error",
"jsonc/no-multi-str": "error",
"jsonc/no-nan": "error",
"jsonc/no-number-props": "error",
"jsonc/no-numeric-separators": "error",
"jsonc/no-octal": "error",
"jsonc/no-octal-escape": "error",
"jsonc/no-octal-numeric-literals": "error",
"jsonc/no-parenthesized": "error",
"jsonc/no-plus-sign": "error",
"jsonc/no-regexp-literals": "error",
"jsonc/no-sparse-arrays": "error",
"jsonc/no-template-literals": "error",
"jsonc/no-undefined-value": "error",
"jsonc/no-unicode-codepoint-escapes": "error",
"jsonc/no-useless-escape": "error",
"jsonc/space-unary-ops": "error",
"jsonc/valid-json-number": "error",
"jsonc/vue-custom-block/no-parsing-error": "error",
...overrides
}
}];
}
//#endregion
//#region src/configs/node.ts
function node() {
return [{
name: "coderwyd/node/rules",
plugins: { node: pluginNode },
rules: {
"node/handle-callback-err": ["error", "^(err|error)$"],
"node/no-deprecated-api": "error",
"node/no-exports-assign": "error",
"node/no-new-require": "error",
"node/no-path-concat": "error",
"node/no-unsupported-features/es-builtins": "error",
"node/prefer-global/buffer": ["error", "never"],
"node/prefer-global/process": ["error", "never"],
"node/process-exit-as-throw": "error"
}
}];
}
//#endregion
//#region src/configs/perfectionist.ts
/**
* Optional perfectionist plugin for props and items sorting.
*
* @see https://github.com/azat-io/eslint-plugin-perfectionist
*/
function perfectionist() {
return [{
name: "coderwyd/perfectionist/rules",
plugins: { perfectionist: pluginPerfectionist },
rules: {
"perfectionist/sort-exports": ["error", {
order: "asc",
type: "natural"
}],
"perfectionist/sort-imports": ["warn", {
groups: [
"side-effect-style",
"value-style",
"value-builtin",
"value-external",
"value-subpath",
"value-internal",
"value-parent",
"value-sibling",
"value-index",
"ts-equals-import",
"side-effect",
"type-builtin",
"type-external",
"type-subpath",
"type-internal",
"type-parent",
"type-sibling",
"type-index",
"unknown"
],
internalPattern: ["^[~@#]/.*"],
newlinesBetween: "ignore",
order: "asc",
type: "natural"
}],
"perfectionist/sort-named-exports": ["warn", {
groupKind: "values-first",
order: "asc",
type: "natural"
}],
"perfectionist/sort-named-imports": ["warn", {
groupKind: "values-first",
order: "asc",
type: "natural"
}]
}
}];
}
//#endregion
//#region src/configs/prettier.ts
const { rules: eslintRules } = prettierRules;
function prettier() {
return [{
name: "coderwyd/prettier/rules",
rules: {
...eslintRules,
"arrow-body-style": "off",
"prefer-arrow-callback": "off"
}
}];
}
//#endregion
//#region src/env.ts
const isInEditor = !!((process.env.VSCODE_PID || process.env.VSCODE_CWD || process.env.JETBRAINS_IDE || process.env.VIM || process.env.NVIM) && !process.env.CI);
const VueJsPackages = [
"vue",
"nuxt",
"vitepress",
"@slidev/cli"
];
const RemixPackages = [
"@remix-run/node",
"@remix-run/react",
"@remix-run/serve",
"@remix-run/dev"
];
const ReactRouterPackages = [
"@react-router/node",
"@react-router/react",
"@react-router/serve",
"@react-router/dev"
];
const NextJsPackages = ["next"];
const ReactRefreshAllowConstantExportPackages = ["vite"];
const isUsingTypeScript = isPackageExists("typescript");
const isUsingVue = hasPackages(VueJsPackages);
const isUsingRemix = hasPackages(RemixPackages);
const isUsingReactRouter = hasPackages(ReactRouterPackages);
const isUsingNext = hasPackages(NextJsPackages);
const isAllowConstantExport = hasPackages(ReactRefreshAllowConstantExportPackages);
function hasPackages(packages) {
return packages.some((name) => isPackageExists(name));
}
//#endregion
//#region src/configs/react.ts
async function react(options = {}) {
const { files = [GLOB_SRC], filesTypeAware = [GLOB_TS, GLOB_TSX], ignoresTypeAware = [`${GLOB_MARKDOWN}/**`, GLOB_ASTRO_TS], overrides = {}, tsconfigPath } = options;
await ensurePackages([
"@eslint-react/eslint-plugin",
"eslint-plugin-react-hooks",
"eslint-plugin-react-refresh"
]);
const isTypeAware = !!tsconfigPath;
const typeAwareRules = { "react/no-leaked-conditional-rendering": "warn" };
const [pluginReact, pluginReactHooks, pluginReactRefresh] = await Promise.all([
interopDefault(import("@eslint-react/eslint-plugin")),
interopDefault(import("eslint-plugin-react-hooks")),
interopDefault(import("eslint-plugin-react-refresh"))
]);
const plugins = pluginReact.configs.all.plugins;
return [
{
name: "coderwyd/react/setup",
plugins: {
react: plugins["@eslint-react"],
"react-dom": plugins["@eslint-react/dom"],
"react-hooks": pluginReactHooks,
"react-hooks-extra": plugins["@eslint-react/hooks-extra"],
"react-naming-convention": plugins["@eslint-react/naming-convention"],
"react-refresh": pluginReactRefresh,
"react-web-api": plugins["@eslint-react/web-api"]
}
},
{
files,
languageOptions: {
parserOptions: { ecmaFeatures: { jsx: true } },
sourceType: "module"
},
name: "coderwyd/react/rules",
rules: {
"react/no-access-state-in-setstate": "error",
"react/no-array-index-key": "warn",
"react/no-children-count": "warn",
"react/no-children-for-each": "warn",
"react/no-children-map": "warn",
"react/no-children-only": "warn",
"react/no-children-to-array": "warn",
"react/no-clone-element": "warn",
"react/no-comment-textnodes": "warn",
"react/no-component-will-mount": "error",
"react/no-component-will-receive-props": "error",
"react/no-component-will-update": "error",
"react/no-context-provider": "warn",
"react/no-create-ref": "error",
"react/no-default-props": "error",
"react/no-direct-mutation-state": "error",
"react/no-duplicate-jsx-props": "warn",
"react/no-duplicate-key": "warn",
"react/no-forward-ref": "warn",
"react/no-implicit-key": "warn",
"react/no-missing-key": "error",
"react/no-nested-component-definitions": "error",
"react/no-prop-types": "error",
"react/no-redundant-should-component-update": "error",
"react/no-set-state-in-component-did-mount": "warn",
"react/no-set-state-in-component-did-update": "warn",
"react/no-set-state-in-component-will-update": "warn",
"react/no-string-refs": "error",
"react/no-unsafe-component-will-mount": "warn",
"react/no-unsafe-component-will-receive-props": "warn",
"react/no-unsafe-component-will-update": "warn",
"react/no-unstable-context-value": "warn",
"react/no-unstable-default-props": "warn",
"react/no-unused-class-component-members": "warn",
"react/no-unused-state": "warn",
"react/no-use-context": "warn",
"react/no-useless-forward-ref": "warn",
"react/use-jsx-vars": "warn",
"react-dom/no-dangerously-set-innerhtml": "warn",
"react-dom/no-dangerously-set-innerhtml-with-children": "error",
"react-dom/no-find-dom-node": "error",
"react-dom/no-flush-sync": "error",
"react-dom/no-hydrate": "error",
"react-dom/no-missing-button-type": "warn",
"react-dom/no-missing-iframe-sandbox": "warn",
"react-dom/no-namespace": "error",
"react-dom/no-render": "error",
"react-dom/no-render-return-value": "error",
"react-dom/no-script-url": "warn",
"react-dom/no-unsafe-iframe-sandbox": "warn",
"react-dom/no-unsafe-target-blank": "warn",
"react-dom/no-use-form-state": "error",
"react-dom/no-void-elements-with-children": "error",
"react-hooks/exhaustive-deps": "warn",
"react-hooks/rules-of-hooks": "error",
"react-hooks/react-compiler": "warn",
"react-hooks-extra/no-direct-set-state-in-use-effect": "warn",
"react-hooks-extra/no-unnecessary-use-prefix": "warn",
"react-web-api/no-leaked-event-listener": "warn",
"react-web-api/no-leaked-interval": "warn",
"react-web-api/no-leaked-resize-observer": "warn",
"react-web-api/no-leaked-timeout": "warn",
"react-refresh/only-export-components": ["warn", {
allowConstantExport: isAllowConstantExport,
allowExportNames: [...isUsingNext ? [
"dynamic",
"dynamicParams",
"revalidate",
"fetchCache",
"runtime",
"preferredRegion",
"maxDuration",
"config",
"generateStaticParams",
"metadata",
"generateMetadata",
"viewport",
"generateViewport"
] : [], ...isUsingRemix || isUsingReactRouter ? [
"meta",
"links",
"headers",
"loader",
"action"
] : []]
}],
...overrides
}
},
...isTypeAware ? [{
files: filesTypeAware,
ignores: ignoresTypeAware,
name: "antfu/react/type-aware-rules",
rules: { ...typeAwareRules }
}] : []
];
}
//#endregion
//#region src/configs/regexp.ts
function regexp(options = {}) {
const config = configs["flat/recommended"];
const rules = { ...config.rules };
if (options.level === "warn") Object.keys(rules).forEach((key) => {
if (rules[key] === "error") rules[key] = "warn";
});
return [{
...config,
name: "coderwyd/regexp/rules",
rules: {
...rules,
...options.overrides
}
}];
}
//#endregion
//#region src/configs/sort.ts
/**
* Sort package.json
*
* Requires `jsonc` config
*/
function sortPackageJson() {
return [{
files: ["**/package.json"],
name: "coderwyd/sort/package-json",
rules: {
"jsonc/sort-array-values": ["error", {
order: { type: "asc" },
pathPattern: "^files$"
}],
"jsonc/sort-keys": [
"error",
{
order: [
"publisher",
"name",
"displayName",
"type",
"version",
"private",
"packageManager",
"description",
"author",
"license",
"funding",
"homepage",
"repository",
"bugs",
"keywords",
"categories",
"sideEffects",
"imports",
"exports",
"main",
"module",
"unpkg",
"jsdelivr",
"types",
"typesVersions",
"bin",
"icon",
"files",
"engines",
"activationEvents",
"contributes",
"scripts",
"peerDependencies",
"peerDependenciesMeta",
"dependencies",
"optionalDependencies",
"devDependencies",
"pnpm",
"overrides",
"resolutions",
"husky",
"simple-git-hooks",
"lint-staged",
"nano-staged",
"eslintConfig"
],
pathPattern: "^$"
},
{
order: { type: "asc" },
pathPattern: "^(?:dev|peer|optional|bundled)?[Dd]ependencies(Meta)?$"
},
{
order: { type: "asc" },
pathPattern: "^(?:resolutions|overrides|pnpm.overrides)$"
},
{
order: [
"types",
"import",
"require",
"default"
],
pathPattern: "^exports.*$"
},
{
order: [
"pre-commit",
"prepare-commit-msg",
"commit-msg",
"post-commit",
"pre-rebase",
"post-rewrite",
"post-checkout",
"post-merge",
"pre-push",
"pre-auto-gc"
],
pathPattern: "^(?:gitHooks|husky|simple-git-hooks)$"
}
]
}
}];
}
/**
* Sort tsconfig.json
*
* Requires `jsonc` config
*/
function sortTsconfig() {
return [{
files: ["**/tsconfig.json", "**/tsconfig.*.json"],
name: "coderwyd/sort/tsconfig-json",
rules: { "jsonc/sort-keys": [
"error",
{
order: [
"extends",
"compilerOptions",
"references",
"files",
"include",
"exclude"
],
pathPattern: "^$"
},
{
order: [
"incremental",
"composite",
"tsBuildInfoFile",
"disableSourceOfProjectReferenceRedirect",
"disableSolutionSearching",
"disableReferencedProjectLoad",
"target",
"jsx",
"jsxFactory",
"jsxFragmentFactory",
"jsxImportSource",
"lib",
"moduleDetection",
"noLib",
"reactNamespace",
"useDefineForClassFields",
"emitDecoratorMetadata",
"experimentalDecorators",
"libReplacement",
"baseUrl",
"rootDir",
"rootDirs",
"customConditions",
"module",
"moduleResolution",
"moduleSuffixes",
"noResolve",
"paths",
"resolveJsonModule",
"resolvePackageJsonExports",
"resolvePackageJsonImports",
"typeRoots",
"types",
"allowArbitraryExtensions",
"allowImportingTsExtensions",
"allowUmdGlobalAccess",
"allowJs",
"checkJs",
"maxNodeModuleJsDepth",
"strict",
"strictBindCallApply",
"strictFunctionTypes",
"strictNullChecks",
"strictPropertyInitialization",
"allowUnreachableCode",
"allowUnusedLabels",
"alwaysStrict",
"exactOptionalPropertyTypes",
"noFallthroughCasesInSwitch",
"noImplicitAny",
"noImplicitOverride",
"noImplicitReturns",
"noImplicitThis",
"noPropertyAccessFromIndexSignature",
"noUncheckedIndexedAccess",
"noUnusedLocals",
"noUnusedParameters",
"useUnknownInCatchVariables",
"declaration",
"declarationDir",
"declarationMap",
"downlevelIteration",
"emitBOM",
"emitDeclarationOnly",
"importHelpers",
"importsNotUsedAsValues",
"inlineSourceMap",
"inlineSources",
"mapRoot",
"newLine",
"noEmit",
"noEmitHelpers",
"noEmitOnError",
"outDir",
"outFile",
"preserveConstEnums",
"preserveValueImports",
"removeComments",
"sourceMap",
"sourceRoot",
"stripInternal",
"allowSyntheticDefaultImports",
"esModuleInterop",
"forceConsistentCasingInFileNames",
"isolatedDeclarations",
"isolatedModules",
"preserveSymlinks",
"verbatimModuleSyntax",
"erasableSyntaxOnly",
"skipDefaultLibCheck",
"skipLibCheck"
],
pathPattern: "^compilerOptions$"
}
] }
}];
}
//#endregion
//#region src/configs/specials.ts
function specials() {
return [
{
files: [`**/scripts/${GLOB_SRC}`],
name: "coderwyd/specials/scripts",
rules: {
"antfu/no-top-level-await": "off",
"no-console": "off",
"ts/explicit-function-return-type": "off"
}
},
{
files: [`**/cli/${GLOB_SRC}`, `**/cli.${GLOB_SRC_EXT}`],
name: "coderwyd/specials/cli",
rules: {
"antfu/no-top-level-await": "off",
"no-console": "off"
}
},
{
files: ["**/bin/**/*", `**/bin.${GLOB_SRC_EXT}`],
name: "coderwyd/specials/bin",
rules: {
"antfu/no-import-dist": "off",
"antfu/no-import-node-modules-by-path": "off"
}
},
{
files: [GLOB_DTS],
name: "coderwyd/specials/dts",
rules: {
"eslint-comments/no-unlimited-disable": "off",
"import/no-duplicates": "off",
"no-restricted-syntax": "off",
"unused-imports/no-unused-vars": "off"
}
},
{
files: ["**/*.{test,spec}.([tj])s?(x)"],
name: "coderwyd/specials/test",
rules: {
"antfu/no-top-level-await": "off",
"no-unused-expressions": "off"
}
},
{
files: ["**/*.js", "**/*.cjs"],
name: "coderwyd/specials/cjs",
rules: { "ts/no-require-imports": "off" }
}
];
}
//#endregion
//#region src/configs/svelte.ts
async function svelte(options = {}) {
const { files = [GLOB_SVELTE], overrides = {} } = options;
await ensurePackages(["eslint-plugin-svelte"]);
const [pluginSvelte, parserSvelte] = await Promise.all([interopDefault(import("eslint-plugin-svelte")), interopDefault(import("svelte-eslint-parser"))]);
return [{
name: "coderwyd/svelte/setup",
plugins: { svelte: pluginSvelte }
}, {
files,
languageOptions: {
parser: parserSvelte,
parserOptions: {
extraFileExtensions: [".svelte"],
parser: options.typescript ? await interopDefault(import("@typescript-eslint/parser")) : null
}
},
name: "coderwyd/svelte/rules",
processor: pluginSvelte.processors[".svelte"],
rules: {
"import/no-mutable-exports": "off",
"no-undef": "off",
"no-unused-vars": ["error", {
args: "none",
caughtErrors: "none",
ignoreRestSiblings: true,
vars: "all",
varsIgnorePattern: "^(\\$\\$Props$|\\$\\$Events$|\\$\\$Slots$)"
}],
"svelte/comment-directive": "error",
"svelte/no-at-debug-tags": "warn",
"svelte/no-at-html-tags": "error",
"svelte/no-dupe-else-if-blocks": "error",
"svelte/no-dupe-style-properties": "error",
"svelte/no-dupe-use-directives": "error",
"svelte/no-dynamic-slot-name": "error",
"svelte/no-export-load-in-svelte-module-in-kit-pages": "error",
"svelte/no-inner-declarations": "error",
"svelte/no-not-function-handler": "error",
"svelte/no-object-in-text-mustaches": "error",
"svelte/no-reactive-functions": "error",
"svelte/no-reactive-literals": "error",
"svelte/no-shorthand-style-property-overrides": "error",
"svelte/no-unknown-style-directive-property": "error",
"svelte/no-unused-svelte-ignore": "error",
"svelte/no-useless-mustaches": "error",
"svelte/require-store-callbacks-use-set-param": "error",
"svelte/system": "error",
"svelte/valid-each-key": "error",
"unused-imports/no-unused-vars": ["error", {
args: "after-used",
argsIgnorePattern: "^_",
vars: "all",
varsIgnorePattern: "^(_|\\$\\$Props$|\\$\\$Events$|\\$\\$Slots$)"
}],
...overrides
}
}];
}
//#endregion
//#region src/configs/tailwindcss.ts
async function tailwindcss(options = {}) {
const { overrides } = options;
await ensurePackages(["eslint-plugin-tailwindcss"]);
const pluginTailwindcss = await interopDefault(import("eslint-plugin-tailwindcss"));
return [{
name: "coderwyd/tailwindcss/rules",
plugins: { tailwindcss: pluginTailwindcss },
rules: {
"tailwindcss/classnames-order": "warn",
"tailwindcss/enforces-negative-arbitrary-values": "warn",
"tailwindcss/enforces-shorthand": "warn",
"tailwindcss/migration-from-tailwind-2": "warn",
"tailwindcss/no-arbitrary-value": "off",
"tailwindcss/no-contradicting-classname": "warn",
"tailwindcss/no-custom-classname": "off",
"tailwindcss/no-unnecessary-arbitrary-value": "warn",
...overrides
}
}];
}
//#endregion
//#region src/configs/test.ts
let _pluginTest;
async function test(options = {}) {
const { files = GLOB_TESTS, isInEditor: isInEditor$1 = false, overrides = {} } = options;
const [pluginVitest, pluginNoOnlyTests] = await Promise.all([interopDefault(import("@vitest/eslint-plugin")), interopDefault(import("eslint-plugin-no-only-tests"))]);
_pluginTest = _pluginTest || {
...pluginVitest,
rules: {
...pluginVitest.rules,
...pluginNoOnlyTests.rules
}
};
return [{
name: "coderwyd/test/setup",
plugins: { test: _pluginTest }
}, {
files,
name: "coderwyd/test/rules",
rules: {
"node/prefer-global/process": "off",
"test/consistent-test-it": ["error", {
fn: "it",
withinDescribe: "it"
}],
"test/no-identical-title": "error",
"test/no-import-node-test": "error",
"test/no-only-tests": isInEditor$1 ? "off" : "error",
"test/prefer-hooks-in-order": "error",
"test/prefer-lowercase-title": "error",
"ts/explicit-function-return-type": "off",
...overrides
}
}];
}
//#endregion
//#region src/configs/typescript.ts
async function typescript(options = {}) {
const { componentExts = [], overrides = {}, overridesTypeAware = {}, parserOptions = {} } = options;
const files = options.files ?? [
GLOB_TS,
GLOB_TSX,
...componentExts.map((ext) => `**/*.${ext}`)
];
const filesTypeAware = options.filesTypeAware ?? [GLOB_TS, GLOB_TSX];
const ignoresTypeAware = options.ignoresTypeAware ?? [`${GLOB_MARKDOWN}/**`, GLOB_ASTRO_TS];
const tsconfigPath = options.tsconfigPath;
const isTypeAware = !!tsconfigPath;
const typeAwareRules = {
"dot-notation": "off",
"no-implied-eval": "off",
"ts/await-thenable": "error",
"ts/dot-notation": ["error", { allowKeywords: true }],
"ts/no-floating-promises": "error",
"ts/no-for-in-array": "error",
"ts/no-implied-eval": "error",
"ts/no-misused-promises": "error",
"ts/no-unnecessary-type-assertion": "error",
"ts/no-unsafe-argument": "error",
"ts/no-unsafe-assignment": "error",
"ts/no-unsafe-call": "error",
"ts/no-unsafe-member-access": "error",
"ts/no-unsafe-return": "error",
"ts/promise-function-async": "error",
"ts/restrict-plus-operands": "error",
"ts/restrict-template-expressions": "error",
"ts/return-await": "error",
"ts/strict-boolean-expressions": "error",
"ts/switch-exhaustiveness-check": "error",
"ts/unbound-method": "error"
};
const [pluginTs, parserTs] = await Promise.all([interopDefault(import("@typescript-eslint/eslint-plugin")), interopDefault(import("@typescript-eslint/parser"))]);
function makeParser(typeAware, files$1, ignores$1) {
return {
files: files$1,
...ignores$1 ? { ignores: ignores$1 } : {},
languageOptions: {
parser: parserTs,
parserOptions: {
extraFileExtensions: componentExts.map((ext) => `.${ext}`),
sourceType: "module",
...typeAware ? {
projectService: {
allowDefaultProject: ["./*.js"],
defaultProject: tsconfigPath
},
tsconfigRootDir: process.cwd()
} : {},
...parserOptions
}
},
name: `coderwyd/typescript/${typeAware ? "type-aware-parser" : "parser"}`
};
}
return [
{
name: "coderwyd/typescript/setup",
plugins: {
antfu: pluginAntfu,
ts: pluginTs
}
},
...isTypeAware ? [makeParser(false, files), makeParser(true, filesTypeAware, ignoresTypeAware)] : [makeParser(false, files)],
{
files,
name: "coderwyd/typescript/rules",
rules: {
...renameRules(pluginTs.configs["eslint-recommended"].overrides[0].rules, { "@typescript-eslint": "ts" }),
...renameRules(pluginTs.configs.strict.rules, { "@typescript-eslint": "ts" }),
"no-dupe-class-members": "off",
"no-redeclare": "off",
"no-use-before-define": "off",
"no-useless-constructor": "off",
"ts/ban-ts-comment": ["error", { "ts-expect-error": "allow-with-description" }],
"ts/consistent-type-definitions": ["error", "interface"],
"ts/consistent-type-imports": ["error", {
disallowTypeAnnotations: false,
fixStyle: "separate-type-imports",
prefer: "type-imports"
}],
"ts/method-signature-style": ["error", "property"],
"ts/no-dupe-class-members": "error",
"ts/no-dynamic-delete": "off",
"ts/no-empty-object-type": ["error", {
allowInterfaces: "with-single-extends",
allowObjectTypes: "never",
allowWithName: "Props$"
}],
"ts/no-explicit-any": "off",
"ts/no-extraneous-class": "off",
"ts/no-import-type-side-effects": "error",
"ts/no-invalid-void-type": "off",
"ts/no-non-null-assertion": "off",
"ts/no-redeclare": ["error", { builtinGlobals: false }],
"ts/no-require-imports": "error",
"ts/no-unused-expressions": ["error", {
allowShortCircuit: true,
allowTaggedTemplates: true,
allowTernary: true
}],
"ts/no-unused-vars": "off",
"ts/no-use-before-define": ["error", {
classes: false,
functions: false,
variables: true
}],
"ts/no-useless-constructor": "off",
"ts/no-wrapper-object-types": "error",
"ts/triple-slash-reference": "off",
"ts/unified-signatures": "off",
...overrides
}
},
...isTypeAware ? [{
files: filesTypeAware,
ignores: ignoresTypeAware,
name: "coderwyd/typescript/rules-type-aware",
rules: {
...typeAwareRules,
...overridesTypeAware
}
}] : []
];
}
//#endregion
//#region src/configs/unicorn.ts
function unicorn(options = {}) {
const { overrides = {} } = options;
return [{
name: "coderwyd/unicorn/rules",
plugins: { unicorn: pluginUnicorn },
rules: {
"unicorn/catch-error-name": "error",
"unicorn/consistent-empty-array-spread": "error",
"unicorn/consistent-existence-index-check": "error",
"unicorn/custom-error-definition": "error",
"unicorn/error-message": "error",
"unicorn/escape-case": "error",
"unicorn/new-for-builtins": "error",
"unicorn/no-array-method-this-argument": "error",
"unicorn/no-await-in-promise-methods": "error",
"unicorn/no-console-spaces": "error",
"unicorn/no-for-loop": "error",
"unicorn/no-hex-escape": "error",
"unicorn/no-instanceof-builtins": "error",
"unicorn/no-invalid-remove-event-listener": "error",
"unicorn/no-lonely-if": "error",
"unicorn/no-negation-in-equality-check": "error",
"unicorn/no-new-array": "error",
"unicorn/no-new-buffer": "error",
"unicorn/no-single-promise-in-promise-methods": "error",
"unicorn/no-static-only-class": "error",
"unicorn/no-unnecessary-array-flat-depth": "error",
"unicorn/no-unnecessary-array-splice-count": "error",
"unicorn/no-unnecessary-await": "error",
"unicorn/no-unnecessary-slice-end": "error",
"unicorn/no-zero-fractions": "error",
"unicorn/prefer-add-event-listener": "error",
"unicorn/prefer-array-find": "error",
"unicorn/prefer-array-flat-map": "error",
"unicorn/prefer-array-index-of": "error",
"unicorn/prefer-array-some": "error",
"unicorn/prefer-at": "error",
"unicorn/prefer-blob-reading-methods": "error",
"unicorn/prefer-date-now": "error",
"unicorn/prefer-dom-node-append": "error",
"unicorn/prefer-dom-node-dataset": "error",
"unicorn/prefer-dom-node-remove": "error",
"unicorn/prefer-dom-node-text-content": "error",
"unicorn/prefer-includes": "error",
"unicorn/prefer-keyboard-event-key": "error",
"unicorn/prefer-math-min-max": "error",
"unicorn/prefer-math-trunc": "error",
"unicorn/prefer-modern-dom-apis": "error",
"unicorn/prefer-modern-math-apis": "error",
"unicorn/prefer-negative-index": "error",
"unicorn/prefer-node-protocol": "error",
"unicorn/prefer-number-properties": "error",
"unicorn/prefer-optional-catch-binding": "error",
"unicorn/prefer-prototype-methods": "error",
"unicorn/prefer-query-selector": "error",
"unicorn/prefer-reflect-apply": "error",
"unicorn/prefer-single-call": "error",
"unicorn/prefer-string-replace-all": "error",
"unicorn/prefer-string-slice": "error",
"unicorn/prefer-string-starts-ends-with": "error",
"unicorn/prefer-string-trim-start-end": "error",
"unicorn/prefer-type-error": "error",
"unicorn/throw-new-error": "error",
...overrides
}
}];
}
//#endregion
//#region src/configs/unocss.ts
async function unocss(options = {}) {
const { attributify = true, strict = false } = options;
await ensurePackages(["@unocss/eslint-plugin"]);
const [pluginUnoCSS] = await Promise.all([interopDefault(import("@unocss/eslint-plugin"))]);
return [{
name: "coderwyd/unocss/rules",
plugins: { unocss: pluginUnoCSS },
rules: {
"unocss/order": "warn",
...attributify ? { "unocss/order-attributify": "warn" } : {},
...strict ? { "unocss/blocklist": "error" } : {}
}
}];
}
//#endregion
//#region src/configs/vue.ts
async function vue(options = {}) {
const { files = [GLOB_VUE], overrides = {} } = options;
const [pluginVue, parserVue] = await Promise.all([interopDefault(import("eslint-plugin-vue")), interopDefault(import("vue-eslint-parser"))]);
const isVue3 = getVueVersion() === 3;
const configKeys = isVue3 ? [
"essential",
"strongly-recommended",
"recommended"
] : [
"vue2-essential",
"vue2-strongly-recommended",
"vue2-recommended"
];
const vueRules = configKeys.reduce((preRules, key) => {
const config = pluginVue.configs[key];
return {
...preRules,
...config.rules
};
}, {});
return [{
files,
languageOptions: {
parser: parserVue,
parserOptions: {
ecmaFeatures: { jsx: true },
extraFileExtensions: [".vue"],
parser: options.typescript ? await interopDefault(import("@typescript-eslint/parser")) : null,
sourceType: "module"
}
},
name: "coderwyd/vue/rules",
plugins: { vue: pluginVue },
processor: pluginVue.processors[".vue"],
rules: {
...pluginVue.configs.base.rules,
...vueRules,
"antfu/no-top-level-await": "off",
"node/prefer-global/process": "off",
"ts/explicit-function-return-type": "off",
"vue/block-order": ["error", { order: isVue3 ? [
"script",
"template",
"style"
] : [
"template",
"script",
"style"
] }],
"vue/component-name-in-template-casing": ["error", "PascalCase"],
"vue/component-options-name-casing": ["error", "PascalCase"],
"vue/component-tags-order": "off",
"vue/custom-event-name-casing": ["error", "camelCase"],
"vue/define-macros-order": ["error", { order: [
"defineOptions",
"defineProps",
"defineEmits",
"defineSlots"
] }],
"vue/eqeqeq": ["error", "smart"],
"vue/html-self-closing": ["error", {
html: {
component: "always",
normal: "always",
void: "any"
},
math: "always",
svg: "always"
}],
"vue/max-attributes-per-line": "off",
"vue/multi-word-component-names": "off",
"vue/no-constant-condition": "warn",
"vue/no-duplicate-attr-inheritance": "warn",
"vue/no-empty-pattern": "error",
"vue/no-extra-parens": ["error", "functions"],
"vue/no-irregular-whitespace": "error",
"vue/no-loss-of-precision": "error",
"vue/no-required-prop-with-default": "warn",
"vue/no-restricted-syntax": [
"error",
"DebuggerStatement",
"LabeledStatement",
"WithStatement"
],
"vue/no-restricted-v-bind": ["error", "/^v-/"],
"vue/no-setup-props-reactivity-loss": "off",
"vue/no-sparse-arrays": "error",
"vue/no-unsupported-features": "warn",
"vue/no-unused-emit-declarations": "warn",
"vue/no-unused-refs": "error",
"vue/no-use-v-else-with-v-for": "error",
"vue/no-useless-mustaches": "warn",
"vue/no-useless-v-bind": "error",
"vue/no-v-html": "off",
"vue/no-v-text": "warn",
"vue/object-shorthand": [
"error",
"always",
{
avoidQuotes: true,
ignoreConstructors: false
}
],
"vue/padding-line-between-blocks": ["error", "always"],
"vue/prefer-define-options": "warn",
"vue/prefer-separate-static-class": "error",
"vue/prefer-template": "error",
"vue/prop-name-casing": ["error", "camelCase"],
"vue/require-default-prop": "off",
"vue/require-macro-variable-name": ["warn", {
defineEmits: "emit",
defineProps: "props",
defineSlots: "slots",
useAttrs: "attrs",
useSlots: "slots"
}],
"vue/require-prop-types": "off",
"vue/space-infix-ops": "error",
"vue/space-unary-ops": ["error", {
nonwords: false,
words: true
}],
"vue/valid-define-options": "warn",
...overrides
}
}];
}
//#endregion
//#region src/configs/yaml.ts
async function yaml(options = {}) {
const { files = [GLOB_YAML], overrides = {} } = options;
const [pluginYaml, parserYaml] = await Promise.all([interopDefault(import("eslint-plugin-yml")), interopDefault(import("yaml-eslint-parser"))]);
return [
{
name: "coderwyd/yaml/setup",
plugins: { yaml: pluginYaml }
},
{
files,
languageOptions: { parser: parserYaml },
name: "coderwyd/yaml/rules",
rules: {
"yaml/block-mapping": "error",
"yaml/block-sequence": "error",
"yaml/no-empty-key": "error",
"yaml/no-empty-sequence-entry": "error",
"yaml/no-irregular-whitespace": "error",
"yaml/plain-scalar": "error",
"yaml/vue-custom-block/no-parsing-error": "error",
...overrides
}
},
{
files: ["pnpm-workspace.yaml"],
name: "coderwyd/yaml/pnpm-workspace",
rules: { "yaml/sort-keys": [
"error",
{
order: [
"packages",
"overrides",
"patchedDependencies",
"hoistPattern",
"catalog",
"catalogs",
"allowedDeprecatedVersions",
"allowNonAppliedPatches",
"configDependencies",
"ignoredBuiltDependencies",
"ignoredOptionalDependencies",
"neverBuiltDependencies",
"onlyBuiltDependencies",
"onlyBuiltDependenciesFile",
"packageExtensions",
"peerDependencyRules",
"supportedArchitectures"
],
pathPattern: "^$"
},
{
order: { type: "asc" },
pathPattern: ".*"
}
] }
}
];
}
//#endregion
//#region src/index.ts
const flatConfigProps = [
"name",
"languageOptions",
"linterOptions",
"processor",
"plugins",
"rules",
"settings"
];
const defaultPluginRenaming = {
"@eslint-react": "react",
"@eslint-react/dom": "react-dom",
"@eslint-react/hooks-extra": "react-hooks-extra",
"@eslint-react/naming-convention": "react-naming-convention",
"@typescript-eslint": "ts",
"import-lite": "import",
n: "node",
vitest: "test",
yml: "yaml"
};
/**
* Construct an array of ESLint flat config items.
*
* @param {OptionsConfig & TypedFlatConfigItem} options
* The options for generating the ESLint configurations.
* @param {Awaitable<TypedFlatConfigItem | TypedFlatConfigItem[] | Linter.Config[]>[]} userConfigs
* The user configurations to be merged with the generated configurations.
* @returns {Promise<TypedFlatConfigItem[]>}
* The merged ESLint configurations.
*/
async function defineConfig(options = {}, ...userConfigs) {
const { autoRenamePlugins = true, componentExts = [], gitignore: enableGitignore = true, react: enableReact = false, regexp: enableRegexp = true, svelte: enableSvelte = false, tailwindcss: enableTailwindCSS = false, typescript: enableTypeScript = isUsingTypeScript, unocss: enableUnoCSS = false, vue: enableVue = isUsingVue } = options;
let isInEditor$1 = options.isInEditor;
if (isInEditor$1 == null) {
isInEditor$1 = isInEditorEnv();
if (isInEditor$1) console.log("[@coderwyd/eslint-config] Detected running in editor, some rules are disabled.");
}
const configs$1 = [];
if (enableGitignore) if (typeof enableGitignore !== "boolean") configs$1.push(interopDefault(import("eslint-config-flat-gitignore")).then((r) => [r({
...enableGitignore,
name: "coderwyd/gitignore"
})]));
else configs$1.push(interopDefault(import("eslint-config-flat-gitignore")).then((r) => [r({
name: "coderwyd/gitignore",
strict: false
})]));
const typescriptOptions = resolveSubOptions(options, "typescript");
const tsconfigPath = "tsconfigPath" in typescriptOptions ? typescriptOptions.tsconfigPath : void 0;
configs$1.push(ignores(options.ignores), javascript({
isInEditor: isInEditor$1,
overrides: getOverrides(options, "javascript")
}), comments(), node(), jsdoc(), imports(), unicorn(), command(), deMorgan(), perfectionist());
if (enableVue) componentExts.push("vue");
if (enableTypeScript) configs$1.push(typescript({
...typescriptOptions,
componentExts,
overrides: getOverrides(options, "typescript")
}));
if (enableRegexp) configs$1.push(regexp(typeof enableRegexp === "boolean" ? {} : enableRegexp));
if (options.test ?? true) configs$1.push(test({
isInEditor: isInEditor$1,
overrides: