Skip to content

Commit 40701dd

Browse files
authored
Update docs with covered cases (#8)
* update docs * add missing test cases * add note about prop forwarding
1 parent b583054 commit 40701dd

File tree

3 files changed

+173
-12
lines changed

3 files changed

+173
-12
lines changed

README.md

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,24 @@
11
# @fullstory/eslint-plugin-annotate-react
22

3-
An ESLint plugin for adding 'data-attribute' to React components. The purpose of this plugin is to automatically
4-
make css selectors. Here is an example
3+
An ESLint plugin for adding 'data-attribute' to React components. The purpose of this plugin is to automatically make css selectors. Here is an example:
54

65
```
7-
const myDiv = () => (
8-
<div/>
9-
); `;
6+
const MyComponent = () => (
7+
<div />
8+
);
109
```
1110

12-
This plugin will autofix and add data-component to the div
11+
This plugin will autofix and add the `data-component` prop to the div:
1312

1413
```
15-
const myDiv = () => (
16-
<div data-component="temp"/>
17-
); `;
14+
const MyComponent = () => (
15+
<div data-component="MyComponent" />
16+
);
1817
```
1918

20-
This plugin is intended to not be too opinionated. In general the approach is to suggest to the developer to add 'data-attribute' when there is an obvious approach, but in questionable cases, the plugin will tend towards being quiet.
19+
This plugin is intended to not be too opinionated. In general the approach is to suggest to the developer to add 'data-component' when there is an obvious approach, but in questionable cases, the plugin will tend towards being quiet. Click to learn more about the [covered cases](./docs/covered-cases.md).
2120

22-
- When there is a [fragment](https://reactjs.org/docs/fragments.html) this plugin won't add data-attribute
23-
- Where there are multiple return elements this plugin won't add data-attribute
21+
_Note: This plugin cannot guarantee that the `data-component` prop will actually make it to the DOM node if the top level element is another React component. For it to work effectively, make sure you are properly [forwarding props with the JSX spread syntax](https://react.dev/learn/passing-props-to-a-component#forwarding-props-with-the-jsx-spread-syntax)._
2422

2523
## Installation
2624

docs/covered-cases.md

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
# Covered Cases
2+
3+
This plugin is intended to not be too opinionated. In general the approach is to suggest to the developer to add 'data-component' when there is an obvious approach, but in questionable cases, the plugin will them and stay quiet.
4+
5+
### Covered
6+
7+
#### Basic function components
8+
9+
```tsx
10+
const MyComponent = () => <div />;
11+
```
12+
13+
> MyComponent is missing the data-component attribute for the top-level element.
14+
15+
```tsx
16+
function MyComponent() {
17+
return <div />;
18+
}
19+
```
20+
21+
> MyComponent is missing the data-component attribute for the top-level element.
22+
23+
```tsx
24+
export default function MyComponent() {
25+
return <div />;
26+
}
27+
```
28+
29+
> MyComponent is missing the data-component attribute for the top-level element.
30+
31+
#### Typescript generic components
32+
33+
```tsx
34+
const yAxis = (xScale, xTicks) => (
35+
<BottomAxis<Date> width={1} height={1} xScale={xScale} xTicks={xTicks}>
36+
123
37+
</BottomAxis>
38+
);
39+
```
40+
41+
> yAxis is missing the data-component attribute for the top-level element.
42+
43+
#### Multiple components in a file
44+
45+
```tsx
46+
const Component1 = () => <div />;
47+
const Component2 = () => <span />;
48+
```
49+
50+
> Component1 is missing the data-component attribute for the top-level element.
51+
> Component2 is missing the data-component attribute for the top-level element.
52+
53+
#### Class-based components
54+
55+
```tsx
56+
class Car extends React.Component {
57+
render() {
58+
return <h2>Hi, I am a Car!</h2>;
59+
}
60+
}
61+
```
62+
63+
> Car is missing the data-component attribute for the top-level element.
64+
65+
#### Components wrapped with forwardRef
66+
67+
```tsx
68+
export const Navigate = React.forwardRef<HTMLAnchorElement, NavigateProps>(
69+
(props, ref) => <Link ref={ref} {...props} />,
70+
);
71+
```
72+
73+
> Navigate is missing the data-component attribute for the top-level element.
74+
75+
### Ignored
76+
77+
#### Components with Provider as the top-level element
78+
79+
```tsx
80+
export const App = () => <AppContext.Provider value={ctx} />;
81+
```
82+
83+
> All good!
84+
85+
_Note: This just uses a simple `/Provider$/` regex test_
86+
87+
#### Components with a [React Fragment](https://reactjs.org/docs/fragments.html) as the top-level element
88+
89+
```tsx
90+
const FragmentComponent = () => (
91+
<>
92+
<span />
93+
<div />
94+
<a />
95+
</>
96+
);
97+
```
98+
99+
> All good!
100+
101+
#### Components that conditionally return different values
102+
103+
```tsx
104+
const ConditionalComponent = () => {
105+
const isActive = useIsActive();
106+
return isActive ? <div /> : null;
107+
};
108+
```
109+
110+
> All good!
111+
112+
```tsx
113+
const ConditionalComponent = () => {
114+
const isActive = useIsActive();
115+
if (isActive) {
116+
return <ActiveComponent />;
117+
}
118+
return <div />;
119+
};
120+
```
121+
122+
> All good!

test.js

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,14 @@ const singleComponentError = `const temp = () => {
1414
return <Icon name="metric" size={24} />;
1515
};`;
1616

17+
const defaultSingleComponent = `export default function temp () {
18+
return <Icon data-component="temp" name="metric" size={24} />;
19+
};`;
20+
21+
const defaultSingleComponentError = `export default function temp () {
22+
return <Icon name="metric" size={24} />;
23+
};`;
24+
1725
const genericTest = `
1826
const yAxis = (xScale, xTicks) => (
1927
<BottomAxis<Date> data-component="yAxis" width={1} height={1} xScale={xScale} xTicks={xTicks}>
@@ -249,6 +257,23 @@ const providerWithDot = /* tsx */ `
249257
export const Test = () => <Test.Provider />;
250258
`;
251259

260+
const ternary = /* tsx */ `
261+
export const TernaryComponent = () => {
262+
const active = useIsActive();
263+
return active ? <ActiveComponent /> : null;
264+
};
265+
`;
266+
267+
const ifBlock = /* tsx */ `
268+
export const IfBlockComponent = () => {
269+
const active = useIsActive();
270+
if (active) {
271+
return <ActiveComponent />;
272+
}
273+
return <div />;
274+
};
275+
`;
276+
252277
const tests = {
253278
'data-component': {
254279
// Require the actual rule definition
@@ -278,6 +303,9 @@ const tests = {
278303
{
279304
code: singleComponent,
280305
},
306+
{
307+
code: defaultSingleComponent,
308+
},
281309
{
282310
code: genericTest,
283311
},
@@ -312,6 +340,12 @@ const tests = {
312340
{
313341
code: providerWithDot,
314342
},
343+
{
344+
code: ternary,
345+
},
346+
{
347+
code: ifBlock,
348+
},
315349
],
316350
invalid: [
317351
{
@@ -321,6 +355,13 @@ const tests = {
321355
'temp is missing the data-component attribute for the top-level element.',
322356
],
323357
},
358+
{
359+
code: defaultSingleComponentError,
360+
output: defaultSingleComponent,
361+
errors: [
362+
'temp is missing the data-component attribute for the top-level element.',
363+
],
364+
},
324365
{
325366
code: classComponentError,
326367
output: classComponent,

0 commit comments

Comments
 (0)