Skip to content

Conversation

@eneroth
Copy link
Contributor

@eneroth eneroth commented Jun 18, 2025

Summary

Taking a shot at fixing my own complaint from #18336.

Added failing test and fix for extracting classes containing a pseudo-class from Clojure keywords. Eg., :hover:text -> "hover:text". This would previously produce ["hover", "text"].

Test plan

  • Add a failing test.
  • Verify that it fails with cargo test.
  • Add fix.
  • Verify that cargo test has no further complaints.

ATT: @RobinMalfait

@eneroth eneroth requested a review from a team as a code owner June 18, 2025 14:28
@thecrypticace
Copy link
Contributor

thecrypticace commented Jun 18, 2025

o/ I'm fairly unfamiliar with ClojureScript (so maybe there's an obvious answer) but is there a reason to use keyword literals for class lists rather than strings?

@thecrypticace
Copy link
Contributor

Like to my knowledge you can't write classes like 2xl:flex with that since keywords can't start with a number (if I'm reading the docs right anyway…)

@eneroth
Copy link
Contributor Author

eneroth commented Jun 18, 2025

@thecrypticace No worries!

There are a lot of different reasons why keywords are preferred in Clojure, but the most basic one comes down to types: precisely because it's not a string, but captures something symbolic. It disambiguates, in your editor, and at runtime, from things you actually do want to capture in strings: names, text, etc. So, a combination of being both general enough, and specific enough, makes it useful.

Other than that, keywords are interned: the keyword :hello and the keyword :hello are identical in memory, which has all kinds of implications.

A common DSL for writing HTML and CSS within the Clojure community is called Hiccup, and looks like this:

[:p
 [:span.bg-white "Hello"]
 [:span#unique.text-red-500 "World"]]

The semantics are :<tag>#<id>.<class-1>.<class-2>….<class-n>.

As for numbers, the intention was that eg. :2 wasn't supported, but a bug in an early Clojure version made it possible to use it. And Clojure goes to extreme lengths to never backwards compatibility, so it's in fact supported.

@thecrypticace
Copy link
Contributor

Ah okay that's helpful — thanks! I left a comment. I think you mean't variant and not pseudo-class (e.g. sm:dark:… are variants in Tailwind CSS terminology. Sometimes they map to pseudo class but not always. (media queries, container queries, other selectors, etc…)

Co-authored-by: Jordan Pittman <jordan@cryptica.me>
@thecrypticace thecrypticace changed the title Add test and fix for pseudo-class extraction from Clojure/Script keywords Jun 18, 2025
@thecrypticace thecrypticace merged commit f4a7eea into tailwindlabs:main Jun 18, 2025
7 checks passed
@thecrypticace
Copy link
Contributor

Thanks! This will be in the next release. You can use our insiders build before then to test it:

npm install tailwindcss@insiders @tailwindcss/cli@insiders

It may take about 15–30m before it's built and available on NPM.

@eneroth
Copy link
Contributor Author

eneroth commented Jun 18, 2025

Many thanks @thecrypticace!

@eneroth eneroth deleted the fix/issue-18336 branch June 18, 2025 16:44
thecrypticace added a commit that referenced this pull request Jun 30, 2025
…#18345)

## Summary

In a form like, 

```clojure 
(if condition :bg-white :bg-black)
```

`:bg-black` will fail to extract, while `:bg-white` is extracted as
expected. This PR fixes this case, implements more comprehensive
candidate filtering, and supersedes a previous PR.

Having recently submitted a PR for handling another special case with
Clojure keywords (the presence of `:` inside of keywords), I thought it
best to invert the previous strategy: Instead of handling special cases
one by one, consume keywords according to the Clojure reader spec.
Consume nothing else, other than strings.

Because of this, this PR is a tad more invasive rather than additive,
for which I apologize. The strategy is this:
- Strings begin with a `"` and ends with an unescaped `"`. Consume
everything between these delimiters (existing case).
- Keywords begin with `:`, and end with whitespace, or one out of a
small set of specific reserved characters. Everything else is a valid
character in a keyword. Consume everything between these delimiters, and
apply the class splitting previously contained in the outer loop. My
previous special case handling of `:` inside of keywords in #18338 is
now redundant (and is removed), as this is a more general solution.
- Discard _everything else_. 

I'm hoping that a strategy that is based on Clojure's definition of
strings and keywords will pre-empt any further issues with edge cases.

Closes #18344.

## Test plan
- Added failing tests.
- `cargo test` -> failure
- Added fix
- `cargo test` -> success

---------

Co-authored-by: Jordan Pittman <jordan@cryptica.me>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

2 participants