Skip to content

Commit 0884e29

Browse files
authored
fix(noTailwindArbitraryValue): use shared syntax query (#11860)
1 parent 17a2560 commit 0884e29

22 files changed

Lines changed: 130 additions & 353 deletions

File tree

‎.changeset/loose-hats-cough.md‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@biomejs/biome": patch
3+
---
4+
5+
Removed the `attributes` and `functions` options from the nursery rule [`noTailwindArbitraryValue`](https://biomejs.dev/linter/rules/no-tailwind-arbitrary-value/). The rule now uses the same Tailwind detection as [`useTailwindShorthandClasses`](https://biomejs.dev/linter/rules/use-tailwind-shorthand-classes/).
Lines changed: 10 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1+
use crate::tailwind::host_range;
12
use biome_analyze::{
2-
Ast, Rule, RuleDiagnostic, RuleDomain, RuleSource, context::RuleContext, declare_lint_rule,
3+
Rule, RuleDiagnostic, RuleDomain, RuleSource, context::RuleContext, declare_lint_rule,
34
};
45
use biome_console::markup;
5-
use biome_html_syntax::{AnyHtmlAttributeInitializer, HtmlAttribute, inner_string_text};
6+
use biome_html_syntax::HtmlAttribute;
67
use biome_rowan::{TextRange, TextSize};
78
use biome_rule_options::no_tailwind_arbitrary_value::NoTailwindArbitraryValueOptions;
8-
use biome_tailwind_parser::parse_tailwind;
9+
use biome_tailwind_logic::syntax_service::TailwindSyntax;
910
use biome_tailwind_syntax::lint_utils::arbitrary_ranges;
1011

1112
declare_lint_rule! {
@@ -42,29 +43,6 @@ declare_lint_rule! {
4243
/// <div class="[&:nth-child(3)]:px-2"></div>
4344
/// ```
4445
///
45-
/// ## Options
46-
///
47-
/// By default, this rule checks the `class` attribute. The `attributes`
48-
/// option adds more HTML attributes to check.
49-
///
50-
/// ```json,options
51-
/// {
52-
/// "options": {
53-
/// "attributes": ["classList"]
54-
/// }
55-
/// }
56-
/// ```
57-
///
58-
/// ```html,use_options,expect_diagnostic
59-
/// <div classList="w-[400px]"></div>
60-
/// ```
61-
///
62-
/// ### attributes
63-
///
64-
/// Additional HTML attribute names to check.
65-
///
66-
/// Default: `[]` (the `class` attribute is always checked).
67-
///
6846
pub NoTailwindArbitraryValue {
6947
version: "2.5.7",
7048
name: "noTailwindArbitraryValue",
@@ -76,48 +54,17 @@ declare_lint_rule! {
7654
}
7755

7856
impl Rule for NoTailwindArbitraryValue {
79-
type Query = Ast<HtmlAttribute>;
57+
type Query = TailwindSyntax<HtmlAttribute>;
8058
type State = TextRange;
8159
type Signals = Vec<TextRange>;
8260
type Options = NoTailwindArbitraryValueOptions;
8361

8462
fn run(ctx: &RuleContext<Self>) -> Self::Signals {
85-
let attribute = ctx.query();
86-
let options = ctx.options();
87-
88-
let Some(name) = attribute
89-
.name()
90-
.ok()
91-
.and_then(|name| name.value_token().ok())
92-
.map(|token| token.token_text_trimmed())
93-
else {
94-
return vec![];
95-
};
96-
97-
if !is_html_class_attribute(name.text(), options) {
98-
return vec![];
99-
}
100-
101-
let Some(initializer) = attribute.initializer() else {
102-
return vec![];
103-
};
104-
let Ok(AnyHtmlAttributeInitializer::HtmlString(html_string)) = initializer.value() else {
105-
return vec![];
106-
};
107-
let Ok(token) = html_string.value_token() else {
108-
return vec![];
109-
};
110-
111-
let text = inner_string_text(&token);
112-
if !text.text().contains('[') {
113-
return vec![];
114-
}
115-
116-
// HTML attribute values are always quoted per spec
117-
let content_start = token.text_trimmed_range().start() + TextSize::from(1);
118-
119-
let parse = parse_tailwind(text.text());
120-
arbitrary_ranges(&parse.tree().candidates(), content_start)
63+
let query = ctx.query();
64+
arbitrary_ranges(&query.tailwind_root().candidates(), TextSize::from(0))
65+
.into_iter()
66+
.filter_map(|range| host_range(query.node(), range))
67+
.collect()
12168
}
12269

12370
fn diagnostic(_ctx: &RuleContext<Self>, range: &Self::State) -> Option<RuleDiagnostic> {
@@ -136,13 +83,3 @@ impl Rule for NoTailwindArbitraryValue {
13683
)
13784
}
13885
}
139-
140-
fn is_html_class_attribute(name: &str, options: &NoTailwindArbitraryValueOptions) -> bool {
141-
name.eq_ignore_ascii_case("class")
142-
|| options
143-
.attributes
144-
.iter()
145-
.flatten()
146-
.any(|attribute| attribute.as_ref().eq_ignore_ascii_case(name))
147-
}
148-

‎crates/biome_html_analyze/tests/specs/nursery/noTailwindArbitraryValue/invalid.html‎

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,4 @@
55
<div class="hover:w-[400px]"></div>
66
<div class="text-red-500/[0.31]"></div>
77
<div class="[color:red]"></div>
8-
<div classList="p-[10px]"></div>
98
<div CLASS="m-[2px]"></div>
10-
<div CLASSLIST="p-[10px]"></div>

‎crates/biome_html_analyze/tests/specs/nursery/noTailwindArbitraryValue/invalid.html.snap‎

Lines changed: 16 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,15 @@ expression: invalid.html
1111
<div class="hover:w-[400px]"></div>
1212
<div class="text-red-500/[0.31]"></div>
1313
<div class="[color:red]"></div>
14-
<div classList="p-[10px]"></div>
1514
<div CLASS="m-[2px]"></div>
16-
<div CLASSLIST="p-[10px]"></div>
1715
1816
```
1917

2018
# Diagnostics
2119
```
2220
invalid.html:2:15 lint/nursery/noTailwindArbitraryValue ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
2321
24-
× Found an arbitrary value in a Tailwind CSS class.
22+
i Found an arbitrary value in a Tailwind CSS class.
2523
2624
1 │ <!-- should generate diagnostics -->
2725
> 2 │ <div class="w-[400px]"></div>
@@ -41,7 +39,7 @@ invalid.html:2:15 lint/nursery/noTailwindArbitraryValue ━━━━━━━━
4139
```
4240
invalid.html:3:18 lint/nursery/noTailwindArbitraryValue ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
4341
44-
× Found an arbitrary value in a Tailwind CSS class.
42+
i Found an arbitrary value in a Tailwind CSS class.
4543
4644
1 │ <!-- should generate diagnostics -->
4745
2 │ <div class="w-[400px]"></div>
@@ -62,7 +60,7 @@ invalid.html:3:18 lint/nursery/noTailwindArbitraryValue ━━━━━━━━
6260
```
6361
invalid.html:4:19 lint/nursery/noTailwindArbitraryValue ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
6462
65-
× Found an arbitrary value in a Tailwind CSS class.
63+
i Found an arbitrary value in a Tailwind CSS class.
6664
6765
2 │ <div class="w-[400px]"></div>
6866
3 │ <div class="text-[#555] bg-white"></div>
@@ -83,7 +81,7 @@ invalid.html:4:19 lint/nursery/noTailwindArbitraryValue ━━━━━━━━
8381
```
8482
invalid.html:5:21 lint/nursery/noTailwindArbitraryValue ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
8583
86-
× Found an arbitrary value in a Tailwind CSS class.
84+
i Found an arbitrary value in a Tailwind CSS class.
8785
8886
3 │ <div class="text-[#555] bg-white"></div>
8987
4 │ <div class="max-h-[calc(100dvh-40px)]"></div>
@@ -104,14 +102,14 @@ invalid.html:5:21 lint/nursery/noTailwindArbitraryValue ━━━━━━━━
104102
```
105103
invalid.html:6:26 lint/nursery/noTailwindArbitraryValue ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
106104
107-
× Found an arbitrary value in a Tailwind CSS class.
105+
i Found an arbitrary value in a Tailwind CSS class.
108106
109107
4 │ <div class="max-h-[calc(100dvh-40px)]"></div>
110108
5 │ <div class="hover:w-[400px]"></div>
111109
> 6 │ <div class="text-red-500/[0.31]"></div>
112110
│ ^^^^^^
113111
7 │ <div class="[color:red]"></div>
114-
8 │ <div classList="p-[10px]"></div>
112+
8 │ <div CLASS="m-[2px]"></div>
115113
116114
i Arbitrary values bypass Tailwind's theme configuration, defeating design-system consistency and making styles harder to refactor.
117115
@@ -125,14 +123,14 @@ invalid.html:6:26 lint/nursery/noTailwindArbitraryValue ━━━━━━━━
125123
```
126124
invalid.html:7:13 lint/nursery/noTailwindArbitraryValue ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
127125
128-
× Found an arbitrary value in a Tailwind CSS class.
126+
i Found an arbitrary value in a Tailwind CSS class.
129127
130128
5 │ <div class="hover:w-[400px]"></div>
131129
6 │ <div class="text-red-500/[0.31]"></div>
132130
> 7 │ <div class="[color:red]"></div>
133131
│ ^^^^^^^^^^^
134-
8 │ <div classList="p-[10px]"></div>
135-
9 │ <div CLASS="m-[2px]"></div>
132+
8 │ <div CLASS="m-[2px]"></div>
133+
9 │
136134
137135
i Arbitrary values bypass Tailwind's theme configuration, defeating design-system consistency and making styles harder to refactor.
138136
@@ -144,57 +142,15 @@ invalid.html:7:13 lint/nursery/noTailwindArbitraryValue ━━━━━━━━
144142
```
145143

146144
```
147-
invalid.html:8:19 lint/nursery/noTailwindArbitraryValue ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
145+
invalid.html:8:15 lint/nursery/noTailwindArbitraryValue ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
148146
149-
× Found an arbitrary value in a Tailwind CSS class.
147+
i Found an arbitrary value in a Tailwind CSS class.
150148
151-
6 │ <div class="text-red-500/[0.31]"></div>
152-
7 │ <div class="[color:red]"></div>
153-
> 8 │ <div classList="p-[10px]"></div>
154-
│ ^^^^^^
155-
9 │ <div CLASS="m-[2px]"></div>
156-
10 │ <div CLASSLIST="p-[10px]"></div>
157-
158-
i Arbitrary values bypass Tailwind's theme configuration, defeating design-system consistency and making styles harder to refactor.
159-
160-
i Use a named utility from your Tailwind configuration instead.
161-
162-
i This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information.
163-
164-
165-
```
166-
167-
```
168-
invalid.html:9:15 lint/nursery/noTailwindArbitraryValue ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
169-
170-
× Found an arbitrary value in a Tailwind CSS class.
171-
172-
7 │ <div class="[color:red]"></div>
173-
8 │ <div classList="p-[10px]"></div>
174-
> 9 │ <div CLASS="m-[2px]"></div>
175-
│ ^^^^^
176-
10 │ <div CLASSLIST="p-[10px]"></div>
177-
11 │
178-
179-
i Arbitrary values bypass Tailwind's theme configuration, defeating design-system consistency and making styles harder to refactor.
180-
181-
i Use a named utility from your Tailwind configuration instead.
182-
183-
i This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information.
184-
185-
186-
```
187-
188-
```
189-
invalid.html:10:19 lint/nursery/noTailwindArbitraryValue ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
190-
191-
× Found an arbitrary value in a Tailwind CSS class.
192-
193-
8 │ <div classList="p-[10px]"></div>
194-
9 │ <div CLASS="m-[2px]"></div>
195-
> 10 │ <div CLASSLIST="p-[10px]"></div>
196-
│ ^^^^^^
197-
11 │
149+
6 │ <div class="text-red-500/[0.31]"></div>
150+
7 │ <div class="[color:red]"></div>
151+
> 8 │ <div CLASS="m-[2px]"></div>
152+
│ ^^^^^
153+
9 │
198154
199155
i Arbitrary values bypass Tailwind's theme configuration, defeating design-system consistency and making styles harder to refactor.
200156

‎crates/biome_html_analyze/tests/specs/nursery/noTailwindArbitraryValue/invalid.options.json‎

Lines changed: 0 additions & 15 deletions
This file was deleted.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
<!-- should generate diagnostics -->
2+
<div class="hover:"></div>
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
---
2+
source: crates/biome_html_analyze/tests/spec_tests.rs
3+
expression: parse_errors.html
4+
---
5+
# Input
6+
```html
7+
<!-- should generate diagnostics -->
8+
<div class="hover:"></div>
9+
10+
```
11+
12+
# Diagnostics
13+
```
14+
parse_errors.html:2:13 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
15+
16+
× Expected a candidate but instead found 'hover:'.
17+
18+
1 │ <!-- should generate diagnostics -->
19+
> 2 │ <div class="hover:"></div>
20+
│ ^^^^^^
21+
3 │
22+
23+
i Expected a candidate here.
24+
25+
1 │ <!-- should generate diagnostics -->
26+
> 2 │ <div class="hover:"></div>
27+
│ ^^^^^^
28+
3 │
29+
30+
31+
```

‎crates/biome_html_analyze/tests/specs/nursery/noTailwindArbitraryValue/valid.html‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@
55
<div class="has-[:checked]:bg-red-500"></div>
66
<div classList="p-[10px]"></div>
77
<div className="w-[400px]"></div>
8+
<div CLASSLIST="p-[10px]"></div>

‎crates/biome_html_analyze/tests/specs/nursery/noTailwindArbitraryValue/valid.html.snap‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,6 @@ expression: valid.html
1111
<div class="has-[:checked]:bg-red-500"></div>
1212
<div classList="p-[10px]"></div>
1313
<div className="w-[400px]"></div>
14+
<div CLASSLIST="p-[10px]"></div>
1415
1516
```

0 commit comments

Comments
 (0)