Git Product home page Git Product logo

ljosberinn / eslint-config-galex Goto Github PK

View Code? Open in Web Editor NEW
175.0 4.0 9.0 9.28 MB

hopefully the last eslint config you'll ever need - customizable & modern best practices for JS, TS, Node, React, Remix, Next, Jest, testing-library & storybook

Home Page: https://www.npmjs.com/package/eslint-config-galex

License: MIT License

JavaScript 6.90% CSS 3.93% TypeScript 88.97% Dockerfile 0.21%
eslint eslint-config react typescript esnext nextjs jest testing-library best-practices rulesets

eslint-config-galex's Introduction

eslint-config-galex

npm NPM Total Downloads NPM Test Coverage

yarn add -D eslint-config-galex eslint

npm install --save-dev eslint-config-galex eslint

Compatibility

Usage with create-react-app

As of January 2021 / due to CRA v5, currently no additional steps are required! πŸŽ‰

Beginning with eslint-config-galex v4.2.2 or newer, until this disclaimer is removed you need to install the following dependencies additionally:

  • "eslint-plugin-jest": "27.2.0"
npm i --save-dev [email protected]

yarn add -D [email protected]

Beginning with eslint-config-galex v4.5.0 or newer, until this disclaimer is removed you need to install the following dependencies additionally:

  • "eslint-plugin-react": "7.32.2"
  • "eslint-plugin-jsx-a11y": "6.7.1"
  • "eslint-plugin-import": "2.27.5"
npm i --save-dev [email protected]
npm i --save-dev [email protected]
npm i --save-dev [email protected]

yarn add -D [email protected]
yarn add -D [email protected]
yarn add -D [email protected]
Usage with Next.js

In your next.config.js, I heavily recommend setting eslint.ignoreDuringBuilds to true. Otherwise, you'll have to install eslint-config-next separately and won't benefit of this config and your customization on top.

Usage with Remix Run

No additional setup is required! πŸŽ‰

Setup

Basic

You profit automatically of automatic dependency and feature detection. Due to the nature of ESLint configs however this approach is significantly harder to customize.

// .eslintrc.js
module.exports = {
  extends: 'galex',
};

Advanced

This showcases the required setup to begin with customizing your config on an advanced level. Please check out the Examples section below for more details.

// .eslintrc.js
const { createConfig } = require('eslint-config-galex/dist/createConfig');

module.exports = createConfig();

Features

Incremental Adoption
// .eslintrc.js
const { createConfig } = require('eslint-config-galex/dist/createConfig');

module.exports = createConfig({
  incrementalAdoption: true,
});
Standalone Generation

By default, eslint-config-galex reads your package.json as well as, if present, tsconfig.json to determine feature availability. On weaker machines however, this turned out to be a performance bottleneck. Realistically, neither your dependencies nor your tsconfig change that often.

To generate a static config based on your current dependencies & tsconfig, use:

node node_modules/eslint-config-galex/dist/generateStandalone

which will create a .eslintrc.json in your root directory.

How do I pass settings for createConfig to standalone generation?

Simple! Have a eslint-galex-settings.json file in your root directory and it will be picked up.

An example would look like this:

// eslint-galex-settings.json (remove this comment as its invalid json)
{
  "incrementalAdoption": true
}

Important: to keep this in sync with your dependencies, I recommend adding a postinstall step to your scripts:

// package.json
"scripts": {
  // other scripts
  "postinstall": "node node_modules/eslint-config-galex/dist/generateStandalone"
}

Remember to re-run this command whenever you make feature-availability-relevant changes to your tsconfig.json as well, such as module, target or lib.

History: prior to v4, eslint-config-galex shipped with internal caching. Sadly, this prove to be both a maintenance overhead as well as not as useful as it initially promised to be for various reasons (e.g. VSCode ESLint apparently restarting the process when switching files which cachebusted due to a different process).

Starting with a blank slate

You like all the features eslint-config-galex ships with but you heavily disagree with many rule settings?

Say no more. Simply pass { blankSlate: true } to createConfig and you still benefit from automatic dependency detection, the general override setup based on file patterns, but every rule will be set to off.

This way, you can customize it entirely to your likings without having to create n overrides for rules and or rulesets.

Migrating a codebase to TypeScript

While in the process of migration, you may end up in a situation where you cannot turn on compilerOptions.checkJs from TypeScript itself due to e.g. builds breaking. However, by default certain rules will be disabled for JavaScript files because they are technically shadowed by TypeScript itself, e.g. no-undef.

You can opt out of this behaviour by either:

  • passing enableJavaScriptSpecificRulesInTypeScriptProject as true to createConfig
  • enabling compilerOptions.checkJs once you're there

Example:

const { createConfig } = require('eslint-config-galex/dist/createConfig');

module.exports = createConfig({
  enableJavaScriptSpecificRulesInTypeScriptProject: true,
});

Examples

Disabling a specific @typescript-eslint rule
const { createConfig } = require('eslint-config-galex/dist/createConfig');
const { getDependencies } = require('eslint-config-galex/dist/getDependencies');
const {
  createTypeScriptOverride,
} = require('eslint-config-galex/dist/overrides/typescript');

const dependencies = getDependencies();

const customTypescriptOverride = createTypeScriptOverride({
  ...dependencies,
  rules: {
    // here goes anything that applies **exclusively** to typescript files based on the `files` glob pattern also exported from ../overrides/typescript
    '@typescript-eslint/explicit-module-boundary-types': 'warn', // downgrading the default from "error" to "warn"
  },
});

module.exports = createConfig({
  overrides: [customTypescriptOverride],
});
Changing a eslint-plugin-unicorn rule specifically for React files
const { createConfig } = require('eslint-config-galex/dist/createConfig');
const { getDependencies } = require('eslint-config-galex/dist/getDependencies');
const {
  createReactOverride,
} = require('eslint-config-galex/dist/overrides/react');

const dependencies = getDependencies();

const customReactOverride = createReactOverride({
  ...dependencies,
  rules: {
    'unicorn/no-abusive-eslint-disable': 'off',
  },
});

module.exports = createConfig({
  overrides: [customReactOverride],
});
Adding plugins to any override
const { createConfig } = require('eslint-config-galex/dist/createConfig');
const { getDependencies } = require('eslint-config-galex/dist/getDependencies');
const {
  createReactOverride,
} = require('eslint-config-galex/dist/overrides/react');

const dependencies = getDependencies();

const customReactOverride = createReactOverride({
  ...dependencies,
  plugins: ['my-fancy-plugin'],
  rules: {
    'plugin/foo': 'warn',
    'plugin/bar': 'error',
    'plugin/baz': 'off',
  },
});

module.exports = createConfig({
  overrides: [customReactOverride],
});
Building your own config with the available exports
const { getDependencies } = require('eslint-config-galex/dist/getDependencies');
const {
  files,
  parser,
  defaultSettings,
} = require('eslint-config-galex/dist/overrides/react');

const dependencies = getDependencies();

const myReactOverride = {
  // using the internal react glob pattern
  files,
  // using the internal default react parser
  parser,
  // defining your custom rules
  rules: {
    'react/react-in-jsx-scope': 'warn',
  },
  // using the default settings
  settings: defaultSettings,
};

module.exports = {
  overrides: [myReactOverride],
  rules: {
    'no-await-in-loop': 'warn',
  },
};

I went through 30+ eslint-plugins so you don't have to.

Setting up ESLint can be easy.

Plug in someone's config or one of the many "industry standards" and be done with it. Eventually you learn that some of those practices maybe aren't the best idea. Too restrictive, treading into Prettier territory, conflicting with other rules, too opinionated or even outdated, you name it. What to do?

You begin adding // eslint-disable-next-line rulename-here. It works, but litters the code.

You begin disabling rules altogether. Maybe because you don't know better, or because the rule is actually bad for your situation. You begin to wonder.

You check npm and see there are 2.8k+ (August 2020) 4.1k+ (December 2021) eslint-plugin-* packages out there. And even worse - 10k+ eslint-config-* packages. Which to choose? You sort by popularity and see some familiar faces. Time to install!

A few hours into stitching all those popular linting rules together you notice some rules collide, some rules are outdated, some expect others to be disabled, but only circumstantially. Enough!

"Now is the time to finally read through all rulesets and decide which I want!" you scream out loud, "it can't be that many!" - but find yourself finishing the first repo after 6 hours.

Setting up ESLint properly wasn't that easy after all.

Couldn't this be easier?

What makes this different than all the other configs out there?

  • It's incrementally adoptable! Usually you pick a config at one point in time: when starting a fresh project, or at least early on. Migrating later on, especially when working in teams with lots of code movement, you'd run into merging conflicts real quick.

    Good news: you can use createConfig({ incrementalAdoption: true }) to downgrade all errors to warnings, and disable all warnings!

    This allows you to introduce the config at an arbitrary point in time, while still profiting of it from minute one and still allows you to continue. Most urgent issues won't break the build - the best of both worlds!

    Once you feel comfortable raising the reporting level, simply set incrementalAdoption to false or remove it from the arguments passed to createConfig.

  • Integration tests for all cases.

  • All internals, literally everything, is re-exported. Don't like some decision? Rules too weak? Want to add custom rules? Everything is covered!

    This hopefully prevents the need of having to migrate between configs every once in a while which builds up frustration due to misconfiguration and the entire overhead related to that. Dependency injection, just for an eslint config!

  • This config has a heavy focus on code quality, best practices and tries to omit opinions.

What's included?

Everything is dynamically included based on your package.json and when using TypeScript, your tsconfig.json. Rules are selectively applied based on file name patterns.

All rules are commented and link to their docs.

  • React
  • Next.js
  • Remix Run
  • TypeScript
  • Node.js
  • jest
  • jest-dom
  • @testing-library
  • prettier
  • storybook & storybook/testing-library
  • NestJS (with TypeScript)

Customization

All rulesets and overrides are created through functions accepting an object matching this schema:

interface Project {
  /**
   * whether `jest` is present
   */
  hasJest: boolean;
  /**
   * whether `@testing-library/jest-dom` is present
   */
  hasJestDom: boolean;
  /**
   * whether `@types/node` is present
   */
  hasNodeTypes: boolean;
  /**
   * whether any `@testing-library/<environment>` is present
   */
  hasTestingLibrary: boolean;
  /**
   * whether `@nestjs/core` is present
   */
  hasNest: boolean;
  storybook: {
    /**
     * whether any `@storybook/` is present that is not `@storybook/testing-library`
     */
    hasStorybook: boolean;
    /**
     * whether `@storybook/testing-library` is present
     */
    hasStorybookTestingLibrary: boolean;
  };
  typescript: {
    /**
     * whether `typescript` is present
     */
    hasTypeScript: boolean;
    /**
     * the installed version
     */
    version: string;
    /**
     * your tsConfig; used to detect feature availability
     */
    config?: object;
  };
  react: {
    /**
     * whether any flavour of react is present
     */
    hasReact: boolean;
    /**
     * whether `next` is present
     */
    isNext: boolean;
    /**
     *  whether `@remix-run/react` is present
     */
    isRemix: boolean;
    /**
     * whether `preact` is present
     * currently without effect
     */
    isPreact: boolean;
    /**
     * the installed version
     */
    version: string;
    /**
     * whether the project was bootstrapped with create-react-app
     */
    isCreateReactApp: boolean;
  };
  /**
   * your custom rules on top
   */
  rules?: object;
}

Available main exports:

This list only mentions the exports most people will need. For an exhaustive list, check out the source.

Overrides

  • const { createTypeScriptOverride } = require('eslint-config-galex/dist/overrides/typescript')
  • const { createReactOverride } = require('eslint-config-galex/dist/overrides/react')
  • const { createJestOverride } = require('eslint-config-galex/dist/overrides/jest')
  • const { createStorybookOverride } = require('eslint-config-galex/dist/overrides/storybook')

Please note that the test override should always come last.

Rulesets

  • const { createEslintCoreRules } = require('eslint-config-galex/dist/plugins/eslint-core')
  • const { createImportRules } = require('eslint-config-galex/dist/plugins/import')
  • const { createNextJsRules } = require('eslint-config-galex/dist/plugins/next')
  • const { createPromiseRules } = require('eslint-config-galex/dist/plugins/promise')
  • const { createSonarjsRules } = require('eslint-config-galex/dist/plugins/sonarjs')
  • const { createUnicornRules } = require('eslint-config-galex/dist/plugins/unicorn')

Examples

Custom TypeScript override to disable a rule

const { createConfig } = require('eslint-config-galex/dist/createConfig');
const {
  createTypeScriptOverride,
} = require('eslint-config-galex/dist/overrides/typescript');
const packageJson = require('./package.json');

// since `createTypeScriptOverride` is entirely configurable, we need to inform it about its environment
const tsOverrideConfig = {
  react: {
    hasReact: true,
  },
  rules: {
    '@typescript-eslint/ban-ts-comment': 'off',
  },
  typescript: {
    hasTypeScript: true,
    // sync with package.json should you upgrade TS
    version: packageJson.dependencies.typescript,
  },
};

// solely an override for TS
const tsOverride = createTypeScriptOverride(tsOverrideConfig);

// pass it into createConfig as array as it will be merged with the other overrides
module.exports = createConfig({ overrides: [tsOverride] });

Custom Jest override changing included files:

const { createConfig } = require('eslint-config-galex/dist/createConfig');
const { getDependencies } = require('eslint-config-galex/dist/getDependencies');
const {
  createJestOverride,
} = require('eslint-config-galex/dist/overrides/jest');

/**
 * override to enable jest globals for `/testUtils` folder
 */
const customJestLikeOverride = createJestOverride({
  ...getDependencies(),
  files: ['testUtils/*.ts?(x)'],
});

module.exports = createConfig({
  overrides: [customJestLikeOverride],
});

Meta

This project follows semver.

eslint-config-galex's People

Contributors

axelboc avatar dependabot-preview[bot] avatar dependabot[bot] avatar ljosberinn avatar mergify[bot] avatar muametgrooby avatar renovate-bot avatar renovate[bot] avatar semantic-release-bot avatar themaru avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

eslint-config-galex's Issues

Migrate to TS

kinda wanna ship types and definitely dont want to sync jsdoc comments across the codebase

Trouble using with Create React App

I have a React app bootstrapped with Create React App. I added this eslint config as per the instructions.
Upon running running eslint on the src directory, I got a lot of errors on files that come by default from CRA (eg.: serviceWorker.ts).

How should this be handled? I tried adding react-app to the extensions in the eslint config, but it introduced additional problems and in the end it did not help.

next version (not necessarily major)

  • move to typescript. will be tough and there are some typing issues technically present. at the very least use // @ts-check everywhere
  • a standalone UI to create a config? πŸ€” esp. relevant for those that are unfamiliar with the eslint config schema and how overrides work
  • add CLI capability to statically generate a config (including recommended postinstall step e.g.)

CRA depends on eslint-plugin-testing-library@^3.9.2

The latest release of eslint-config-galex bumps eslint-plugin-testing-library to version 3.10.0, which is incompatible with react-scripts v4.0. As a result, I'm getting the following error:

Definition for rule 'testing-library/no-await-sync-events' was not found testing-library/no-await-sync-events

I'm using NPM so I can't yet override module resolutions.

Parsing error: Unexpected token <

I'm using these eslint rules in a monorepo across two packages (studio and web). On the studio package it works absolutely fine, but on the web package it doesn't seem to be working at all and I get the above error.

The web package is using NextJS so perhaps I'm missing something. I've tried all manor of things to get it working like adding parsing options, babel configs, etc, but nothing seems to work.

I was wondering if I was missing something? I made the repo public below...

https://github.com/Modular-Everything/UEFA

Edit: I'm just noticing that the linting is working, but only in certain files. Editing sanity.js I get the linting errors, but the error mentioned in the title comes from editing index.js

disable no-void

conflicts with no-floating-promises or whatever its called and voiding those should be allowed

@typescript-eslint/non-nullable-type-assertion-style conflicts with other rule

The code below in my codebase triggers a warning suggesting I use ! instead of as Entity. The warning comes from this rule: @typescript-eslint/non-nullable-type-assertion-style.

if (childCache.has(path)) {
  return childCache.get(path) as Entity;
}

However, when I make the change, I get an error because of rule @typescript-eslint/no-non-null-assertion. I personally prefer the casting to be explicit -- ! can easily be missed -- so I would recommend disabling @typescript-eslint/non-nullable-type-assertion-style.

Configuration for rule "@typescript-eslint/ban-ts-comment" is invalid

Hey, I'm getting the following error when launching eslint through the command line:

$ npx eslint src --fix
.eslintrc.js#overrides[1]:
        Configuration for rule "@typescript-eslint/ban-ts-comment" is invalid:
        Value "allow-with-description" should be boolean.

This seems to stop the linting completely. I thought manually overriding the rule should help, but it doesn't:

module.exports = {
  extends: 'galex',
  rules: {
    '@typescript-eslint/ban-ts-comment': 0,
  },
};

[jest] disable rules

  ...(hasReact ? { 'react/button-has-type': 'off' } : null),
  ...(hasReact ? { 'jsx-a11y/control-has-associated-label': 'off' } : null),
  'require-unicode-regexp': 'off',
  'no-param-reassign': 'off',

bug: avoid adding similar overrides multiple times

right now, adding a react override will lead to this order:

  • react override
  • ts override
  • others
  • ...custom

this can lead to issues if you want to configure react rules in a TS react project, as the order is still important - the final react override will take precedence over the default TS override, which results in an error because of a missing parser for @typescript-eslint/eslint-plugin

if each createXYOverride would be uniquely identifiyable internally we could filter overrides before adding customOverrides and maintain the same order

Add `/` marker to spaced-comment config

In CRA, there's a file called react-app-env.d.ts with a triple-slash comment:

image

I believe spaced-comment can be configured as such to remove the warning:

"spaced-comment": ["error", "always", { "markers": ["/"] }]

Action Required: Fix Renovate Configuration

There is an error with this repository's Renovate configuration that needs to be fixed. As a precaution, Renovate will stop PRs until it is resolved.

Error type: undefined. Note: this is a nested preset so please contact the preset author if you are unable to fix it yourself.

The automated release is failing 🚨

🚨 The automated release from the master branch failed. 🚨

I recommend you give this issue a high priority, so other packages depending on you could benefit from your bug fixes and new features.

You can find below the list of errors reported by semantic-release. Each one of them has to be resolved in order to automatically publish your package. I’m sure you can resolve this πŸ’ͺ.

Errors are usually caused by a misconfiguration or an authentication problem. With each error reported below you will find explanation and guidance to help you to resolve it.

Once all the errors are resolved, semantic-release will release your package the next time you push a commit to the master branch. You can also manually restart the failed CI job that runs semantic-release.

If you are not sure how to resolve this, here is some links that can help you:

If those don’t help, or if this issue is reporting something you think isn’t right, you can always ask the humans behind semantic-release.


Invalid npm token.

The npm token configured in the NPM_TOKEN environment variable must be a valid token allowing to publish to the registry https://registry.npmjs.org/.

If you are using Two-Factor Authentication, make configure the auth-only level is supported. semantic-release cannot publish with the default auth-and-writes level.

Please make sure to set the NPM_TOKEN environment variable in your CI with the exact value of the npm token.


Good luck with your project ✨

Your semantic-release bot πŸ“¦πŸš€

allow injecting module globals into create functions too

e.g.

const env = {
  jest: true,
};

const extendsConfig = ['plugin:jest-formatting/strict'];
const files = ['**/*.?(test|spec).?(ts|js)?(x)'];
const parserOptions = {
  ecmaVersion: 2020,
};

const settings = {
  jest: {
    version: 'detect',
  },
};

/**
 * @param {{
 *  hasJestDom: boolean;
 *  hasJest: boolean;
 *  hasTestingLibrary: boolean;
 *  react: {
 *    hasReact: boolean;
 *  };
 *  typescript: {
 *    hasTypeScript: boolean;
 *  };
 *  customRules?: Record<string, string | [string, string | object];
 * }} options
 */
const createJestOverride = ({
  hasJestDom,
  hasJest,
  hasTestingLibrary,
  react,
  typescript,
  // these bad boys here
  customExtends,
  customEnv,
  customSettings,
  // ^^^^^^^
  customRules = {},
}) => {
  // ...
  return {
    env: customEnv ?? env,
  }
}

disable slow rules

import/no-useless-path-segments ~ 25%
import/no-cycle ~ 14%
import/no-extraneous-dependencies ~ 13%
import/no-self-import ~ 11%

consider disabling the following aswell:
@typescript-eslint/no-confusing-void-expression ~ 4%
@typescript-eslint/no-floating-promises ~ 2%

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.