@refinist/eslint-config
Version:
ESLint config for @refinist.
324 lines (315 loc) • 9.52 kB
JavaScript
import { GLOB_ALL_SRC, GLOB_ASTRO_TS, GLOB_CSS, GLOB_DIST, GLOB_EXCLUDE, GLOB_HTML, GLOB_JS, GLOB_JSON, GLOB_JSON5, GLOB_JSONC, GLOB_JSX, GLOB_LESS, GLOB_LOCKFILE, GLOB_MARKDOWN, GLOB_NODE_MODULES, GLOB_SCSS, GLOB_SRC, GLOB_SRC_EXT, GLOB_STYLE, GLOB_TS, GLOB_TSX, GLOB_VUE, GLOB_YAML } from "./globs-BnHr61hi.js";
import tseslint from "typescript-eslint";
import pluginVue from "eslint-plugin-vue";
import pluginPrettier from "eslint-plugin-prettier";
import pluginIgnore from "eslint-config-flat-gitignore";
import pluginPrettierRecommended from "eslint-plugin-prettier/recommended";
import pluginStylistic from "@stylistic/eslint-plugin";
import configJs from "@eslint/js";
import * as parserVue from "vue-eslint-parser";
import globals from "globals";
import { isPackageExists } from "local-pkg";
//#region src/configs/ignores.ts
const ignores = () => [{
ignores: GLOB_EXCLUDE,
name: "refinist/global-ignores"
}, {
...pluginIgnore({ strict: false }),
name: "refinist/gitignore"
}];
//#endregion
//#region src/configs/javascript.ts
const restrictedSyntaxJs = [
"ForInStatement",
"LabeledStatement",
"WithStatement"
];
const javascript = () => [{
...configJs.configs.recommended,
name: "refinist/js/recommended"
}, {
languageOptions: {
globals: {
...globals.browser,
...globals.es2021,
...globals.node
},
parserOptions: {
ecmaFeatures: { jsx: true },
sourceType: "module"
},
sourceType: "module"
},
name: "refinist/js",
rules: {
"array-callback-return": "error",
"block-scoped-var": "error",
"dot-notation": "warn",
eqeqeq: ["error", "smart"],
"no-alert": "warn",
"no-console": ["warn", { allow: [
"warn",
"error",
"info",
"clear"
] }],
"no-debugger": "warn",
"no-duplicate-imports": "error",
"no-empty": ["error", { allowEmptyCatch: true }],
"no-fallthrough": ["warn", { commentPattern: String.raw`break[\s\w]*omitted` }],
"no-inner-declarations": "error",
"no-lonely-if": "error",
"no-multi-str": "error",
"no-restricted-syntax": ["error", ...restrictedSyntaxJs],
"no-unused-expressions": ["error", {
allowShortCircuit: true,
allowTaggedTemplates: true,
allowTernary: true
}],
"no-unused-vars": "off",
"no-void": "error",
"object-shorthand": [
"error",
"always",
{
avoidQuotes: true,
ignoreConstructors: false
}
],
"prefer-arrow-callback": ["error", {
allowNamedFunctions: false,
allowUnboundThis: true
}],
"prefer-const": ["warn", {
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",
"unicode-bom": ["error", "never"],
"use-isnan": ["error", {
enforceForIndexOf: true,
enforceForSwitchCase: true
}],
"valid-typeof": ["error", { requireStringLiterals: true }],
"vars-on-top": "error"
}
}];
//#endregion
//#region src/configs/prettier.ts
const rules = { ...pluginPrettierRecommended.rules };
delete rules["vue/html-self-closing"];
const prettier = () => [{
name: "refinist/prettier",
plugins: { prettier: pluginPrettier },
rules: {
...rules,
"prettier/prettier": "warn"
}
}];
//#endregion
//#region src/configs/stylistic.ts
const stylistic = () => [{
name: "refinist/stylistic",
plugins: { "@stylistic": pluginStylistic },
rules: { "@stylistic/spaced-comment": [
"error",
"always",
{ block: { balanced: true } }
] }
}];
//#endregion
//#region src/configs/typescript.ts
const typescriptCore = ({ typeAware = false } = {}) => tseslint.config({
extends: [...typeAware ? tseslint.configs.recommendedTypeChecked : tseslint.configs.recommended],
...typeAware ? { languageOptions: { parserOptions: {
projectService: true,
tsconfigRootDir: process.cwd()
} } } : void 0,
files: [GLOB_TS, GLOB_TSX],
name: "refinist/typescript",
rules: {
"@typescript-eslint/ban-ts-comment": "off",
"@typescript-eslint/consistent-type-assertions": ["error", {
assertionStyle: "as",
objectLiteralTypeAssertions: "allow-as-parameter"
}],
"@typescript-eslint/consistent-type-imports": ["error", {
disallowTypeAnnotations: false,
fixStyle: "inline-type-imports"
}],
"@typescript-eslint/method-signature-style": ["error", "property"],
"@typescript-eslint/no-empty-object-type": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-import-type-side-effects": "error",
"@typescript-eslint/no-non-null-assertion": "off",
"@typescript-eslint/no-redeclare": "error",
"@typescript-eslint/no-unsafe-function-type": "off",
"@typescript-eslint/no-unused-expressions": ["error", {
allowShortCircuit: true,
allowTaggedTemplates: true,
allowTernary: true
}],
"@typescript-eslint/no-unused-vars": "off",
"@typescript-eslint/prefer-as-const": "warn",
"@typescript-eslint/prefer-literal-enum-member": ["error", { allowBitwiseExpressions: true }],
"no-restricted-syntax": [
"error",
...restrictedSyntaxJs,
"TSEnumDeclaration[const=true]"
]
}
});
const typescript = ({ typeAware = false } = {}) => [
...typescriptCore({ typeAware }),
{
files: ["**/*.d.ts"],
name: "refinist/typescript/dts-rules",
rules: {
"eslint-comments/no-unlimited-disable": "off",
"import/no-duplicates": "off",
"no-restricted-syntax": "off",
"unused-imports/no-unused-vars": "off"
}
},
{
files: [GLOB_JS, "**/*.cjs"],
name: "refinist/typescript/cjs-rules",
rules: { "@typescript-eslint/no-require-imports": "off" }
}
];
//#endregion
//#region src/configs/vue.ts
const reactivityTransform = () => [{
languageOptions: { globals: {
$: "readonly",
$$: "readonly",
$computed: "readonly",
$customRef: "readonly",
$ref: "readonly",
$shallowRef: "readonly",
$toRef: "readonly"
} },
name: "refinist/vue/reactivity-transform",
plugins: { vue: pluginVue },
rules: { "vue/no-setup-props-reactivity-loss": "off" }
}];
const vueTs = typescriptCore().filter((config) => config.name !== "typescript-eslint/base").map((config) => {
return {
...config,
files: [GLOB_VUE],
name: `refinist/vue/${config.name?.replace("refinist/", "") || "anonymous"}`
};
});
const recommendedRules = pluginVue.configs["flat/recommended"].map((c) => c.rules).reduce((acc, c) => ({
...acc,
...c
}), {});
const vue = () => [
...vueTs,
{
files: [GLOB_VUE],
languageOptions: {
parser: parserVue,
parserOptions: {
ecmaFeatures: { jsx: true },
extraFileExtensions: [".vue"],
parser: tseslint.parser,
sourceType: "module"
}
},
name: "refinist/vue",
plugins: {
"@typescript-eslint": tseslint.plugin,
vue: pluginVue
},
processor: pluginVue.processors[".vue"],
rules: {
...recommendedRules,
"vue/block-order": ["error", { order: [
"script",
"template",
"style"
] }],
"vue/custom-event-name-casing": ["error", "camelCase"],
"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-empty-pattern": "error",
"vue/no-loss-of-precision": "error",
"vue/no-unused-refs": "error",
"vue/no-useless-v-bind": "error",
"vue/no-v-html": "off",
"vue/object-shorthand": [
"error",
"always",
{
avoidQuotes: true,
ignoreConstructors: false
}
],
"vue/one-component-per-file": "off",
"vue/padding-line-between-blocks": ["error", "always"],
"vue/prefer-template": "error",
"vue/require-default-prop": "off",
"vue/require-prop-types": "off"
}
},
...reactivityTransform()
];
//#endregion
//#region src/env.ts
const hasTypeScript = () => isPackageExists("typescript");
const hasVue = () => [
"vue",
"nuxt",
"vitepress",
"@slidev/cli"
].some((i) => isPackageExists(i));
const hasReact = () => [
"react",
"react-dom",
"react-router",
"@remix-run/node",
"@remix-run/react",
"@remix-run/serve",
"@remix-run/dev",
"@react-router/node",
"@react-router/react",
"@react-router/serve",
"@react-router/dev",
"next"
].some((i) => isPackageExists(i));
//#endregion
//#region src/presets.ts
const presetBasic = ({ typeAware = false } = {}) => [
...ignores(),
...javascript(),
...stylistic(),
...typescript({ typeAware })
];
function refinist(options = {}, ...userConfigs) {
const { vue: enableVue = hasVue(), prettier: enablePrettier = true } = options;
const _userConfigs = [...userConfigs.flat()];
const hasReact$1 = _userConfigs.some((_) => _.name?.includes("refinist/react"));
const configs = [...presetBasic({ typeAware: hasReact$1 })];
if (enableVue) configs.push(...vue());
if (enablePrettier) configs.push(...prettier());
return [...configs, ..._userConfigs];
}
//#endregion
export { GLOB_ALL_SRC, GLOB_ASTRO_TS, GLOB_CSS, GLOB_DIST, GLOB_EXCLUDE, GLOB_HTML, GLOB_JS, GLOB_JSON, GLOB_JSON5, GLOB_JSONC, GLOB_JSX, GLOB_LESS, GLOB_LOCKFILE, GLOB_MARKDOWN, GLOB_NODE_MODULES, GLOB_SCSS, GLOB_SRC, GLOB_SRC_EXT, GLOB_STYLE, GLOB_TS, GLOB_TSX, GLOB_VUE, GLOB_YAML, configJs, hasReact, hasTypeScript, hasVue, ignores, javascript, parserVue, pluginIgnore, pluginPrettier, pluginPrettierRecommended, pluginStylistic, pluginVue, prettier, reactivityTransform, refinist, restrictedSyntaxJs, stylistic, tseslint, typescript, typescriptCore, vue };