You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This issue delves into some of the issues surrounding why the parser doesn't properly handle supports-[content:"("]:grid, first explored in #13596. This specific case turned out to be quite the rabbit hole.
From what I can tell, Tailwind's Rust parser runs into issues related to its quote_stack and bracket_stack when encountering a construct like '('.
None of these process correctly, apparently for this same reason:
I can think of a few potential solutions, all of which come with trade-offs:
We could interpret everything after an open quote as a string until we hit the closing quote. This would break some things, but we'd be able to handle brackets or quotes within strings.
We could always ignore bracket_stack characters within quote_stack characters, but not ignore quote_stack characters within bracket_stack characters.
Specifically enforce escaping characters related to quote_stack and bracket_stack when they're in a string context. This would mean that supports-[content:"("] would need to be written as supports-[content:"\("] to work.
supports-[content:'('] -> supports-[content:'\(']
supports-[content:'['] -> supports-[content:'\[']
supports-[content:'"'] -> supports-[content:'\"']
supports-[content:\"'\"] -> supports-[content:\"\'\"]
☝🏼 this last one might be problematic for more reasons than one, related to escaping the same quotes used when opening the class attribute as well as escaping the inner quote_stack character
We could strictly enforce escaping special characters like these in string contexts.
This might be most consistent and with common escape patterns, but it would also be one of the most disruptive solutions.
In the case of my Multi plugin, for example, I was surprised—when chatting with @RobinMalfait (see discussion)—to discover that nesting quotes in arbitrary values is not only supported but that they appear to be infinitely nestable.
If escapes were required to resolve this issue, each level of nesting might require a greater level of escape characters, which could get out of hand quickly. For example, the above would need to be written like this:
Of course, it would be convenient for me not to need to update my plugin(s) with new syntax and safety measures again, and such escaping would probably render my plugin too cumbersome to justify using. However, greater parity with CSS is probably a higher and more evergreen standard here.
Simply wrapping the arbitrary value in quotes was an easy fix, but the magic around it allowing nested quotes may be the culprit behind "(" not working, to some degree.
I'm new to Rust, so all of this is "to the best of my current knowledge" from what I could grok reading through the parser. I also consulted a colleague who is more experienced with Rust to corroborate my findings and theories, and they came to roughly the same conclusions.
The text was updated successfully, but these errors were encountered:
Actually had nothing to do with the Rust stuff — if you add this test to the Rust parser you can see it passes:
#[test]
fn it_should_keep_candidates_with_brackets_in_arbitrary_values_inside_quotes() {
let candidates = run("content-['hello_[_]_world']", false);
assert_eq!(candidates, vec!["content-['hello_[_]_world']"]);
+ let candidates = run("supports-[content:\"(\")]:grid", false);+ assert_eq!(candidates, vec!["supports-[content:\"(\")]:grid"]);
}
The Rust parser's job is just to extract strings from template files and pass those potential class name strings to the JS engine, so if it successfully pulls out the string then the problem is not in Rust but in JS somewhere 👍
Tailwind Play doesn't run any of the Rust code at all either, so when something can be reproduced in Play it's very likely a JS engine bug rather than a bug in the Rust parser.
Technical Configuration
Reproduction URL
The accepted test results from #13596
Describe your issue
This issue delves into some of the issues surrounding why the parser doesn't properly handle
supports-[content:"("]:grid
, first explored in #13596. This specific case turned out to be quite the rabbit hole.From what I can tell, Tailwind's Rust parser runs into issues related to its
quote_stack
andbracket_stack
when encountering a construct like'('
.None of these process correctly, apparently for this same reason:
supports-[content:'(']
supports-[content:'[']
supports-[content:'"']
supports-[content:"'"]
This Tailwind Play example demonstrates the issue I'm describing: https://play.tailwindcss.com/EAhSfQFfTa
I can think of a few potential solutions, all of which come with trade-offs:
We could interpret everything after an open quote as a string until we hit the closing quote. This would break some things, but we'd be able to handle brackets or quotes within strings.
We could always ignore
bracket_stack
characters withinquote_stack
characters, but not ignorequote_stack
characters withinbracket_stack
characters.Specifically enforce escaping characters related to
quote_stack
andbracket_stack
when they're in a string context. This would mean thatsupports-[content:"("]
would need to be written assupports-[content:"\("]
to work.supports-[content:'(']
->supports-[content:'\(']
supports-[content:'[']
->supports-[content:'\[']
supports-[content:'"']
->supports-[content:'\"']
supports-[content:\"'\"]
->supports-[content:\"\'\"]
☝🏼 this last one might be problematic for more reasons than one, related to escaping the same quotes used when opening the
class
attribute as well as escaping the innerquote_stack
characterWe could strictly enforce escaping special characters like these in string contexts.
This might be most consistent and with common escape patterns, but it would also be one of the most disruptive solutions.
In the case of my Multi plugin, for example, I was surprised—when chatting with @RobinMalfait (see discussion)—to discover that nesting quotes in arbitrary values is not only supported but that they appear to be infinitely nestable.
In other words, this works:
If escapes were required to resolve this issue, each level of nesting might require a greater level of escape characters, which could get out of hand quickly. For example, the above would need to be written like this:
Of course, it would be convenient for me not to need to update my plugin(s) with new syntax and safety measures again, and such escaping would probably render my plugin too cumbersome to justify using. However, greater parity with CSS is probably a higher and more evergreen standard here.
Simply wrapping the arbitrary value in quotes was an easy fix, but the magic around it allowing nested quotes may be the culprit behind
"("
not working, to some degree.I'm new to Rust, so all of this is "to the best of my current knowledge" from what I could grok reading through the parser. I also consulted a colleague who is more experienced with Rust to corroborate my findings and theories, and they came to roughly the same conclusions.
The text was updated successfully, but these errors were encountered: