eslint-plugin-react
eslint-plugin-react copied to clipboard
[Bug]: Wrong definition. jsx-closing-bracket-location
Is there an existing issue for this?
- [X] I have searched the existing issues and my issue is unique
- [X] My issue appears in the command-line and not only in the text editor
Description Overview
I want to use the line-aligned value, but I don't think it works correctly if I have a props that has a hyphenated object.
Here's an example where I don't expect to see any errors:
<Box sx={{
position: "relative",
maxWidth: "720px",
width: "100%",
backgroundColor: "#26216d"
}}>
{/* Content */}
</Box>
or
<Box sx={{
position: "relative",
maxWidth: "720px",
width: "100%",
backgroundColor: "#26216d"
}} />
I think it's because of multiline in props that I'm getting the error.
"react/jsx-closing-bracket-location": [ "error", { "nonEmpty": "line-aligned", "selfClosing": "line-aligned" } ]
Expected Behavior
I would like the code I have provided to work perfectly, for I believe this is the right way to go.
<Box sx={{
position: "relative",
maxWidth: "720px",
width: "100%",
backgroundColor: "#26216d"
}}>
{/* Content */}
</Box>
or
<Box sx={{
position: "relative",
maxWidth: "720px",
width: "100%",
backgroundColor: "#26216d"
}} />
eslint-plugin-react version
^7.33.2
eslint version
^8.54.0
node version
v18.12.1
The rule is expecting this, i suspect:
<Box
sx={{
}}
/>
the tag name and prop name shouldn’t be on the same line, if the prop is spread across multiple lines.
@ljharb, I understand what it expects, but I don't think it's the right option. Why should I carry over if I only have one attribute, even though it's multi-line? I think there should be some kind of customization.
Because you have more than zero attributes. The premise (also supported by the Airbnb styleguide) is that if an entire thing - in this case, a jsx element - isn’t contained within a single line, then each conceptual thing should be on its own line by itself.
We could allow the customization you want via an option, but that’s a lot of extra complexity for something that I’m convinced makes for less readable and deterministic code.
My personal opinion: this variant looks much worse, because it takes up a lot of space. My variant is more compact and readable. If there is no such variant, it is very sad and it looks like I will have to give up this rule altogether, which I would not like.
Compactness can often hurt readability.
Ok, I've decided to try to go with the current format after all. But then how do I automatically move the props to a new line? Right now I get the following:
<Box sx={{
minHeight: "100vh",
background: `url(${ IMGBackground }) center center/cover`,
display: "flex",
flexDirection: "column",
"@supports (min-height: 100dvh)":
{
minHeight: "100dvh"
}
}}
>
<Component />
</Box>
What I'd expect is this:
<Box
sx={{
minHeight: "100vh",
background: `url(${ IMGBackground }) center center/cover`,
display: "flex",
flexDirection: "column",
"@supports (min-height: 100dvh)": {
minHeight: "100dvh"
}
}}
>
<Component />
</Box>
If you start with the airbnb config, it should be roughly corrected to this?
Well, if you're judging by jsx, yes. I can provide my config.
{
"plugins": [ "react", "@typescript-eslint", "react-hooks" ],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"project": "./tsconfig.json"
},
"settings": {
"react": { "version": "detect" }
},
"rules": {
"no-restricted-imports": [
"error",
{
"paths": [
{
"name": "react-i18next",
"importNames": [
"useTranslation"
],
"message": "Please use useTranslation from next-i18next instead."
}
]
}
],
"array-bracket-newline": [ "error", "consistent" ],
"array-bracket-spacing": [ "error", "always" ],
"array-element-newline": [ "error", "consistent" ],
"arrow-spacing": [ "error", { "before": true, "after": true } ],
"block-spacing": [ "error", "always" ],
"brace-style": [ "error", "allman", { "allowSingleLine": true } ],
"comma-dangle": [ "error", "never" ],
"comma-spacing": [ "error", { "before": false, "after": true } ],
"comma-style": [ "error", "last" ],
"computed-property-spacing": [ "error", "always" ],
"keyword-spacing": [ "error", { "before": true, "after": true } ],
"no-extra-semi": "error",
"object-curly-spacing": [ "error", "always" ],
"object-curly-newline": [ "error", { "consistent": true, "multiline": true } ],
"object-property-newline": [ "error", { "allowAllPropertiesOnSameLine": true } ],
"quotes": [ "error", "double", { "avoidEscape": true } ],
"semi": "error",
"semi-spacing": [ "error", { "before": false, "after": true } ],
"space-before-blocks": "error",
"space-before-function-paren": [ "error", { "asyncArrow": "always", "anonymous": "always", "named": "never" } ],
"template-curly-spacing": [ "error", "always" ],
"template-tag-spacing": [ "error", "never" ],
"space-in-parens": [ "error", "never" ],
"space-infix-ops": [ "error", { "int32Hint": false } ],
"space-unary-ops": [ "error", { "words": true, "nonwords": false } ],
"switch-colon-spacing": [ "error", { "after": true, "before": false } ],
"dot-location": [ "error", "property" ],
"dot-notation": "off",
"eol-last": [ "error", "always" ],
"no-multiple-empty-lines": [ "error", { "max": 1, "maxEOF": 0, "maxBOF": 0 } ],
"no-trailing-spaces": "error",
"func-call-spacing": [ "error", "never" ],
"function-call-argument-newline": [ "error", "consistent" ],
"function-paren-newline": [ "error", "multiline-arguments" ],
"implicit-arrow-linebreak": [ "error", "beside" ],
"indent": [ "error", "tab", { "SwitchCase": 1, "MemberExpression": 1 } ],
"jsx-quotes": [ "error", "prefer-double" ],
"key-spacing": [ "error", { "beforeColon": false, "afterColon": true } ],
"padding-line-between-statements": [
"error",
{ "blankLine": "always", "prev": [ "import", "cjs-import", "function", "block-like", "multiline-const", "multiline-let", "multiline-var" ], "next": "*" },
{ "blankLine": "any", "prev": [ "import", "cjs-import" ], "next": [ "import", "cjs-import" ] },
{ "blankLine": "always", "prev": [ "const", "let", "var" ], "next": "*" },
{ "blankLine": "any", "prev": [ "const", "let", "var" ], "next": [ "const", "let", "var", "if" ] },
{ "blankLine": "always", "prev": "*", "next": "return" }
],
"max-len": [
"error",
{
"code": 140,
"tabWidth": 3,
"ignoreUrls": true,
"ignoreStrings": true,
"ignoreTemplateLiterals": true,
"ignoreRegExpLiterals": true,
"ignoreComments": true,
"ignoreTrailingComments": true
}
],
"multiline-ternary": [ "error", "always-multiline" ],
"new-parens": "error",
"newline-per-chained-call": [ "error", { "ignoreChainWithDepth": 3 } ],
"no-mixed-spaces-and-tabs": [ "error", "smart-tabs" ],
"no-multi-spaces": "error",
"no-whitespace-before-property": "error",
"quote-props": [ "error", "as-needed" ],
"rest-spread-spacing": [ "error", "never" ],
"vars-on-top": "error",
"no-unneeded-ternary": "error",
"no-console": [ "error", { "allow": [ "warn", "error", "debug", "info" ] } ],
"no-else-return": "error",
"func-style": [ "error", "declaration" ],
"default-param-last": "off",
"use-isnan": "error",
// React
"react/destructuring-assignment": [ "error", "always" ],
"react/function-component-definition": [
"error",
{ "namedComponents": "function-declaration", "unnamedComponents": "arrow-function" }
],
"react/hook-use-state": [ "off", { "allowDestructuredState": true } ],
"react/jsx-boolean-value": [ "error", "never" ],
"react/jsx-closing-bracket-location": [ "error", { "nonEmpty": "line-aligned", "selfClosing": "line-aligned" } ],
"react/jsx-closing-tag-location": [ "error" ],
"react/jsx-curly-brace-presence": [ "error", { "props": "never", "children": "never", "propElementValues": "always" } ],
"react/jsx-equals-spacing": [ "error", "never" ],
"react/jsx-filename-extension": [ "error", { "extensions": [ ".jsx", ".tsx" ] } ],
"react/jsx-fragments": [ "error", "syntax" ],
"react/jsx-first-prop-new-line": [ "error", "multiline-multiprop" ],
"react/jsx-indent": [ "error", "tab", { "indentLogicalExpressions": true, "checkAttributes": true } ],
"react/jsx-indent-props": [ "error", "tab" ],
"react/jsx-key": [ "off" ],
"react/jsx-max-props-per-line": [ "error", { "maximum": { "single": 5, "multi": 1 } } ],
"react/jsx-no-constructed-context-values": [ "error" ],
"react/jsx-no-duplicate-props": [ "error" ],
"react/jsx-no-leaked-render": [ "error" ],
"react/jsx-no-useless-fragment": [ "error", { "allowExpressions": true } ],
"react/jsx-pascal-case": [ "error", { "allowNamespace": true } ],
"react/jsx-props-no-multi-spaces": [ "error" ],
"react/jsx-tag-spacing": [
"error",
{
"closingSlash": "never",
"beforeSelfClosing": "always",
"afterOpening": "never",
"beforeClosing": "never"
}
],
"react/jsx-wrap-multilines": [
"error",
{
"declaration": "parens",
"assignment": "parens",
"return": "parens",
"arrow": "parens-new-line",
"condition": "ignore",
"logical": "ignore",
"prop": "ignore"
}
],
"react/self-closing-comp": [
"error",
{
"component": true,
"html": true
}
],
"react/style-prop-object": [ "error" ],
// Typescript
"@typescript-eslint/adjacent-overload-signatures": "error",
"@typescript-eslint/await-thenable": "error",
"@typescript-eslint/consistent-generic-constructors": [ "error", "constructor" ],
"@typescript-eslint/consistent-indexed-object-style": [ "error", "record" ],
"@typescript-eslint/default-param-last": "error",
"@typescript-eslint/dot-notation": "error",
"@typescript-eslint/explicit-member-accessibility": [ "error", { "accessibility": "no-public" } ],
"@typescript-eslint/member-delimiter-style": [ "error", { "singleline": { "requireLast": true } } ],
"@typescript-eslint/method-signature-style": [ "error", "method" ],
"@typescript-eslint/no-base-to-string": "error",
"@typescript-eslint/no-confusing-non-null-assertion": "error",
"@typescript-eslint/no-duplicate-enum-values": "error",
"@typescript-eslint/no-duplicate-type-constituents": "error",
"@typescript-eslint/no-empty-function": "error",
"@typescript-eslint/no-empty-interface": [ "off", { "allowSingleExtends": true } ],
"@typescript-eslint/no-for-in-array": "error",
"@typescript-eslint/prefer-for-of": "error",
"@typescript-eslint/prefer-optional-chain": "error",
"@typescript-eslint/prefer-reduce-type-parameter": "error",
"@typescript-eslint/prefer-string-starts-ends-with": "error",
"@typescript-eslint/require-array-sort-compare": "error",
"@typescript-eslint/type-annotation-spacing": [
"error",
{
"before": false,
"after": true,
"overrides": { "arrow": { "before": true, "after": true } }
}
]
}
}
@CzarOfScripts sorry for the long delay. if you autofix with the full airbnb config, what code are you left with that still requires manual fixing, and what are the errors?