headwind icon indicating copy to clipboard operation
headwind copied to clipboard

Here is a regex that works for React and Preact JSX/TSX "class" and "className" with + without brackets =)

Open GavinRay97 opened this issue 4 years ago • 7 comments

Had a friend who writes React ask about this and helped him figure out a working regex, here it is:

"headwind.classRegex": {
  "javascriptreact": "(?:\\b(?:class|className)?\\s*=\\s*{?[\\\"\\']([_a-zA-Z0-9\\s\\-\\:/]+)[\\\"\\']}?)",
  "typescriptreact": "(?:\\b(?:class|className)?\\s*=\\s*{?[\\\"\\']([_a-zA-Z0-9\\s\\-\\:/]+)[\\\"\\']}?)"
}

headwind-regex

GavinRay97 avatar Jul 11 '20 02:07 GavinRay97

@GavinRay97 this solved my problem thank you

aeonthread avatar Jul 11 '20 03:07 aeonthread

And for twin.macro while we’re at it:

{
  "headwind.classRegex": {
    "typescriptreact": "(?:\\b(?:class|className|tw)?\\.?\\w?\\s*=*\\s*{?[\\\"\\'\\`]([_a-zA-Z0-9\\s\\-\\:/]+)[\\\"\\'\\`]}?)",
    "javascriptreact": "(?:\\b(?:class|className|tw)?\\.?\\w?\\s*=*\\s*{?[\\\"\\'\\`]([_a-zA-Z0-9\\s\\-\\:/]+)[\\\"\\'\\`]}?)"
  }
}

The debugging example in the README is super helpful and the only thing after that is escaping the regex.

jlarmstrongiv avatar Feb 02 '21 17:02 jlarmstrongiv

Here's a slightly more full-featured regex for twin.macro:

"headwind.classRegex": {
	"javascript": "(?:\\b(?:class|className|tw)(?:=(?:{\\s*)?)?(?:\\.\\w*)?(?:\\(\\s*\\w*\\s*\\))?[\\\"\\'\\`]([\\w\\s\\-\\:\\[\\]]+)[\\\"\\'\\`]}?)",
	"javascriptreact": "(?:\\b(?:class|className|tw)(?:=(?:{\\s*)?)?(?:\\.\\w*)?(?:\\(\\s*\\w*\\s*\\))?[\\\"\\'\\`]([\\w\\s\\-\\:\\[\\]]+)[\\\"\\'\\`]}?)",
	"typescript": "(?:\\b(?:class|className|tw)(?:=(?:{\\s*)?)?(?:\\.\\w*)?(?:\\(\\s*\\w*\\s*\\))?[\\\"\\'\\`]([\\w\\s\\-\\:\\[\\]]+)[\\\"\\'\\`]}?)",
	"typescriptreact": "(?:\\b(?:class|className|tw)(?:=(?:{\\s*)?)?(?:\\.\\w*)?(?:\\(\\s*\\w*\\s*\\))?[\\\"\\'\\`]([\\w\\s\\-\\:\\[\\]]+)[\\\"\\'\\`]}?)"
},

I'm new to regex, so I just want to break it down (more for my sanity that anything else):

  • (?:) is a non-capturing group, which means it should attempt to match the contents, but not return them.
  • (?:class|className|tw) matches class, className, or tw.
  • (?:=(?:{\s*)?)? optionally matches an = followed by an optional { followed by optional whitespace (i.e., tw={ or - tw={ ).
  • (?:\.\w*)? optionally matches a . followed by any number of letters (i.e., tw.div).
  • (?:\(\s*\w*\s*\))? optionally matches a ( followed by optional whitespace then any number of letters then more optional whitespace and a ) (i.e., tw(div) or tw( div )).
  • [\"\'\`] matches a ", ', or `.
  • ([\w\s\-\:\[\]]+) matches any number of letters, whitespace, hyphens, and square brackets (i.e., all of the tailwind classes) and returns them.
  • }? optionally matches the closing } when that's needed.

j0hnm4r5 avatar Mar 11 '21 18:03 j0hnm4r5

That regex is wonderful, thank you @j0hnm4r5! But there's a few problems with it:

  • it doesn't work for interpolated strings
  • it doesn't support slashes like h-1/2
  • it doesn't support dash prefixes like -top-0.5
  • it doesn't support periods like right-1.5

Here's one that fixes these issues:

  "headwind.classRegex": {
    "javascript": "(?:\\b(?:class|className|tw)(?:=(?:{\\s*)?)?(?:\\.\\w*)?(?:\\(\\s*\\w*\\s*\\))?[\\\"\\'\\`]((?:[\\w\\s\\-\\/\\:\\.\\[\\]]|\\$\\{(.*?)\\})+)[\\\"\\'\\`]}?)",
    "javascriptreact": "(?:\\b(?:class|className|tw)(?:=(?:{\\s*)?)?(?:\\.\\w*)?(?:\\(\\s*\\w*\\s*\\))?[\\\"\\'\\`]((?:[\\w\\s\\-\\/\\:\\.\\[\\]]|\\$\\{(.*?)\\})+)[\\\"\\'\\`]}?)",
    "typescript": "(?:\\b(?:class|className|tw)(?:=(?:{\\s*)?)?(?:\\.\\w*)?(?:\\(\\s*\\w*\\s*\\))?[\\\"\\'\\`]((?:[\\w\\s\\-\\/\\:\\.\\[\\]]|\\$\\{(.*?)\\})+)[\\\"\\'\\`]}?)",
    "typescriptreact": "(?:\\b(?:class|className|tw)(?:=(?:{\\s*)?)?(?:\\.\\w*)?(?:\\(\\s*\\w*\\s*\\))?[\\\"\\'\\`]((?:[\\w\\s\\-\\/\\:\\.\\[\\]]|\\$\\{(.*?)\\})+)[\\\"\\'\\`]}?)"
  },

Here is the regexr for the new regex with all passing tests:

bbugh avatar Jun 21 '21 17:06 bbugh

^ Does this regex sort JIT mode correctly, e.g. w-[10px]?

KnifeFed avatar Oct 19 '21 19:10 KnifeFed

@KnifeFed no, headwind itself doesn't support JIT.

bbugh avatar Jun 15 '22 20:06 bbugh

Thank you so much for your regex @bbugh. I'm not a regexpert (aha) but something is missing in your regex:

When some tailwind classes are set as important, the regex doesn't work... (I'm working on tsx files)

Example:

<div className={"!class1 !class2 ..."}></div>

Hope you could fix it ! Thank you again :)

Edit: ~~I think I fixed it myself:~~

- (?:\b(?:class|className|tw)(?:=(?:{\s*)?)?(?:\.\w*)?(?:\(\s*\w*\s*\))?[\"\'\`]((?:[\w\s\-\/\:\.\[\]]|\$\{(.*?)\})+)[\"\'\`]}?)
+ (?:\b(?:class|className|tw)(?:=(?:{\s*)?)?(?:\.\w*)?(?:\(\s*\w*\s*\))?[\"\'\`]((?:[\w\s\-\/\:\.\[\]]\!?|\$\{(.*?)\}))+[\"\'\`]}?)
  "headwind.classRegex": {
    "javascript": "/(?:\\b(?:class|className|tw)(?:=(?:{\\s*)?)?(?:\\.\\w*)?(?:\\(\\s*\\w*\\s*\\))?[\\\"\\'\\`]((?:[\\w\\s\\-\\/\\:\\.\\[\\]]\\!?|\\$\\{(.*?)\\}))+[\\\"\\'\\`]}?)/",
    "javascriptreact": "/(?:\\b(?:class|className|tw)(?:=(?:{\\s*)?)?(?:\\.\\w*)?(?:\\(\\s*\\w*\\s*\\))?[\\\"\\'\\`]((?:[\\w\\s\\-\\/\\:\\.\\[\\]]\\!?|\\$\\{(.*?)\\}))+[\\\"\\'\\`]}?)/",
    "typescript": "/(?:\\b(?:class|className|tw)(?:=(?:{\\s*)?)?(?:\\.\\w*)?(?:\\(\\s*\\w*\\s*\\))?[\\\"\\'\\`]((?:[\\w\\s\\-\\/\\:\\.\\[\\]]\\!?|\\$\\{(.*?)\\}))+[\\\"\\'\\`]}?)/",
    "typescriptreact": "/(?:\\b(?:class|className|tw)(?:=(?:{\\s*)?)?(?:\\.\\w*)?(?:\\(\\s*\\w*\\s*\\))?[\\\"\\'\\`]((?:[\\w\\s\\-\\/\\:\\.\\[\\]]\\!?|\\$\\{(.*?)\\}))+[\\\"\\'\\`]}?)/"
  },

Edit 2: I think it doesn't work

valflrt avatar Jan 08 '23 15:01 valflrt