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

πŸ› useSortedClasses lint error with Template literals #3394

Closed
1 task done
hangaoke1 opened this issue Jul 9, 2024 · 10 comments Β· Fixed by #3472
Closed
1 task done

πŸ› useSortedClasses lint error with Template literals #3394

hangaoke1 opened this issue Jul 9, 2024 · 10 comments Β· Fixed by #3472

Comments

@hangaoke1
Copy link
Contributor

Environment information

βœ– These CSS classes should be sorted.
  
    3 β”‚ const App = () => {
    4 β”‚   const listType = 'picture-card';
  > 5 β”‚   return <div className={`m-websession-uploadlist fishd-upload-list-${listType}`}>app</div>;
      β”‚                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    6 β”‚ };
    7 β”‚ 
  
  β„Ή Unsafe fix: Sort the classes.
  
    3 3 β”‚   const App = () => {
    4 4 β”‚     const listType = 'picture-card';
    5   β”‚ - Β·Β·returnΒ·<divΒ·className={`m-websession-uploadlistΒ·fishd-upload-list-${listType}`}>app</div>;
      5 β”‚ + Β·Β·returnΒ·<divΒ·className={`fishd-upload-list-Β·m-websession-uploadlist${listType}`}>app</div>;
    6 6 β”‚   };
    7 7 β”‚   
  


### Configuration

```JSON
{
  "$schema": "https://biomejs.dev/schemas/1.8.3/schema.json",
  "vcs": {
    "enabled": true,
    "clientKind": "git",
    "useIgnoreFile": true
  },
  "linter": {
    "enabled": true,
    "rules": {
      "recommended": false,
      "a11y": {
        "noBlankTarget": "error"
      },
      "complexity": {
        "noBannedTypes": "error",
        "noEmptyTypeParameters": "error",
        "noExcessiveNestedTestSuites": "error",
        "noExtraBooleanCast": "error",
        "noMultipleSpacesInRegularExpressionLiterals": "error",
        "noUselessCatch": "warn",
        "noUselessConstructor": "warn",
        "noUselessEmptyExport": "error",
        "noUselessLabel": "error",
        "noUselessLoneBlockStatements": "error",
        "noUselessRename": "error",
        "noUselessSwitchCase": "error",
        "noUselessTernary": "warn",
        "noUselessTypeConstraint": "error",
        "noVoid": "warn",
        "noWith": "error",
        "useLiteralKeys": "warn"
      },
      "correctness": {
        "noChildrenProp": "warn",
        "noConstAssign": "error",
        "noConstantCondition": "warn",
        "noConstructorReturn": "error",
        "noEmptyCharacterClassInRegex": "error",
        "noEmptyPattern": "error",
        "noGlobalObjectCalls": "error",
        "noInnerDeclarations": "warn",
        "noInvalidConstructorSuper": "error",
        "noInvalidNewBuiltin": "error",
        "noInvalidUseBeforeDeclaration": "warn",
        "noNewSymbol": "error",
        "noNonoctalDecimalEscape": "error",
        "noPrecisionLoss": "error",
        "noRenderReturnValue": "warn",
        "noSelfAssign": "error",
        "noSetterReturn": "error",
        "noStringCaseMismatch": "error",
        "noSwitchDeclarations": "warn",
        "noUndeclaredVariables": "off",
        "noUnnecessaryContinue": "error",
        "noUnreachable": "error",
        "noUnreachableSuper": "error",
        "noUnsafeFinally": "error",
        "noUnsafeOptionalChaining": "error",
        "noUnusedVariables": "warn",
        "noVoidElementsWithChildren": "error",
        "noVoidTypeReturn": "error",
        "useExhaustiveDependencies": "warn",
        "useHookAtTopLevel": "error",
        "useIsNan": "error",
        "useJsxKeyInIterable": "error"
      },
      "performance": {
        "noAccumulatingSpread": "error"
      },
      "security": {
        "noDangerouslySetInnerHtml": "warn",
        "noGlobalEval": "error"
      },
      "style": {
        "noArguments": "warn",
        "noCommaOperator": "error",
        "noInferrableTypes": "error",
        "noNamespace": "error",
        "noNonNullAssertion": "warn",
        "noVar": "warn",
        "useAsConstAssertion": "error",
        "useConst": "warn",
        "useDefaultParameterLast": "error",
        "useEnumInitializers": "error",
        "useExportType": "error",
        "useImportType": "error",
        "useShorthandFunctionType": "error",
        "useSingleVarDeclarator": "error",
        "useTemplate": "error"
      },
      "suspicious": {
        "noArrayIndexKey": "warn",
        "noAssignInExpressions": "error",
        "noAsyncPromiseExecutor": "error",
        "noCatchAssign": "error",
        "noClassAssign": "error",
        "noCommentText": "error",
        "noCompareNegZero": "error",
        "noConfusingLabels": "error",
        "noConfusingVoidType": "error",
        "noConstEnum": "error",
        "noControlCharactersInRegex": "error",
        "noDebugger": "warn",
        "noDoubleEquals": "warn",
        "noDuplicateCase": "error",
        "noDuplicateClassMembers": "error",
        "noDuplicateJsxProps": "error",
        "noDuplicateObjectKeys": "error",
        "noDuplicateParameters": "error",
        "noDuplicateTestHooks": "error",
        "noExplicitAny": "warn",
        "noExportsInTest": "error",
        "noExtraNonNullAssertion": "error",
        "noFallthroughSwitchClause": "error",
        "noFunctionAssign": "error",
        "noGlobalAssign": "error",
        "noGlobalIsFinite": "error",
        "noGlobalIsNan": "error",
        "noImportAssign": "error",
        "noMisleadingCharacterClass": "error",
        "noMisleadingInstantiator": "error",
        "noMisrefactoredShorthandAssign": "error",
        "noPrototypeBuiltins": "warn",
        "noRedeclare": "error",
        "noRedundantUseStrict": "off",
        "noSelfCompare": "error",
        "noShadowRestrictedNames": "error",
        "noSuspiciousSemicolonInJsx": "error",
        "noThenProperty": "error",
        "noUnsafeNegation": "error",
        "useDefaultSwitchClauseLast": "error",
        "useGetterReturn": "error",
        "useIsArray": "error",
        "useNamespaceKeyword": "error",
        "useValidTypeof": "error"
      },
      "nursery": {
        "useSortedClasses": {
          "level": "error",
          "fix": "unsafe",
          "options": {
            "attributes": ["className", "tw"],
            "functions": ["tw"]
          }
        }
      }
    }
  },
  "formatter": {
    "enabled": true,
    "formatWithErrors": true,
    "indentStyle": "space",
    "indentWidth": 2,
    "lineEnding": "lf",
    "lineWidth": 120,
    "attributePosition": "auto"
  },
  "organizeImports": {
    "enabled": true
  },
  "javascript": {
    "globals": [],
    "parser": {
      "unsafeParameterDecoratorsEnabled": true
    },
    "jsxRuntime": "reactClassic",
    "formatter": {
      "quoteStyle": "single",
      "jsxQuoteStyle": "double",
      "quoteProperties": "asNeeded",
      "trailingCommas": "all",
      "semicolons": "always",
      "arrowParentheses": "always",
      "bracketSpacing": true,
      "bracketSameLine": false,
      "attributePosition": "auto"
    }
  },
  "json": {
    "parser": {
      "allowComments": true
    },
    "formatter": {
      "trailingCommas": "none",
      "indentStyle": "space",
      "indentWidth": 2
    }
  },
  "overrides": [
    {
      "include": ["package.json", "_package.json"],
      "formatter": {
        "lineWidth": 1
      }
    }
  ]
}

Playground link

https://biomejs.dev/playground/?bracketSameLine=true&lintRules=all&code=aQBtAHAAbwByAHQAIABSAGUAYQBjAHQAIABmAHIAbwBtACAAJwByAGUAYQBjAHQAJwA7AAoACgBjAG8AbgBzAHQAIABBAHAAcAAgAD0AIAAoACkAIAA9AD4AIAB7AAoAIAAgAGMAbwBuAHMAdAAgAGwAaQBzAHQAVAB5AHAAZQAgAD0AIAAnAHAAaQBjAHQAdQByAGUALQBjAGEAcgBkACcAOwAKACAAIAByAGUAdAB1AHIAbgAgADwAZABpAHYAIABjAGwAYQBzAHMATgBhAG0AZQA9AHsAYABtAC0AdwBlAGIAcwBlAHMAcwBpAG8AbgAtAHUAcABsAG8AYQBkAGwAaQBzAHQAIABmAGkAcwBoAGQALQB1AHAAbABvAGEAZAAtAGwAaQBzAHQALQAkAHsAbABpAHMAdABUAHkAcABlAH0AYAB9AD4AYQBwAHAAPAAvAGQAaQB2AD4AOwAKAH0AOwAKAAoAZQB4AHAAbwByAHQAIABkAGUAZgBhAHUAbAB0ACAAQQBwAHAAOwAKAA%3D%3D

Code of Conduct

  • I agree to follow Biome's Code of Conduct
@hangaoke1 hangaoke1 changed the title useSortedClasses lint error with Template literals πŸ“ <TITLE> useSortedClasses lint error with Template literals Jul 9, 2024
@hangaoke1 hangaoke1 changed the title useSortedClasses lint error with Template literals πŸ› useSortedClasses lint error with Template literals Jul 9, 2024
@ematipico
Copy link
Member

Providing a fix for this use case will be extremely challenging, almost impossible.

What's the expected and correct fix?

@hangaoke1
Copy link
Contributor Author

Maybe

 <div className={`fishd-upload-list-${listType} m-websession-uploadlist`}>app</div>

But ,Now it break fishd-upload-list-${listType}

@hangaoke1
Copy link
Contributor Author

hangaoke1 commented Jul 9, 2024

image

I think it maybe need handle JsTemplateElementList? but unfortunately I am just start to learn

@ematipico
Copy link
Member

The rule does handle template literals, however there's a limitation of what the rule can do and that's one of them.

@hangaoke1
Copy link
Contributor Author

hangaoke1 commented Jul 10, 2024

The rule does handle template literals, however there's a limitation of what the rule can do and that's one of them.

Hello buddy, I think it is possible by dealing with JsTemplateExpression

1、Extract the template string content from JsTemplateExpression
2、Sort string content
3、Rebuild JsTemplateExpression with make::js_template_expression (Perhaps biome provides an easier way to generate expression nodes from string)
4、Replace node in rule action

@ematipico
Copy link
Member

That's not what I'm talking about. Can the tailwind plugin fix your case?

@hangaoke1
Copy link
Contributor Author

hangaoke1 commented Jul 10, 2024

That's not what I'm talking about. Can the tailwind plugin fix your case?

Test in prettier-plugin-tailwindcss

image

It has special logic in sortTemplateLiteral,and fishd-upload-list- will be filter

https://github.com/tailwindlabs/prettier-plugin-tailwindcss/blob/main/src/index.ts#L538

@damianobarbati
Copy link

@ematipico sorry but I can't understand if tailwind sorting of classes is enabled and handled out of the box when using Biome.
In my monorepo project I don't see it working, but from the convos here on github (like this one) I'm assuming yes.

I also tried moving tailwind.config.ts from the /package/webapp folder into /root folder but nothing.

Can you point me out to relevant documentation? I only found this https://biomejs.dev/linter/rules/use-sorted-classes/#important-notes.

@ematipico
Copy link
Member

This rule has been flagged with an unsafe fix, hence it's only fixable via CLI using the --unsafe option, or using the "Quick fix" pop up that VSCode provides.

You're free to change the severity of the fix. The lint rule page provides useful links at the bottom of the page. One of them is this one: https://biomejs.dev/linter/#configure-the-rule-fix

I advise you to read more about how our linter works, it's different from ESLint

@damianobarbati
Copy link

@ematipico I managed to have the sort working, marking as "safe" and letting webstorm handling it on save as I had with eslint, grazie!

As reference for others:

{
  "$schema": "https://biomejs.dev/schemas/1.8.3/schema.json",
  "organizeImports": {
    "enabled": true
  },
  "formatter": {
    "indentStyle": "space",
    "indentWidth": 2,
    "lineWidth": 160,
    "lineEnding": "lf"
  },
  "linter": {
    "enabled": true,
    "rules": {
      "recommended": true,
      "a11y": {
        "recommended": false
      },
      "suspicious": {
        "recommended": false
      },
      "nursery": {
        "useSortedClasses": {
          "level": "error",
          "fix": "safe",
          "options": {
            "attributes": ["className"],
            "functions": ["cx"]
          }
        }
      }
    }
  }
}

hangaoke1 pushed a commit to hangaoke1/biome that referenced this issue Aug 12, 2024
hangaoke1 pushed a commit to hangaoke1/biome that referenced this issue Dec 4, 2024
ematipico added a commit that referenced this issue Dec 5, 2024
Co-authored-by: ιŸ©ι«˜ι’Ά <hangaoke@corp.netease.com>
Co-authored-by: Emanuele Stoppa <my.burning@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants