Skip to content

Commit

Permalink
fix(lint/noDuplicateJsxProps): make the rule case-sensitive (#100)
Browse files Browse the repository at this point in the history
  • Loading branch information
Conaclos authored Aug 31, 2023
1 parent 2c8343c commit 2a9c8b0
Show file tree
Hide file tree
Showing 7 changed files with 72 additions and 81 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,15 @@ Read our [guidelines for writing a good changelog entry](https://github.com/biom

### Bug fixes

- Fix [#80](https://github.com/biomejs/biome/issues/95), making [noDuplicateJsxProps](https://biomejs.dev/lint/rules/noDuplicateJsxProps/) case-insensitive.

Some frameworks, such as Material UI, rely on the case-sensitivity of JSX properties.
For example, [TextField has two properties with the same name, but distinct cases](https://mui.com/material-ui/api/text-field/#TextField-prop-inputProps):

```jsx
<TextField inputLabelProps="" InputLabelProps=""></TextField>
```

- Fix [rome#4713](https://github.com/rome/tools/issues/4713).

Previously, [useTemplate](https://biomejs.dev/lint/rules/useTemplate/) made the following suggestion:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,16 +37,6 @@ declare_rule! {
}
}

fn push_attribute(
attr: JsxAttribute,
attributes: &mut HashMap<String, Vec<JsxAttribute>>,
) -> Option<()> {
let name = attr.name().ok()?.syntax().text_trimmed();
let name = name.to_string().to_lowercase();
attributes.entry(name).or_default().push(attr);
Some(())
}

impl Rule for NoDuplicateJsxProps {
type Query = Ast<AnyJsxElement>;
type State = (String, Vec<JsxAttribute>);
Expand All @@ -59,7 +49,12 @@ impl Rule for NoDuplicateJsxProps {
let mut defined_attributes: HashMap<String, Vec<JsxAttribute>> = HashMap::new();
for attribute in node.attributes() {
if let AnyJsxAttribute::JsxAttribute(attr) = attribute {
let _ = push_attribute(attr, &mut defined_attributes);
if let Ok(name) = attr.name() {
defined_attributes
.entry(name.text())
.or_default()
.push(attr);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
//Duplicate `name` property
<Hello name="John" name="John" />;

//Case insensitive case
<Hello name="John" Name="John" />;

//Case where property is repeated more than twice
<Hello name="John" name="John" name="John" />;

//Case with two duplicates
<Hello name="John" Name="John" lastname="Doe" lastname="Doe" />;
<Hello name="John" name="John" lastname="Doe" lastname="Doe" />;

<label xml:lang="en-US" xml:lang="en-US"></label>
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,11 @@ expression: invalid.jsx
//Duplicate `name` property
<Hello name="John" name="John" />;

//Case insensitive case
<Hello name="John" Name="John" />;

//Case where property is repeated more than twice
<Hello name="John" name="John" name="John" />;

//Case with two duplicates
<Hello name="John" Name="John" lastname="Doe" lastname="Doe" />;
<Hello name="John" name="John" lastname="Doe" lastname="Doe" />;

<label xml:lang="en-US" xml:lang="en-US"></label>

Expand All @@ -30,15 +27,15 @@ invalid.jsx:2:8 lint/suspicious/noDuplicateJsxProps ━━━━━━━━━
> 2 │ <Hello name="John" name="John" />;
│ ^^^^^^^^^^^
3 │
4 │ //Case insensitive case
4 │ //Case where property is repeated more than twice
i This attribute is assigned again here.
1 │ //Duplicate `name` property
> 2 │ <Hello name="John" name="John" />;
│ ^^^^^^^^^^^
3 │
4 │ //Case insensitive case
4 │ //Case where property is repeated more than twice
```
Expand All @@ -48,115 +45,93 @@ invalid.jsx:5:8 lint/suspicious/noDuplicateJsxProps ━━━━━━━━━
! This JSX property is assigned multiple times.
4 │ //Case insensitive case
> 5 │ <Hello name="John" Name="John" />;
4 │ //Case where property is repeated more than twice
> 5 │ <Hello name="John" name="John" name="John" />;
│ ^^^^^^^^^^^
6 │
7 │ //Case where property is repeated more than twice
7 │ //Case with two duplicates
i This attribute is assigned again here.
4 │ //Case insensitive case
> 5 │ <Hello name="John" Name="John" />;
4 │ //Case where property is repeated more than twice
> 5 │ <Hello name="John" name="John" name="John" />;
│ ^^^^^^^^^^^
6 │
7 │ //Case where property is repeated more than twice
```

```
invalid.jsx:8:8 lint/suspicious/noDuplicateJsxProps ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
! This JSX property is assigned multiple times.
7 │ //Case where property is repeated more than twice
> 8 │ <Hello name="John" name="John" name="John" />;
│ ^^^^^^^^^^^
9 │
10 │ //Case with two duplicates
i This attribute is assigned again here.
7 │ //Case where property is repeated more than twice
> 8 │ <Hello name="John" name="John" name="John" />;
│ ^^^^^^^^^^^
9 │
10 │ //Case with two duplicates
7 │ //Case with two duplicates
i This attribute is assigned again here.
7 │ //Case where property is repeated more than twice
> 8 │ <Hello name="John" name="John" name="John" />;
│ ^^^^^^^^^^^
9
10 │ //Case with two duplicates
4 │ //Case where property is repeated more than twice
> 5 │ <Hello name="John" name="John" name="John" />;
│ ^^^^^^^^^^^
6
7 │ //Case with two duplicates
```

```
invalid.jsx:11:8 lint/suspicious/noDuplicateJsxProps ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
invalid.jsx:8:8 lint/suspicious/noDuplicateJsxProps ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
! This JSX property is assigned multiple times.
10 │ //Case with two duplicates
> 11 │ <Hello name="John" Name="John" lastname="Doe" lastname="Doe" />;
7 │ //Case with two duplicates
> 8 │ <Hello name="John" name="John" lastname="Doe" lastname="Doe" />;
│ ^^^^^^^^^^^
12
13 │ <label xml:lang="en-US" xml:lang="en-US"></label>
9
10 │ <label xml:lang="en-US" xml:lang="en-US"></label>
i This attribute is assigned again here.
10 │ //Case with two duplicates
> 11 │ <Hello name="John" Name="John" lastname="Doe" lastname="Doe" />;
7 │ //Case with two duplicates
> 8 │ <Hello name="John" name="John" lastname="Doe" lastname="Doe" />;
│ ^^^^^^^^^^^
12
13 │ <label xml:lang="en-US" xml:lang="en-US"></label>
9
10 │ <label xml:lang="en-US" xml:lang="en-US"></label>
```

```
invalid.jsx:11:32 lint/suspicious/noDuplicateJsxProps ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
invalid.jsx:8:32 lint/suspicious/noDuplicateJsxProps ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
! This JSX property is assigned multiple times.
10 │ //Case with two duplicates
> 11 │ <Hello name="John" Name="John" lastname="Doe" lastname="Doe" />;
7 │ //Case with two duplicates
> 8 │ <Hello name="John" name="John" lastname="Doe" lastname="Doe" />;
│ ^^^^^^^^^^^^^^
12
13 │ <label xml:lang="en-US" xml:lang="en-US"></label>
9
10 │ <label xml:lang="en-US" xml:lang="en-US"></label>
i This attribute is assigned again here.
10 │ //Case with two duplicates
> 11 │ <Hello name="John" Name="John" lastname="Doe" lastname="Doe" />;
7 │ //Case with two duplicates
> 8 │ <Hello name="John" name="John" lastname="Doe" lastname="Doe" />;
│ ^^^^^^^^^^^^^^
12
13 │ <label xml:lang="en-US" xml:lang="en-US"></label>
9
10 │ <label xml:lang="en-US" xml:lang="en-US"></label>
```

```
invalid.jsx:13:8 lint/suspicious/noDuplicateJsxProps ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
invalid.jsx:10:8 lint/suspicious/noDuplicateJsxProps ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
! This JSX property is assigned multiple times.
11 │ <Hello name="John" Name="John" lastname="Doe" lastname="Doe" />;
12
> 13 │ <label xml:lang="en-US" xml:lang="en-US"></label>
8 │ <Hello name="John" name="John" lastname="Doe" lastname="Doe" />;
9
> 10 │ <label xml:lang="en-US" xml:lang="en-US"></label>
│ ^^^^^^^^^^^^^^^^
14
11
i This attribute is assigned again here.
11 │ <Hello name="John" Name="John" lastname="Doe" lastname="Doe" />;
12
> 13 │ <label xml:lang="en-US" xml:lang="en-US"></label>
8 │ <Hello name="John" name="John" lastname="Doe" lastname="Doe" />;
9
> 10 │ <label xml:lang="en-US" xml:lang="en-US"></label>
│ ^^^^^^^^^^^^^^^^
14
11
```
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,6 @@
<Hello firstname="John" lastname="Doe" />;

<label xml:lang="en-US" lang="en-US"></label>

//Case insensitive case
<Hello name="John" Name="John" />;
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ expression: valid.jsx

<label xml:lang="en-US" lang="en-US"></label>

//Case insensitive case
<Hello name="John" Name="John" />;

```


9 changes: 9 additions & 0 deletions website/src/pages/internals/changelog.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,15 @@ Read our [guidelines for writing a good changelog entry](https://github.com/biom

### Bug fixes

- Fix [#80](https://github.com/biomejs/biome/issues/95), making [noDuplicateJsxProps](https://biomejs.dev/lint/rules/noDuplicateJsxProps/) case-insensitive.

Some frameworks, such as Material UI, rely on the case-sensitivity of JSX properties.
For example, [TextField has two properties with the same name, but distinct cases](https://mui.com/material-ui/api/text-field/#TextField-prop-inputProps):

```html
<TextField inputLabelProps="" InputLabelProps=""></TextField>
```

- Fix [rome#4713](https://github.com/rome/tools/issues/4713).

Previously, [useTemplate](https://biomejs.dev/lint/rules/useTemplate/) made the following suggestion:
Expand Down

0 comments on commit 2a9c8b0

Please sign in to comment.