rel1cx / eslint-react Goto Github PK
View Code? Open in Web Editor NEWA series of composable ESLint rules for libraries and frameworks that use React as a UI runtime.
Home Page: https://eslint-react.xyz/rules/overview
License: MIT License
A series of composable ESLint rules for libraries and frameworks that use React as a UI runtime.
Home Page: https://eslint-react.xyz/rules/overview
License: MIT License
Add support for detecting ContextProvider
and ContextConsumer
。
Function Call Detection, JSX Analysis, Identifier Lookup.
No response
No response
@eslint-react/no-string-refs
@eslint-react/no-class-component
@eslint-react/no-clone-element
@eslint-react/no-createRef
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;
}
no-children-in-vold-dom-elements
: #12jsx/no-unknown-property
: https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/no-unknown-property.mdjsx/enforce-component-name-pascal-case
: https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-pascal-case.mdnaming-convention/filename-extension
: https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-filename-extension.mdrequire-render-return
: https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/require-render-return.mdensure-class-component-method-order
: https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/sort-comp.mdensure-style-prop-object
: https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/style-prop-object.mdno-access-state-in-setstate
: https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/no-access-state-in-setstate.mdjsx/prefer-fragment-syntax
: https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-fragments.mdjsx/enforce-jsx-key
: https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-key.mdno-string-refs
jsx/no-useless-fragment
: #64no-unused-class-component-methods
: https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/no-unused-class-component-methods.mdno-missing-iframe-sandbox-attribute
: https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/iframe-missing-sandbox.mdno-object-type-as-default-prop
: https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/no-object-type-as-default-prop.mdrequire-button-has-type-attribute
: https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/button-has-type.mdno-namespace
: #13rules
exportsjsx/no-script-url
: Custom Component and prop supportconst 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} />
}
Find all useCallback
and useMemo
hook inside components, and check if their dependency array has 0 elements.
No response
No response
type AppProps<T> = {
someFunction: (data: T) => React.ReactNode;
};
function App<T>({ someFunction }: AppProps<T>) {
return <>{!!someFunction && someFunction(1 as T)}</>;
}
{ 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 />}</>;
};
Support for detecting new components created by calling memo, forwardRef on an existing component.
Component Collecting, Function Call Analysis, Identifier Lookup.
No response
No response
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.
Per documentation (https://eslint-react.rel1cx.io/rules/naming-convention-filename-extension)
This rule has a string option
'@eslint-react/naming-convention/filename-extension': ['error', 'as-needed']
No response
Node.js 20.7.0
@eslint-react 0.9.5
No response
The documentation is outdated and should be updated.
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)
https://stackblitz.com/edit/vitejs-vite-bngjjk?file=src%2Fapp.tsx
No response
In stackblitz with "@eslint-react/eslint-plugin": "^0.8.9"
No response
No response
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.
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
react/jsx-no-useless-fragment
·············->
@eslint-react/jsx/no-useless-fragment
react/jsx-no-leaked-render
················->
@eslint-react/jsx/no-leaked-conditional-rendering
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
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
react/no-string-refs ········|··············->
@eslint-react/react/no-string-refs
-----------------------------|··············->
@eslint-react/react/no-create-ref
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
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
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
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 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
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
jsx/max-depth
naming-convention/boolean-prop
naming-convention/handler-prop
react/prefer-readonly-props
react/ban-component-props
react/ban-components
react/no-unused-class-component-members
react/no-unsorted-class-component-members
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} />
}
Find all useMemo
hook inside components, and check if their dependency array has 0 elements.
No response
No response
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.
Supports detecting the actual displayName of components and contexts.
component
, context
collecting, assignment expression
analyzing, identifier
lookup.
No response
No response
Disallow function calls in useState
that aren't wrapped in an initializer function:
// Bad
const [value, setValue] = useState(generateTodos());
// Good
const [value, setValue] = useState(() => generateTodos());
Port jsx-eslint/eslint-plugin-react#3579
No response
No response
And maybe we also need something like changelogithub with bumpp
Continue on the https://github.com/eslint-react/eslint-react/tree/flat-config branch if we need to do this.
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.
❯ 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
.
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} />
}
Find all useCallback
hook inside components, and check if their dependency array has 0 elements.
No response
No response
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);
No response
No response
node: v18.18.2
@eslint-react: v0.8.10-beta.2
No response
No response
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.