@wagtail/eslint-config-wagtail
v0.6.0
Published
Shareable ESLint config for Wagtail
Readme
@wagtail/eslint-config-wagtail
Shareable ESLint config for Wagtail.
The package provides Wagtail's ESLint configuration as an extensible shared config using the ESLint flat config format.
Usage
This package uses ESLint v9+ flat config format. Install it with its peer dependencies:
npm install --save-dev @wagtail/eslint-config-wagtail@latestThen, import and use the config in your eslint.config.js file:
import wagtailConfig from '@wagtail/eslint-config-wagtail';
export default [
...wagtailConfig,
// Your custom config here
];Code style
This ESLint config includes recommended rules from:
- ESLint rules
- eslint-plugin-import
- eslint-plugin-react
- eslint-plugin-react-hooks
- eslint-plugin-jsx-a11y
- eslint-config-prettier
With some Wagtail-specific customizations:
- Use soft-tabs with a two space indent. Spaces are the only way to guarantee code renders the same in any person's environment.
- We accept
snake_casein object properties, such asajaxResponse.page_title, however camelCase or UPPER_CASE should be used everywhere else.
Contribution Guidelines
Install
- Required Node
- We recommend using nvm
- Clone the project on to your computer
- Run
nvm installto ensure you have the correct Node version - Run
npm installto install project dependencies - Ensure your editor is set up to use editorconfig, Prettier and Eslint
Development
- Run
nvm useto set Node to the correct version - Run tests via
npm run test - Run linting via
npm run lint - Run preflight checks before commiting final code via
npm run preflight - Note: When working with the rule set, only modify the
index.jsfile, not theeslint.config.jsfile as it is for the linting of this project only
Rules
| Rule | Severity | Config |
| ------------------------------------------------------------------ | -------- | ------------------------------------------------------------------------- |
| @stylistic/lines-between-class-members | error | "always", {"exceptAfterOverload":true,"exceptAfterSingleLine":true} |
| @stylistic/spaced-comment | error | see Config |
| @typescript-eslint/adjacent-overload-signatures | error | |
| @typescript-eslint/array-type | error | {"default":"array-simple"} |
| @typescript-eslint/ban-ts-comment | error | {"minimumDescriptionLength":10} |
| @typescript-eslint/ban-tslint-comment | error | |
| @typescript-eslint/class-literal-property-style | error | |
| @typescript-eslint/consistent-generic-constructors | error | |
| @typescript-eslint/consistent-type-assertions | error | |
| @typescript-eslint/consistent-type-definitions | error | |
| @typescript-eslint/no-array-constructor | error | |
| @typescript-eslint/no-confusing-non-null-assertion | error | |
| @typescript-eslint/no-duplicate-enum-values | error | |
| @typescript-eslint/no-dynamic-delete | error | |
| @typescript-eslint/no-empty-function | error | {"allow":["arrowFunctions","functions","methods"]} |
| @typescript-eslint/no-empty-object-type | error | |
| @typescript-eslint/no-explicit-any | error | |
| @typescript-eslint/no-extra-non-null-assertion | error | |
| @typescript-eslint/no-extraneous-class | error | {"allowConstructorOnly":true} |
| @typescript-eslint/no-inferrable-types | error | |
| @typescript-eslint/no-invalid-void-type | error | |
| @typescript-eslint/no-misused-new | error | |
| @typescript-eslint/no-namespace | error | |
| @typescript-eslint/no-non-null-asserted-nullish-coalescing | error | |
| @typescript-eslint/no-non-null-asserted-optional-chain | error | |
| @typescript-eslint/no-require-imports | error | |
| @typescript-eslint/no-shadow | error | |
| @typescript-eslint/no-this-alias | error | |
| @typescript-eslint/no-unnecessary-type-constraint | error | |
| @typescript-eslint/no-unsafe-declaration-merging | error | |
| @typescript-eslint/no-unsafe-function-type | error | |
| @typescript-eslint/no-unused-expressions | error | see Config |
| @typescript-eslint/no-unused-vars | error | see Config |
| @typescript-eslint/no-use-before-define | error | |
| @typescript-eslint/no-useless-constructor | error | |
| @typescript-eslint/no-wrapper-object-types | error | |
| @typescript-eslint/prefer-as-const | error | |
| @typescript-eslint/prefer-for-of | error | |
| @typescript-eslint/prefer-function-type | error | |
| @typescript-eslint/prefer-literal-enum-member | error | |
| @typescript-eslint/prefer-namespace-keyword | error | |
| @typescript-eslint/triple-slash-reference | error | |
| @typescript-eslint/unified-signatures | error | |
| array-callback-return | error | {"allowImplicit":true,"checkForEach":false,"allowVoid":false} |
| arrow-body-style | error | "as-needed" |
| block-scoped-var | error | |
| camelcase | error | see Config |
| consistent-return | error | {"treatUndefinedAsUnspecified":false} |
| constructor-super | error | |
| default-case | error | {"commentPattern":"^no default$"} |
| default-case-last | error | |
| default-param-last | error | |
| dot-notation | error | {"allowKeywords":true,"allowPattern":""} |
| eqeqeq | error | "always", {"null":"ignore"} |
| for-direction | error | |
| func-names | warn | "always", {} |
| getter-return | error | {"allowImplicit":false} |
| grouped-accessor-pairs | error | "anyOrder", {"enforceForTSTypes":false} |
| guard-for-in | error | |
| id-length | warn | see Config |
| import-x/default | error | |
| import-x/export | error | |
| import-x/first | error | |
| import-x/namespace | error | |
| import-x/newline-after-import | error | |
| import-x/no-absolute-path | error | |
| import-x/no-amd | error | |
| import-x/no-cycle | error | |
| import-x/no-duplicates | error | |
| import-x/no-dynamic-require | error | |
| import-x/no-extraneous-dependencies | error | see Config |
| import-x/no-import-module-exports | error | {"exceptions":[]} |
| import-x/no-mutable-exports | error | |
| import-x/no-named-as-default | error | |
| import-x/no-named-default | error | |
| import-x/no-relative-packages | error | |
| import-x/no-self-import | error | |
| import-x/no-unresolved | error | {"commonjs":true,"caseSensitive":true} |
| import-x/no-useless-path-segments | error | {"commonjs":true} |
| import-x/no-webpack-loader-syntax | error | |
| import-x/order | error | see Config |
| jsx-a11y/alt-text | error | |
| jsx-a11y/anchor-has-content | error | |
| jsx-a11y/anchor-is-valid | error | |
| jsx-a11y/aria-activedescendant-has-tabindex | error | |
| jsx-a11y/aria-props | error | |
| jsx-a11y/aria-proptypes | error | |
| jsx-a11y/aria-role | error | |
| jsx-a11y/aria-unsupported-elements | error | |
| jsx-a11y/autocomplete-valid | error | |
| jsx-a11y/click-events-have-key-events | error | |
| jsx-a11y/control-has-associated-label | error | see Config |
| jsx-a11y/heading-has-content | error | |
| jsx-a11y/html-has-lang | error | |
| jsx-a11y/iframe-has-title | error | |
| jsx-a11y/img-redundant-alt | error | |
| jsx-a11y/interactive-supports-focus | error | see Config |
| jsx-a11y/label-has-associated-control | error | {"assert":"either","depth":25} |
| jsx-a11y/lang | error | |
| jsx-a11y/media-has-caption | error | |
| jsx-a11y/mouse-events-have-key-events | error | |
| jsx-a11y/no-access-key | error | |
| jsx-a11y/no-autofocus | error | |
| jsx-a11y/no-distracting-elements | error | |
| jsx-a11y/no-interactive-element-to-noninteractive-role | error | {"tr":["none","presentation"],"canvas":["img"]} |
| jsx-a11y/no-noninteractive-element-interactions | error | see Config |
| jsx-a11y/no-noninteractive-element-to-interactive-role | error | see Config |
| jsx-a11y/no-noninteractive-tabindex | error | {"tags":[],"roles":["tabpanel"],"allowExpressionValues":true} |
| jsx-a11y/no-redundant-roles | error | |
| jsx-a11y/no-static-element-interactions | error | see Config |
| jsx-a11y/role-has-required-aria-props | error | |
| jsx-a11y/role-supports-aria-props | error | |
| jsx-a11y/scope | error | |
| jsx-a11y/tabindex-no-positive | error | |
| new-cap | error | see Config |
| no-alert | warn | |
| no-async-promise-executor | error | |
| no-await-in-loop | error | |
| no-bitwise | error | {"allow":[],"int32Hint":false} |
| no-caller | error | |
| no-case-declarations | error | |
| no-class-assign | error | |
| no-compare-neg-zero | error | |
| no-cond-assign | error | "always" |
| no-console | warn | {} |
| no-const-assign | error | |
| no-constant-binary-expression | error | |
| no-constant-condition | error | {"checkLoops":"allExceptWhileTrue"} |
| no-constructor-return | error | |
| no-continue | error | |
| no-control-regex | error | |
| no-debugger | error | |
| no-delete-var | error | |
| no-dupe-args | error | |
| no-dupe-class-members | error | |
| no-dupe-else-if | error | |
| no-dupe-keys | error | |
| no-duplicate-case | error | |
| no-else-return | error | {"allowElseIf":false} |
| no-empty | error | {"allowEmptyCatch":false} |
| no-empty-character-class | error | |
| no-empty-pattern | error | {"allowObjectPatternsAsParameters":false} |
| no-empty-static-block | error | |
| no-eval | error | {"allowIndirect":false} |
| no-ex-assign | error | |
| no-extend-native | error | {"exceptions":[]} |
| no-extra-bind | error | |
| no-extra-boolean-cast | error | {} |
| no-extra-label | error | |
| no-fallthrough | error | {"allowEmptyCase":false,"reportUnusedFallthroughComment":false} |
| no-func-assign | error | |
| no-global-assign | error | {"exceptions":[]} |
| no-implied-eval | error | |
| no-import-assign | error | |
| no-inner-declarations | error | "functions", {"blockScopedFunctions":"allow"} |
| no-invalid-regexp | error | {} |
| no-irregular-whitespace | error | see Config |
| no-iterator | error | |
| no-label-var | error | |
| no-labels | error | {"allowLoop":false,"allowSwitch":false} |
| no-lone-blocks | error | |
| no-lonely-if | error | |
| no-loop-func | error | |
| no-loss-of-precision | error | |
| no-misleading-character-class | error | {"allowEscape":false} |
| no-multi-assign | error | {"ignoreNonDeclaration":false} |
| [no-multi-str][166] | error | |
| [no-nested-ternary][167] | error | |
| [no-new][168] | warn | |
| [no-new-func][169] | error | |
| [no-new-native-nonconstructor][170] | error | |
| [no-new-wrappers][171] | error | |
| [no-nonoctal-decimal-escape][172] | error | |
| [no-obj-calls][173] | error | |
| [no-object-constructor][174] | error | |
| [no-octal][175] | error | |
| [no-octal-escape][176] | error | |
| [no-param-reassign][177] | error | |
| [no-plusplus][178] | error | {"allowForLoopAfterthoughts":false} |
| [no-promise-executor-return][179] | error | {"allowVoid":false} |
| [no-proto][180] | error | |
| [no-prototype-builtins][181] | error | |
| [no-redeclare][182] | error | {"builtinGlobals":true} |
| [no-regex-spaces][183] | error | |
| [no-restricted-exports][184] | error | {"restrictedNamedExports":["default","then"]} |
| [no-restricted-globals][185] | error | see Config |
| [no-restricted-properties][186] | error | see Config |
| [no-restricted-syntax][187] | error | see Config |
| [no-return-assign][188] | error | "always" |
| [no-script-url][189] | error | |
| [no-self-assign][190] | error | {"props":true} |
| [no-self-compare][191] | error | |
| [no-sequences][192] | error | {"allowInParentheses":true} |
| [no-setter-return][193] | error | |
| [no-shadow-restricted-names][194] | error | {"reportGlobalThis":false} |
| [no-sparse-arrays][195] | error | |
| [no-template-curly-in-string][196] | error | |
| [no-this-before-super][197] | error | |
| [no-undef][198] | error | {"typeof":false} |
| [no-undef-init][199] | error | |
| [no-underscore-dangle][200] | error | see Config |
| [no-unneeded-ternary][201] | error | {"defaultAssignment":false} |
| [no-unreachable][202] | error | |
| [no-unreachable-loop][203] | error | {"ignore":[]} |
| [no-unsafe-finally][204] | error | |
| [no-unsafe-negation][205] | error | {"enforceForOrderingRelations":false} |
| [no-unsafe-optional-chaining][206] | error | {"disallowArithmeticOperators":true} |
| [no-unused-labels][207] | error | |
| [no-unused-private-class-members][208] | error | |
| [no-useless-backreference][209] | error | |
| [no-useless-catch][210] | error | |
| [no-useless-computed-key][211] | error | {"enforceForClassMembers":true} |
| [no-useless-concat][212] | error | |
| [no-useless-escape][213] | error | {"allowRegexCharacters":[]} |
| [no-useless-rename][214] | error | {"ignoreDestructuring":false,"ignoreImport":false,"ignoreExport":false} |
| [no-useless-return][215] | error | |
| [no-void][216] | error | {"allowAsStatement":false} |
| [no-with][217] | error | |
| [object-shorthand][218] | error | "methods" |
| [one-var][219] | error | "never" |
| [operator-assignment][220] | error | "always" |
| [prefer-arrow-callback][221] | error | {"allowNamedFunctions":false,"allowUnboundThis":true} |
| [prefer-const][222] | error | {"destructuring":"any","ignoreReadBeforeAssign":true} |
| [prefer-exponentiation-operator][223] | error | |
| [prefer-numeric-literals][224] | error | |
| [prefer-object-spread][225] | error | |
| [prefer-promise-reject-errors][226] | error | {"allowEmptyReject":true} |
| [prefer-regex-literals][227] | error | {"disallowRedundantWrapping":true} |
| [prefer-rest-params][228] | error | |
| [prefer-spread][229] | error | |
| [radix][230] | error | "always" |
| [react-hooks/component-hook-factories][231] | error | |
| [react-hooks/config][232] | error | |
| [react-hooks/error-boundaries][233] | error | |
| [react-hooks/exhaustive-deps][234] | error | |
| [react-hooks/gating][235] | error | |
| [react-hooks/globals][236] | error | |
| [react-hooks/immutability][237] | error | |
| [react-hooks/incompatible-library][238] | warn | |
| [react-hooks/preserve-manual-memoization][239] | error | |
| [react-hooks/purity][240] | error | |
| [react-hooks/refs][241] | error | |
| [react-hooks/rules-of-hooks][242] | error | |
| [react-hooks/set-state-in-effect][243] | error | |
| [react-hooks/set-state-in-render][244] | error | |
| [react-hooks/static-components][245] | error | |
| [react-hooks/unsupported-syntax][246] | warn | |
| [react-hooks/use-memo][247] | error | |
| [react/button-has-type][248] | error | {"reset":false,"button":true,"submit":true} |
| [react/default-props-match-prop-types][249] | error | {"allowRequiredDefaults":false} |
| [react/destructuring-assignment][250] | error | |
| [react/display-name][251] | error | |
| [react/forbid-foreign-prop-types][252] | warn | {"allowInPropTypes":true} |
| [react/forbid-prop-types][253] | error | {"checkContextTypes":true,"checkChildContextTypes":true} |
| [react/function-component-definition][254] | error | see Config |
| [react/hook-use-state][255] | error | |
| [react/jsx-curly-brace-presence][256] | error | {"props":"never","children":"never"} |
| [react/jsx-filename-extension][257] | error | |
| [react/jsx-fragments][258] | error | |
| [react/jsx-key][259] | error | |
| [react/jsx-no-comment-textnodes][260] | error | |
| [react/jsx-no-constructed-context-values][261] | error | |
| [react/jsx-no-duplicate-props][262] | error | {"ignoreCase":true} |
| [react/jsx-no-script-url][263] | error | |
| [react/jsx-no-target-blank][264] | error | |
| [react/jsx-no-undef][265] | error | |
| [react/jsx-no-useless-fragment][266] | error | |
| [react/jsx-pascal-case][267] | error | {"allowAllCaps":true} |
| [react/jsx-props-no-spreading][268] | error | {"explicitSpread":"ignore"} |
| [react/jsx-uses-react][269] | error | |
| [react/jsx-uses-vars][270] | error | |
| [react/no-access-state-in-setstate][271] | error | |
| [react/no-array-index-key][272] | error | |
| [react/no-arrow-function-lifecycle][273] | error | |
| [react/no-children-prop][274] | error | |
| [react/no-danger][275] | warn | |
| [react/no-danger-with-children][276] | error | |
| [react/no-deprecated][277] | error | |
| [react/no-did-update-set-state][278] | error | |
| [react/no-direct-mutation-state][279] | error | |
| [react/no-find-dom-node][280] | error | |
| [react/no-invalid-html-attribute][281] | error | |
| [react/no-is-mounted][282] | error | |
| [react/no-namespace][283] | error | |
| [react/no-redundant-should-component-update][284] | error | |
| [react/no-render-return-value][285] | error | |
| [react/no-string-refs][286] | error | |
| [react/no-this-in-sfc][287] | error | |
| [react/no-typos][288] | error | |
| [react/no-unescaped-entities][289] | error | |
| [react/no-unknown-property][290] | error | |
| [react/no-unstable-nested-components][291] | error | |
| [react/no-unused-class-component-methods][292] | error | |
| [react/no-unused-prop-types][293] | error | |
| [react/no-unused-state][294] | error | |
| [react/no-will-update-set-state][295] | error | |
| [react/prefer-exact-props][296] | error | |
| [react/prefer-stateless-function][297] | error | {"ignorePureComponents":true} |
| [react/react-in-jsx-scope][298] | error | |
| [react/require-default-props][299] | error | {"forbidDefaultForRequired":true} |
| [react/require-render-return][300] | error | |
| [react/self-closing-comp][301] | error | |
| [react/state-in-constructor][302] | error | |
| [react/static-property-placement][303] | error | "property assignment" |
| [react/style-prop-object][304] | error | |
| [react/void-dom-elements-no-children][305] | error | |
| [require-yield][306] | error | |
| [strict][307] | error | "never" |
| [symbol-description][308] | error | |
| [unicode-bom][309] | error | "never" |
| [use-isnan][310] | error | {"enforceForIndexOf":false,"enforceForSwitchCase":true} |
| [valid-typeof][311] | error | {"requireStringLiterals":true} |
| [vars-on-top][312] | error | |
| [yoda][313] | error | "never", {"exceptRange":false,"onlyEquality":false} |
