nonebot2/.eslintrc.js
2025-03-09 21:18:32 +08:00

404 lines
13 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const OFF = 0;
const WARNING = 1;
const ERROR = 2;
// Prevent importing lodash, usually for browser bundle size reasons
const LodashImportPatterns = ["lodash", "lodash.**", "lodash/**"];
module.exports = {
root: true,
env: {
browser: true,
commonjs: true,
node: true,
},
parser: "@typescript-eslint/parser",
parserOptions: {},
globals: {
JSX: true,
},
extends: [
"eslint:recommended",
"plugin:react-hooks/recommended",
"airbnb",
"plugin:@typescript-eslint/recommended",
// 'plugin:@typescript-eslint/recommended-requiring-type-checking',
// 'plugin:@typescript-eslint/strict',
"plugin:regexp/recommended",
"prettier",
"plugin:@docusaurus/all",
],
settings: {
"import/resolver": {
node: {
extensions: [".js", ".jsx", ".ts", ".tsx"],
},
},
},
reportUnusedDisableDirectives: true,
plugins: ["react-hooks", "@typescript-eslint", "regexp", "@docusaurus"],
rules: {
"react/jsx-uses-react": OFF, // JSX runtime: automatic
"react/react-in-jsx-scope": OFF, // JSX runtime: automatic
"array-callback-return": WARNING,
camelcase: WARNING,
"class-methods-use-this": OFF, // It's a way of allowing private variables.
curly: [WARNING, "all"],
"global-require": WARNING,
"lines-between-class-members": OFF,
"max-classes-per-file": OFF,
"max-len": [
WARNING,
{
code: Infinity, // Code width is already enforced by Prettier
tabWidth: 2,
comments: 80,
ignoreUrls: true,
ignorePattern: "(eslint-disable|@)",
},
],
"arrow-body-style": OFF,
"no-await-in-loop": OFF,
"no-case-declarations": WARNING,
"no-console": OFF,
"no-constant-binary-expression": ERROR,
"no-continue": OFF,
"no-control-regex": WARNING,
"no-else-return": OFF,
"no-empty": [WARNING, { allowEmptyCatch: true }],
"no-lonely-if": WARNING,
"no-nested-ternary": WARNING,
"no-param-reassign": [WARNING, { props: false }],
"no-prototype-builtins": WARNING,
"no-restricted-exports": OFF,
"no-restricted-properties": [
ERROR,
.../** @type {[string, string][]} */ ([
// TODO: TS doesn't make Boolean a narrowing function yet,
// so filter(Boolean) is problematic type-wise
// ['compact', 'Array#filter(Boolean)'],
["concat", "Array#concat"],
["drop", "Array#slice(n)"],
["dropRight", "Array#slice(0, -n)"],
["fill", "Array#fill"],
["filter", "Array#filter"],
["find", "Array#find"],
["findIndex", "Array#findIndex"],
["first", "foo[0]"],
["flatten", "Array#flat"],
["flattenDeep", "Array#flat(Infinity)"],
["flatMap", "Array#flatMap"],
["fromPairs", "Object.fromEntries"],
["head", "foo[0]"],
["indexOf", "Array#indexOf"],
["initial", "Array#slice(0, -1)"],
["join", "Array#join"],
// Unfortunately there's no great alternative to _.last yet
// Candidates: foo.slice(-1)[0]; foo[foo.length - 1]
// Array#at is ES2022; could replace _.nth as well
// ['last'],
["map", "Array#map"],
["reduce", "Array#reduce"],
["reverse", "Array#reverse"],
["slice", "Array#slice"],
["take", "Array#slice(0, n)"],
["takeRight", "Array#slice(-n)"],
["tail", "Array#slice(1)"],
]).map(([property, alternative]) => ({
object: "_",
property,
message: `Use ${alternative} instead.`,
})),
...[
"readdirSync",
"readFileSync",
"statSync",
"lstatSync",
"existsSync",
"pathExistsSync",
"realpathSync",
"mkdirSync",
"mkdirpSync",
"mkdirsSync",
"writeFileSync",
"writeJsonSync",
"outputFileSync",
"outputJsonSync",
"moveSync",
"copySync",
"copyFileSync",
"ensureFileSync",
"ensureDirSync",
"ensureLinkSync",
"ensureSymlinkSync",
"unlinkSync",
"removeSync",
"emptyDirSync",
].map((property) => ({
object: "fs",
property,
message: "Do not use sync fs methods.",
})),
],
"no-restricted-syntax": [
WARNING,
// Copied from airbnb, removed for...of statement, added export all
{
selector: "ForInStatement",
message:
"for..in loops iterate over the entire prototype chain, which is virtually never what you want. Use Object.{keys,values,entries}, and iterate over the resulting array.",
},
{
selector: "LabeledStatement",
message:
"Labels are a form of GOTO; using them makes code confusing and hard to maintain and understand.",
},
{
selector: "WithStatement",
message:
"`with` is disallowed in strict mode because it makes code impossible to predict and optimize.",
},
{
selector: "ExportAllDeclaration",
message:
"Export all does't work well if imported in ESM due to how they are transpiled, and they can also lead to unexpected exposure of internal methods.",
},
// TODO make an internal plugin to ensure this
// {
// selector:
// @ 'ExportDefaultDeclaration > Identifier, ExportNamedDeclaration[source=null] > ExportSpecifier',
// message: 'Export in one statement'
// },
...["path", "fs-extra", "webpack", "lodash"].map((m) => ({
selector: `ImportDeclaration[importKind=value]:has(Literal[value=${m}]) > ImportSpecifier[importKind=value]`,
message:
"Default-import this, both for readability and interoperability with ESM",
})),
],
"no-template-curly-in-string": WARNING,
"no-unused-expressions": [
WARNING,
{ allowTaggedTemplates: true, allowShortCircuit: true },
],
"no-useless-escape": WARNING,
"no-void": [ERROR, { allowAsStatement: true }],
"prefer-destructuring": WARNING,
"prefer-named-capture-group": WARNING,
"prefer-template": WARNING,
yoda: WARNING,
"import/extensions": OFF,
// This rule doesn't yet support resolving .js imports when the actual file
// is .ts. Plus it's not all that useful when our code is fully TS-covered.
"import/no-unresolved": [
OFF,
{
// Ignore certain webpack aliases because they can't be resolved
ignore: [
"^@theme",
"^@docusaurus",
"^@generated",
"^@site",
"^@testing-utils",
],
},
],
"import/order": [
WARNING,
{
groups: [
"builtin",
"external",
"internal",
["parent", "sibling", "index"],
"type",
],
"newlines-between": "always",
pathGroups: [
// always put css import to the last, ref:
// https://github.com/import-js/eslint-plugin-import/issues/1239
{
pattern: "*.+(css|sass|less|scss|pcss|styl)",
group: "unknown",
patternOptions: { matchBase: true },
position: "after",
},
{ pattern: "react", group: "builtin", position: "before" },
{ pattern: "react-dom", group: "builtin", position: "before" },
{ pattern: "react-dom/**", group: "builtin", position: "before" },
{ pattern: "stream", group: "builtin", position: "before" },
{ pattern: "fs-extra", group: "builtin" },
{ pattern: "lodash", group: "external", position: "before" },
{ pattern: "clsx", group: "external", position: "before" },
// 'Bit weird to not use the `import/internal-regex` option, but this
// way, we can make `import type { Props } from "@theme/*"` appear
// before `import styles from "styles.module.css"`, which is what we
// always did. This should be removable once we stop using ambient
// module declarations for theme aliases.
{ pattern: "@theme/**", group: "internal" },
{ pattern: "@site/**", group: "internal" },
{ pattern: "@theme-init/**", group: "internal" },
{ pattern: "@theme-original/**", group: "internal" },
{ pattern: "@/components/**", group: "internal" },
{ pattern: "@/libs/**", group: "internal" },
{ pattern: "@/types/**", group: "type" },
],
pathGroupsExcludedImportTypes: [],
// example: let `import './nprogress.css';` after importing others
// in `packages/docusaurus-theme-classic/src/nprogress.ts`
// see more: https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/order.md#warnonunassignedimports-truefalse
warnOnUnassignedImports: true,
},
],
"import/prefer-default-export": OFF,
"jsx-a11y/click-events-have-key-events": WARNING,
"jsx-a11y/no-noninteractive-element-interactions": WARNING,
"jsx-a11y/html-has-lang": OFF,
"react-hooks/rules-of-hooks": ERROR,
"react-hooks/exhaustive-deps": ERROR,
// Sometimes we do need the props as a whole, e.g. when spreading
"react/destructuring-assignment": OFF,
"react/function-component-definition": [
WARNING,
{
namedComponents: "function-declaration",
unnamedComponents: "arrow-function",
},
],
"react/jsx-filename-extension": OFF,
"react/jsx-key": [ERROR, { checkFragmentShorthand: true }],
"react/jsx-no-useless-fragment": [ERROR, { allowExpressions: true }],
"react/jsx-props-no-spreading": OFF,
"react/no-array-index-key": OFF, // We build a static site, and nearly all components don't change.
"react/no-unstable-nested-components": [WARNING, { allowAsProps: true }],
"react/prefer-stateless-function": WARNING,
"react/prop-types": OFF,
"react/require-default-props": [
ERROR,
{ ignoreFunctionalComponents: true },
],
"@typescript-eslint/consistent-type-definitions": OFF,
"@typescript-eslint/require-await": OFF,
"@typescript-eslint/ban-ts-comment": [
ERROR,
{ "ts-expect-error": "allow-with-description" },
],
"@typescript-eslint/consistent-indexed-object-style": OFF,
"@typescript-eslint/consistent-type-imports": [
WARNING,
{ disallowTypeAnnotations: false },
],
"@typescript-eslint/explicit-module-boundary-types": WARNING,
"@typescript-eslint/method-signature-style": ERROR,
"@typescript-eslint/no-empty-function": OFF,
"@typescript-eslint/no-empty-interface": [
ERROR,
{
allowSingleExtends: true,
},
],
"@typescript-eslint/no-inferrable-types": OFF,
"@typescript-eslint/no-namespace": [WARNING, { allowDeclarations: true }],
"no-use-before-define": OFF,
"@typescript-eslint/no-use-before-define": [
ERROR,
{ functions: false, classes: false, variables: true },
],
"@typescript-eslint/no-non-null-assertion": OFF,
"no-redeclare": OFF,
"@typescript-eslint/no-redeclare": ERROR,
"no-shadow": OFF,
"@typescript-eslint/no-shadow": ERROR,
"no-unused-vars": OFF,
// We don't provide any escape hatches for this rule. Rest siblings and
// function placeholder params are always ignored, and any other unused
// locals must be justified with a disable comment.
"@typescript-eslint/no-unused-vars": [ERROR, { ignoreRestSiblings: true }],
"@typescript-eslint/prefer-optional-chain": ERROR,
"@docusaurus/no-html-links": ERROR,
"@docusaurus/prefer-docusaurus-heading": ERROR,
"@docusaurus/no-untranslated-text": [
WARNING,
{
ignoredStrings: [
"·",
"-",
"—",
"×",
"", // zwj: ​
"@",
"WebContainers",
"Twitter",
"GitHub",
"Dev.to",
"1.x",
],
},
],
},
overrides: [
{
files: ["packages/*/src/theme/**/*.{js,ts,tsx}"],
excludedFiles: "*.test.{js,ts,tsx}",
rules: {
"no-restricted-imports": [
"error",
{
patterns: LodashImportPatterns.concat(
// Prevents relative imports between React theme components
[
"../**",
"./**",
// Allows relative styles module import with consistent filename
"!./styles.module.css",
// Allows relative tailwind css import with consistent filename
"!./styles.css",
]
),
},
],
},
},
{
files: ["packages/*/src/theme/**/*.{js,ts,tsx}"],
rules: {
"import/no-named-export": ERROR,
},
},
{
files: ["*.d.ts"],
rules: {
"import/no-duplicates": OFF,
},
},
{
files: ["*.{ts,tsx}"],
rules: {
"no-undef": OFF,
"import/no-import-module-exports": OFF,
},
},
{
files: ["*.{js,mjs,cjs}"],
rules: {
// Make JS code directly runnable in Node.
"@typescript-eslint/no-var-requires": OFF,
"@typescript-eslint/explicit-module-boundary-types": OFF,
},
},
{
// Internal files where extraneous deps don't matter much at long as
// they run
files: ["website/**"],
rules: {
"import/no-extraneous-dependencies": OFF,
},
},
],
};