Giter VIP home page Giter VIP logo

eslint-react's Introduction

logo

ESLint React

Version Size Downloads

A series of composable ESLint rules for libraries and frameworks that use React as a UI runtime.

Roadmap

Features

  • Universal rules for libraries and frameworks that use React as a UI runtime.
  • Well designed rule behaviors and sensible defaults.
  • Maximum flexibility through minimum configuration options.

Public packages

All-in-one packages

Individual packages (will be available in 2.0)

  • eslint-plugin-react-core - Core rules (DOM Irrelevant, Render Target Agnostic, Formatting Independent).
  • eslint-plugin-react-dom - DOM specific rules for React DOM.
  • eslint-plugin-react-hooks-extra - Extra React Hooks rules.
  • eslint-plugin-react-naming-convention - Naming convention rules.

Supported React versions

  • 18.2.0 or later

Supported engines

Node.js

  • 18.18.0 or later

Bun

  • 1.0.15 or later

Install

# npm
npm install --save-dev @eslint-react/eslint-plugin

Setup

Add the plugin to your eslint.config.js:

// @ts-check

import eslint from "@eslint/js";
import tseslint from "typescript-eslint";
import eslintReact from "@eslint-react/eslint-plugin";

export default tseslint.config(
  eslint.configs.recommended,
  ...tseslint.configs.recommended,
  {
    files: ["src/**/*.{ts,tsx}"],
    ...eslintReact.configs.recommended,
  },
);

Full Installation Guide ↗

Presets

  • recommended
    Enable rules that are recommended by ESLint React.
  • recommended-type-checked
    Enable rules that are recommended by ESLint React with additional rules that require type information.
  • dom
    Enable rules that are specific to React DOM.
  • off-dom
    Disable rules that are specific to React DOM.
  • all
    Enable all rules in this plugin except for debug rules.
  • off
    Disable all rules in this plugin except for debug rules.

Full Presets List↗

Rules

Rules Overview ↗

Contributing

Before you start working on something, it's best to check if there is an existing issue first. It's also a good idea to reach the maintainer and confirm if it makes sense or if someone else is already working on it.

Please make sure to read the Contributing Guide before making a pull request.

Thank you to everyone contributing to ESLint React!

License

This project is licensed under the MIT License - see the LICENSE file for details.

Inspiration

Prior art

eslint-react's People

Contributors

dependabot[bot] avatar hyoban avatar rel1cx 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

Watchers

 avatar  avatar

eslint-react's Issues

Fail to install `@eslint-react/eslint-plugin`

❯ ni @eslint-react/eslint-plugin
 ERR_PNPM_FETCH_404  GET https://registry.npmjs.org/@eslint-react%2Feslint-plugin-hooks: Not Found - 404

This error happened while installing the dependencies of @eslint-react/[email protected]

@eslint-react/eslint-plugin-hooks is not in the npm registry, or you have no permission to fetch it.

An authorization header was used: Bearer npm_[hidden]
Progress: resolved 420, reused 397, downloaded 0, added 0

The declared dependency @eslint-react/eslint-plugin-xxx is not published to npm, we have packaged it into @eslint-react/eslint-plugin.

[bug] `no-missing-component-display-name` not work with early return component

Describe the bug

The following code should not report an error

import { forwardRef, ReactNode } from 'react';

interface Props {
  children?: ReactNode;
}
export type Ref = HTMLButtonElement;

const FancyButton = forwardRef<Ref, Props>((props, ref) => {
  // It's works without this
  if (!props.children) return null;
  return (
    <button ref={ref} className="MyClassName" type="button">
      {props.children}
      hell
    </button>
  );
});

FancyButton.displayName = 'FancyButton';

export default function App() {
  return <FancyButton />;
}
/home/projects/vitejs-vite-bngjjk/src/app.tsx
  8:44  warning  no missing display name  @eslint-react/react/no-missing-component-display-name

✖ 1 problem (0 errors, 1 warning)

Reproduction

https://stackblitz.com/edit/vitejs-vite-bngjjk?file=src%2Fapp.tsx

Expected behavior

No response

Platform and versions

In stackblitz with "@eslint-react/eslint-plugin": "^0.8.9"

Stack trace

No response

Additional context

No response

Rule Request: implement `eslint-plugin-react` rules


  • Add all rules implementation to rules exports
  • Link all rules implementation documentation to README.md

  • jsx/no-script-url: Custom Component and prop support

[bug] `Error: Key "rules": Key "@eslint-react/naming-convention/filename-extension": Value "as-needed" should be object.`

Describe the bug

Per documentation (https://eslint-react.rel1cx.io/rules/naming-convention-filename-extension)

This rule has a string option

Reproduction

'@eslint-react/naming-convention/filename-extension': ['error', 'as-needed']

Expected behavior

No response

Platform and versions

Node.js 20.7.0
@eslint-react 0.9.5

Stack trace

No response

Additional context

The documentation is outdated and should be updated.

TypeError: Key "rules": Key "@eslint-react/jsx/no-array-index-key": Could not find plugin "@eslint-react/jsx".

Will you release different packages for different rules or modify the default preset? For example, jsx/no-array-index-key corresponds to @eslint-react/jsx.

Currently, it is not possible to use the @eslint-react/eslint-plugin package to lint as described in the readme, because jsx-related rules cannot be correctly mapped.

TypeError: Key "rules": Key "@eslint-react/jsx/no-array-index-key": Could not find plugin "@eslint-react/jsx".

I'm using eslint flat config.

[feat] Request rule: `require-use-memo-use-callback-to-have-non-empty-dependency-array`

Describe the problem

const Comp = () => {
  const style = useCallback((theme: MantineTheme) => ({
    input: {
      fontFamily: theme.fontFamilyMonospace
    }
  }), []);
  return <Button sx={style} />
}

The useCallback here is completely not necessary, it can be hoisted:

const style = (theme: MantineTheme) => ({
  input: {
    fontFamily: theme.fontFamilyMonospace
  }
});

const Comp = () => {
  return <Button sx={style} />
}

Describe the solution you'd like

Find all useCallback and useMemo hook inside components, and check if their dependency array has 0 elements.

Alternatives considered

No response

Additional context

No response

`no-leaked-conditional-rendering` maybe no need to check conditional expression

{ x ? y : z }
{ y }
{ x && y }

I just realized that maybe y in a normal expression is no different from y in a conditional expression. They are both what the user expects to be rendered. But x is different, when x is false, it may cause rendering of something other than what is expected.

For example, the following should be the correct code

const SomeComponent = () => <div />;
const someFunction = (input: unknown) => input as number;

const App = ({ someCondition }: { someCondition?: number | undefined }) => {
  return <>{someCondition ? someFunction(someCondition) : <SomeComponent />}</>;
};

[bug] `no-missing-component-display-name` can not check `displayName` from `MemberExpression`

Describe the bug

This should not report an error

const someThing = {
  displayName: "someThing",
}
const Component = React.forwardRef(() => <div/>)
Component.displayName = someThing.displayName

Maybe add a check in componentCollector

const maybeRightValue = match(right)
    .with({ type: NodeType.Literal }, ({ value }) => O.some(value))
    .with({ type: NodeType.TemplateLiteral }, n => O.some(getStaticValue(n)?.value))
    .with({ type: NodeType.MemberExpression }, n => {
	// here
    })
    .with({ type: NodeType.Identifier }, n => {
      return F.pipe(
        findVariableByNameUpToGlobal(n.name, context.getScope()),
        O.flatMap(getVariableInit(0)),
        O.filter(isOneOf([NodeType.Literal, NodeType.TemplateLiteral])),
        O.map(getStaticValue),
        O.flatMapNullable(v => v?.value),
      );
    })
    .otherwise(O.none);

Reproduction

No response

Expected behavior

No response

Platform and versions

node: v18.18.2
@eslint-react: v0.8.10-beta.2

Stack trace

No response

Additional context

No response

Can not work with `eslint-define-config`

import { Pretty } from '@eslint-react/tools';
import * as debug from '@eslint-react/eslint-plugin-debug';
import * as hooks from '@eslint-react/eslint-plugin-hooks';
import * as jsx from '@eslint-react/eslint-plugin-jsx';
import * as namingConvention from '@eslint-react/eslint-plugin-naming-convention';
import * as react from '@eslint-react/eslint-plugin-react';
import { ESLintUtils } from '@typescript-eslint/utils';

type Rules = typeof _default.rules;
type RulesWithOptions = Pretty<
  {
    [ruleName in keyof Rules as `@eslint-react/${ruleName}`]: Parameters<Rules[ruleName]["create"]>[0]["options"];
  }
>;

declare module "eslint-define-config" {
  // eslint-disable-next-line @typescript-eslint/no-empty-interface
  export interface CustomRuleOptions extends RulesWithOptions {}
}

In user-side code, the type for unpublished @eslint-react/tools cannot be found.
We may need something like tsup --dts-resolve, or not use types from internal packages.

[Rule Request] `react-hooks/ensure-use-callback-has-non-empty-deps`

Describe the problem

Describe the problem

const Comp = () => {
  const style = useCallback((theme: MantineTheme) => ({
    input: {
      fontFamily: theme.fontFamilyMonospace
    }
  }), []);
  return <Button sx={style} />
}

The useCallback here is completely not necessary, it can be hoisted:

const style = (theme: MantineTheme) => ({
  input: {
    fontFamily: theme.fontFamilyMonospace
  }
});

const Comp = () => {
  return <Button sx={style} />
}

Describe the solution you'd like

Find all useCallback hook inside components, and check if their dependency array has 0 elements.

Alternatives considered

No response

Additional context

No response

[Rule Migration] migrate eslint-plugin-react rules

Migration Status

Correctness and best practices rules

  • react/jsx-boolean-value ···················-> @eslint-react/jsx/prefer-shorthand-boolean
  • react/jsx-fragments ·······················-> @eslint-react/jsx/prefer-shorthand-fragment
  • react/jsx-key -----------|··················-> @eslint-react/jsx/no-missing-key
  • react/no-array-index-key |··················-> @eslint-react/jsx/no-array-index-key
  • ·························|··················-> @eslint-react/jsx/no-duplicate-key
  • -------------------------|··················-> @eslint-react/jsx/no-spreading-key
  • #102
  • react/jsx-no-useless-fragment ·············-> @eslint-react/jsx/no-useless-fragment
  • react/jsx-no-leaked-render ················-> @eslint-react/jsx/no-leaked-conditional-rendering
  • #104
  • react/jsx-no-comment-textnodes ············-> @eslint-react/jsx/no-comment-textnodes
  • react/jsx-filename-extension ··············-> @eslint-react/naming-convention/filename-extension
  • react/boolean-prop-naming ·················-> @eslint-react/naming-convention/boolean-prop
  • react/jsx-handler-names ···················-> @eslint-react/naming-convention/handler-prop
  • #205
  • #107
  • react/jsx-no-script-url ···················-> @eslint-react/react/no-script-url
  • react/jsx-no-target-blank ·················-> @eslint-react/react/no-unsafe-target-blank
  • react/button-has-type ·····················-> @eslint-react/react/no-missing-button-type
  • react/iframe-missing-sandbox | ············-> @eslint-react/react/no-missing-iframe-sandbox
  • -----------------------------|··············-> @eslint-react/react/no-unsafe-iframe-sandbox
  • react/jsx-no-constructed-context-values ···-> @eslint-react/react/no-constructed-context-value
  • react/no-danger ···························-> @eslint-react/react/no-dangerously-set-innerhtml
  • react/no-danger-with-children ·············-> @eslint-react/react/no-dangerously-set-innerhtml-with-children
  • react/no-namespace ························-> @eslint-react/react/no-namespace
  • #186
  • #173
  • #183
  • #185
  • react/no-string-refs ········|··············-> @eslint-react/react/no-string-refs
  • -----------------------------|··············-> @eslint-react/react/no-create-ref
  • #101
  • #202
  • #190
  • #191
  • #192
  • #197
  • #198
  • #199
  • #187
  • react/no-object-type-as-default-prop ······-> @eslint-react/react/no-unstable-default-props
  • react/no-unstable-nested-components ·······-> @eslint-react/react/no-unstable-nested-components
  • react/no-unused-state ·····················-> @eslint-react/react/no-unused-state
  • #207
  • react/void-dom-elements-no-children ·······-> @eslint-react/react/no-children-in-vold-dom-elements
  • react/destructuring-assignment ············-> @eslint-react/react/prefer-destructuring-assignment
  • react/prefer-read-only-props ··············-> @eslint-react/react/prefer-readonly-props
  • #301
  • #234

The following can be enforced by TypeScript, no need to implement them

  • react/jsx-no-duplicate-props
  • react/jsx-no-undef
  • react/jsx-uses-react
  • react/jsx-uses-vars
  • react/no-invalid-html-attribute
  • react/no-this-in-sfc
  • react/no-unescaped-entities -> No need when using @typescript-eslint/parser
  • react/no-unknown-property
  • react/style-prop-object
  • react/prop-types
  • react/react-in-jsx-scope
  • react/require-render-return

Customized rules

These rule will be added in the future.

  • react/forbid-elements -> @eslint-react/react/ban-components
  • react/forbid-component-props -> @eslint-react/react/ban-component-props
  • react/forbid-dom-props
    • -> @eslint-react/react/ban-html-props
    • -> @eslint-react/react/ban-svg-props

Stylistic rules

Stylistic rules are not supported by this plugin. Use dprint or @stylistic instead.

  • react/jsx-child-element-spacing
  • react/jsx-closing-bracket-location
  • react/jsx-closing-tag-location
  • react/jsx-curly-brace-presence
  • react/jsx-curly-newline
  • react/jsx-curly-spacing
  • react/jsx-equals-spacing
  • react/jsx-first-prop-new-line
  • react/jsx-indent-props
  • react/jsx-indent
  • react/jsx-max-props-per-line
  • react/jsx-newline
  • react/jsx-one-expression-per-line
  • react/jsx-pascal-case
  • react/jsx-props-no-multi-spaces
  • react/jsx-sort-default-props
  • react/jsx-sort-props
  • react/jsx-space-before-closing
  • react/jsx-tag-spacing
  • react/jsx-wrap-multilines

Outdated or obsolete rules

These rules are considered outdated or obsolete. They are not going to be supported by this plugin.

  • react/default-props-match-prop-types
  • react/forbid-foreign-prop-types
  • react/forbid-prop-types
  • react/no-unused-prop-types
  • react/prefer-exact-props
  • react/prefer-es6-class
  • react/prefer-stateless-function
  • react/require-default-props
  • react/require-optimization
  • react/sort-default-props
  • react/sort-prop-types
  • react/state-in-constructor
  • react/static-property-placement
  • react/jsx-no-bind

Work in progress rules

JSX rules

  • jsx/max-depth

Naming convention rules

  • naming-convention/boolean-prop
  • naming-convention/handler-prop

React rules

  • react/prefer-readonly-props
  • react/ban-component-props
  • react/ban-components
  • #294
  • react/no-unused-class-component-members
  • react/no-unsorted-class-component-members

[Rule Request] `react-hooks/ensure-use-memo-has-non-empty-deps`

Describe the problem

Describe the problem

const Comp = () => {
  const style = useMemo((theme: MantineTheme) => ({
    input: {
      fontFamily: theme.fontFamilyMonospace
    }
  }), []);
  return <Button sx={style} />
}

The useCallback here is completely not necessary, it can be hoisted:

const style = (theme: MantineTheme) => ({
  input: {
    fontFamily: theme.fontFamilyMonospace
  }
});

const Comp = () => {
  return <Button sx={style} />
}

Describe the solution you'd like

Find all useMemo hook inside components, and check if their dependency array has 0 elements.

Alternatives considered

No response

Additional context

No response

Rule Request: `ensure-custom-hooks-using-other-hooks`

Valid

const useData = (key) => {
  // Valid, because useData is using other React Hooks.
  return useSWR(key);
}

Invalid

const useClassnames = (obj) => {
  // Invalid, because useClassnames doesn't use any other React Hooks.
  var k, cls='';
  for (k in obj) {
    if (obj[k]) {
      cls && (cls += ' ');
      cls += k;
    }
  }
  return cls;
}

Transfer project back to personal GitHub

image

It looks like we're going to run out of free Netlify credit in just a few days, and I need to transfer the project back to a personal GitHub so we can use Vercel without having to buy a paid team plan, and a lot of other services require a paid plan for projects under the organization, which I don't have the money to pay for at the moment.

A more agnosticism plugin name `eslint-plugin-jsx`?

Hi @Rel1cx .

I believe jsx is not only for react and this amazing ESLint plugin can benefit other jsx friendly frameworks like preact, solid, vue, etc.

And I just got the eslint-plugin-jsx npm package maintainer permission from @jkroso , I'd like to propose to change the current plugin more agnosticism.

How do you think?

Don't mind if you don't agree with me.

Best wishes.

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.