Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Import config from extension; group by plugin #255

Merged
merged 14 commits into from
Apr 8, 2024
222 changes: 16 additions & 206 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,74 +1,39 @@
"use strict";

const xoTypeScriptConfig = require("eslint-config-xo-typescript");

function customize(config, rule, customizer) {
const [type, ruleConfig] = config.rules[rule];
// Spread shallow-clones the object
const newRuleConfig = { ...ruleConfig };
customizer(newRuleConfig);
return {
[rule]: [type, newRuleConfig],
};
}

const config = {
env: {
browser: true,
},
settings: {
"import/resolver": {
typescript: {},
},
"import/ignore": [
"react-select", // For some reason it points to a flow JS file
],
react: {
version: "detect",
},
},
ignorePatterns: [".idea", "dist", "**/__mocks__/**"],
plugins: ["filenames", "jsx-a11y"],
plugins: ["filenames", "jsx-a11y", "@shopify"],
extends: [
"./xo-plugins-config.js",
"xo", // Full config: https://github.com/xojs/eslint-config-xo/blob/main/index.js
"xo-typescript", // Full config: https://github.com/xojs/eslint-config-xo-typescript/blob/main/index.js
"prettier", // Disable style-related rules
"plugin:react/recommended",
"plugin:react-hooks/recommended",
"./vendors/xo-plugins-config.js", // Vendored from xojs/xo package, it must be here as a baseline

"plugin:security/recommended-legacy",
"plugin:unicorn/recommended", // Full config: https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/configs/recommended.js
"plugin:jsx-a11y/recommended", // Full config https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/src/index.js#L55

// Once some plugin configuration becomes "too large" it's extracted to its own file
"./plugins/jsdoc.js",
"./plugins/react.js",
"./plugins/import.js",
"./plugins/typescript.js",
"./plugins/unicorn.js",

// Must be last. Disable style-related rules
"prettier",

/**************************************************************
* Only add test rules and plugins to the "./tests.js" config *
**************************************************************/
],
rules: {
// Enable extra rules

"import/dynamic-import-chunkname": [
"error",
{
webpackChunknameFormat: "[a-zA-Z0-57-9-/_\\[\\].]+",
},
],
"@shopify/react-hooks-strict-return": "error",
"@shopify/prefer-module-scope-constants": "error",

"no-restricted-imports": ["error", require("./no-restricted-imports")],

"no-restricted-syntax": ["error", ...require("./no-restricted-syntax")],

// Avoid imports with side effects
"import/no-unassigned-import": [
"error",
{
allow: [
"**/*.css",
"**/*.scss",
"**/reportUncaughtErrors",
"regenerator-runtime/runtime", // Automatic registration
],
},
],
"no-mixed-operators": [
"error",
{
Expand All @@ -85,176 +50,21 @@ const config = {
},
],

// TODO: Drop/replace `allowExpressions` after https://github.com/jsx-eslint/eslint-plugin-react/issues/2584
// https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-no-useless-fragment.md#allowexpressions
"react/jsx-no-useless-fragment": ["error", { allowExpressions: true }],

// Customize some rules
quotes: ["error", "double", { avoidEscape: true }], // Matches Prettier, but also replaces backticks

...customize(
xoTypeScriptConfig,
"@typescript-eslint/ban-types",
(config) => {
delete config.types.null;
}
),

// Reason: https://github.com/pixiebrix/pixiebrix-extension/pull/7703
"@typescript-eslint/restrict-template-expressions": [
"error",
{ allowNever: true, allowNumber: true },
],

// We want to have a default case to check for `never`
"@typescript-eslint/switch-exhaustiveness-check": [
"error",
{
allowDefaultCaseForExhaustiveSwitch: true,
requireDefaultForNonUnion: true,
},
],

"@typescript-eslint/no-non-null-assertion": "error",
"@typescript-eslint/no-explicit-any": [
"error",
{
fixToUnknown: true,
ignoreRestArgs: true,
},
],

"unicorn/prefer-export-from": [
"error",
{
ignoreUsedVariables: true,
},
],

"unicorn/prevent-abbreviations": [
"error",
{
replacements: {
acc: false,
arg: false,
args: false,
db: false,
dev: false,
doc: false,
docs: false,
env: false,
err: false,
ev: false,
evt: false,
ext: false,
exts: false,
$el: {
$elements: true,
},
$elt: {
$elements: true,
},
$element: {
$elements: true,
},
fn: false,
func: {
fn: true,
function: false,
},
i: false,
j: false,
mod: false,
num: false,
obj: false,
param: false,
params: false,
prev: false,
prod: false,
prop: false,
props: false,
ref: false,
refs: false,
str: false,
var: false,
vars: false,
},
ignore: ["semVer", "SemVer"],
},
],
"unicorn/filename-case": [
"error",
{
cases: {
camelCase: true,
pascalCase: true,
},
},
],
eqeqeq: ["error", "always", { null: "never" }],

// Disable recommended rules
"no-eq-null": "off", // `eqeqeq` covers it: https://github.com/pixiebrix/pixiebrix-extension/pull/887#pullrequestreview-711873690
"unicorn/no-null": "off", // We don't do that here
"react/prop-types": "off", // We don't do that here
"no-warning-comments": "off", // Only useful if there aren't hundreds of other real warnings
"security/detect-non-literal-fs-filename": "off", // 100% false positives, we never use the `fs` module
"unicorn/no-nested-ternary": "off", // Sometimes it conflicts with Prettier
"unicorn/prefer-set-has": "off", // Not always worth the extra code
"unicorn/prefer-top-level-await": "off", // No advantage in browsers
"import/no-extraneous-dependencies": "off", // Not worth it
"@typescript-eslint/triple-slash-reference": "off", // No alternative sometimes
"@typescript-eslint/consistent-type-definitions": "off", // `type` cannot be used to extend globals
"@typescript-eslint/no-dynamic-delete": "off", // Already covered by `security/detect-object-injection`

// Rules that duplicate TypeScript features
"import/default": "off",
"import/named": "off",
"import/no-named-as-default": "off", // Too slow
"import/no-named-as-default-member": "off", // It's common to use `React.memo` instead of just `memo`
"@typescript-eslint/consistent-type-assertions": "off", // Our current typing has too many `unknowns` for this to be applicable https://github.com/typescript-eslint/typescript-eslint/issues/4462

// Disable rule until we find a better config https://github.com/pixiebrix/eslint-config-pixiebrix/issues/5
"@typescript-eslint/naming-convention": "off",

// Requires strictNullChecks
"@typescript-eslint/prefer-nullish-coalescing": "off",

// Maybe later, opinionated
"unicorn/prefer-ternary": "off",
"@typescript-eslint/member-ordering": "off",
"@typescript-eslint/no-empty-function": "off",

"import/order": "off",
"import/extensions": "off",
"import/no-mutable-exports": "off",
"node/file-extension-in-import": "off",
"node/prefer-global/process": "off", // `process.env` is required by webpack
"node/prefer-global/buffer": "off",

"@typescript-eslint/no-use-before-define": [
"error",
{
// Disabling functions -- functions are hoisted and not a risk
// https://eslint.org/docs/latest/rules/no-use-before-define#options
functions: false,
// https://typescript-eslint.io/rules/no-use-before-define/#options
ignoreTypeReferences: false,
},
],
},
overrides: [
{
// JS files shouldn't have TypeScript rules, but it's bothersome to separate them properly
files: ["**/*.js"],
rules: {
"@typescript-eslint/no-unsafe-argument": "off",
"@typescript-eslint/no-unsafe-assignment": "off",
"@typescript-eslint/no-unsafe-call": "off",
"@typescript-eslint/no-unsafe-member-access": "off",
"@typescript-eslint/no-unsafe-return": "off",
},
},
{
files: ["**/*.tsx", "**/use*.ts"],
excludedFiles: ["*.test.tsx", "*.stories.tsx"],
Expand Down
6 changes: 6 additions & 0 deletions no-restricted-syntax.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ module.exports = [
selector:
"ImportDeclaration[source.value=classnames] ImportDefaultSpecifier[local.name!=/cx/]",
},
{
message:
"Instead of `<div onClick/>`, use <UnstyledButton/> (`button` element) or <ClickableElement/> (accessible `div` element)",
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also: updated description to suggest UnstyledButton as well (which is always preferred)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is also very Extension-specific.

Copy link
Collaborator Author

@fregante fregante Apr 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The a11y plugin rules also apply on the app, so these 2 components help fix them correctly:

https://github.com/pixiebrix/pixiebrix-app/pull/5067/files#diff-a215210d34dc5b245c69ef42b4f3831552c05b2f10e1f80d110688a1df8e6ee0

The only relation to the extension is that it lives in the @/components/* folder. The app can use them freely, the other repos can copy-pasted them I suppose.

selector:
"JSXOpeningElement[name.name='div'][attributes.0.name.name='onClick']",
},

// NOTE: If you add more rules, add the tests to no-restricted-syntax.test.ts
];
Loading