nonebot2/.eslintrc.js

404 lines
13 KiB
JavaScript
Raw Normal View History

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,
},
},
],
};