@jimmy.codes/eslint-config
Version:
A simple, modern ESLint config that covers most use cases.
142 lines (141 loc) • 5.37 kB
JavaScript
import { GLOB_JSX, GLOB_TSX } from "./globs.mjs";
import { l as hasTypescript, r as hasNext, u as hasVite } from "./has-dependency-Bzazc-3p.mjs";
import { n as extractOptions, t as unwrapDefault } from "./interop-default-CAdBatTA.mjs";
import { t as rebrand } from "./rebrand-h7fk1Gdd.mjs";
import { t as upwarn } from "./upwarn-CSmqblU7.mjs";
import globals from "globals";
//#region src/rules/react.ts
const nextAllowedExportNames = [
"experimental_ppr",
"dynamic",
"dynamicParams",
"revalidate",
"fetchCache",
"runtime",
"preferredRegion",
"maxDuration",
"metadata",
"generateMetadata",
"viewport",
"generateViewport",
"generateImageMetadata",
"generateSitemaps",
"generateStaticParams",
"alt",
"size",
"contentType"
];
const reactRules = async (options) => {
const [{ configs: reactConfigs }, { configs: jsxA11yConfigs }, { configs: reactDomConfigs }, { configs: reactWebApiConfigs }, { configs: reactNamingConventionConfigs }, { configs: reactRscConfigs }] = await Promise.all([
unwrapDefault(import("eslint-plugin-react-x")),
unwrapDefault(import("eslint-plugin-jsx-a11y-x")),
unwrapDefault(import("eslint-plugin-react-dom")),
unwrapDefault(import("eslint-plugin-react-web-api")),
unwrapDefault(import("eslint-plugin-react-naming-convention")),
unwrapDefault(import("eslint-plugin-react-rsc"))
]);
const isUsingNextjs = hasNext();
const isUsingVite = hasVite();
const isUsingTypesScript = hasTypescript();
const reactPluginRules = isUsingTypesScript ? reactConfigs["strict-type-checked"].rules : reactConfigs.strict.rules;
const reactDomPluginRules = isUsingTypesScript ? {
...reactDomConfigs.strict.rules,
"react-dom/no-string-style-prop": "off",
"react-dom/no-unknown-property": "off"
} : {
...reactDomConfigs.strict.rules,
"react-dom/no-string-style-prop": "error",
"react-dom/no-unknown-property": ["error", { requireDataLowercase: true }]
};
return {
...rebrand(jsxA11yConfigs.recommended.rules, "jsx-a11y-x", "jsx-a11y"),
...upwarn(reactPluginRules),
...upwarn(reactDomPluginRules),
...upwarn(reactWebApiConfigs.recommended.rules),
...upwarn(reactNamingConventionConfigs.recommended.rules),
...upwarn(reactRscConfigs.recommended.rules),
"react-compiler/react-compiler": "error",
"react-hooks/component-hook-factories": "error",
"react-hooks/error-boundaries": "error",
"react-hooks/exhaustive-deps": "error",
"react-hooks/globals": "error",
"react-hooks/immutability": "error",
"react-hooks/incompatible-library": "error",
"react-hooks/preserve-manual-memoization": "error",
"react-hooks/purity": "error",
"react-hooks/refs": "error",
"react-hooks/rules-of-hooks": "error",
"react-hooks/set-state-in-effect": "error",
"react-hooks/set-state-in-render": "error",
"react-hooks/static-components": "error",
"react-hooks/unsupported-syntax": "error",
"react-hooks/use-memo": "error",
"react-hooks/void-use-memo": "error",
"react-refresh/only-export-components": ["warn", {
allowConstantExport: isUsingVite,
allowExportNames: isUsingNextjs ? nextAllowedExportNames : []
}],
"react-x/error-boundaries": "off",
"react-x/exhaustive-deps": "off",
"react-x/globals": "off",
"react-x/immutability": "off",
"react-x/no-duplicate-key": "error",
"react-x/no-implicit-children": "error",
"react-x/no-implicit-key": "error",
"react-x/no-implicit-ref": "error",
"react-x/no-missing-component-display-name": "off",
"react-x/no-missing-context-display-name": "error",
"react-x/no-unused-state": "off",
"react-x/purity": "off",
"react-x/refs": "off",
"react-x/rules-of-hooks": "off",
"react-x/set-state-in-effect": "off",
"react-x/set-state-in-render": "off",
"react-x/static-components": "off",
"react-x/unsupported-syntax": "off",
"react-x/use-memo": "off",
...options?.overrides
};
};
//#endregion
//#region src/configs/react.ts
async function reactConfig(options) {
const extractedOptions = extractOptions(options);
const [reactPlugin, jsxA11yPlugin, reactHooksPlugin, reactRefreshPlugin, reactCompilerPlugin, reactDomPlugin, reactWebApiPlugin, reactNamingConventionPlugin, reactRscPlugin] = await Promise.all([
unwrapDefault(import("eslint-plugin-react-x")),
unwrapDefault(import("eslint-plugin-jsx-a11y-x")),
unwrapDefault(import("eslint-plugin-react-hooks")),
unwrapDefault(import("eslint-plugin-react-refresh")),
unwrapDefault(import("eslint-plugin-react-compiler")),
unwrapDefault(import("eslint-plugin-react-dom")),
unwrapDefault(import("eslint-plugin-react-web-api")),
unwrapDefault(import("eslint-plugin-react-naming-convention")),
unwrapDefault(import("eslint-plugin-react-rsc"))
]);
return [{
files: [GLOB_JSX, GLOB_TSX],
languageOptions: {
globals: { ...globals.browser },
parserOptions: {
ecmaFeatures: { jsx: true },
jsxPragma: null
}
},
name: "jimmy.codes/react",
plugins: {
"jsx-a11y": jsxA11yPlugin,
"react-compiler": reactCompilerPlugin,
"react-dom": reactDomPlugin,
"react-hooks": reactHooksPlugin,
"react-naming-convention": reactNamingConventionPlugin,
"react-refresh": reactRefreshPlugin,
"react-rsc": reactRscPlugin,
"react-web-api": reactWebApiPlugin,
"react-x": reactPlugin
},
rules: await reactRules(extractedOptions),
settings: { react: { version: "detect" } }
}];
}
//#endregion
export { reactConfig as default };