Skip to content

Commit 1cf7887

Browse files
committed
feature: @putout/operator-jsx: className
1 parent 1b21f71 commit 1cf7887

File tree

3 files changed

+162
-9
lines changed

3 files changed

+162
-9
lines changed

packages/operator-jsx/README.md

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,84 @@ Works this way:
9191
+<section className="hello"/>
9292
```
9393

94+
### addClassName(path: Path | Node, value: string)
95+
96+
Add `className`:
97+
98+
```js
99+
addClassName(node, 'hello');
100+
```
101+
102+
Works this way:
103+
104+
```diff
105+
-<section className="world"/>
106+
+<section className="hello"/>
107+
```
108+
109+
### removeClassName(path: Path | Node, value: string)
110+
111+
Remove `className`:
112+
113+
```js
114+
removeClassName(node, 'hello');
115+
```
116+
117+
Works this way:
118+
119+
```diff
120+
-<section className="hello world"/>
121+
+<section className="world"/>
122+
```
123+
124+
### getClassName(path: Path | Node): string
125+
126+
For next jsx:
127+
128+
```jsx
129+
<section className="world"/>;
130+
```
131+
132+
get `className`:
133+
134+
```js
135+
getClassName(node);
136+
// returns
137+
'world';
138+
```
139+
140+
### containsClassName(path: Path | Node, name: string): boolean
141+
142+
For next jsx:
143+
144+
```jsx
145+
<section className="hello world"/>;
146+
```
147+
148+
check:
149+
150+
```js
151+
containsClassName(node, 'hello');
152+
// returns
153+
true;
154+
```
155+
156+
### hasDataName(path: Path | Node, name: string): boolean
157+
158+
For next jsx:
159+
160+
```jsx
161+
<section data-name="hello"/>;
162+
```
163+
164+
check:
165+
166+
```js
167+
hasDataName(node, 'hello');
168+
// returns
169+
true;
170+
```
171+
94172
## License
95173

96174
MIT

packages/operator-jsx/lib/jsx.js

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ module.exports.getAttributeNode = getAttributeNode;
2828
function getAttributeNode(path, name) {
2929
let result = null;
3030

31+
if (!path)
32+
return result;
33+
3134
const node = path.node || path;
3235
const {attributes} = node.openingElement;
3336

@@ -41,25 +44,26 @@ function getAttributeNode(path, name) {
4144
return result;
4245
}
4346

44-
module.exports.getAttributeValue = (path, attributeName) => {
47+
module.exports.getAttributeValue = getAttributeValue;
48+
function getAttributeValue(path, attributeName) {
4549
const attribute = getAttributeNode(path, attributeName);
4650

4751
if (!attribute)
4852
return '';
4953

5054
return attribute.value.value;
51-
};
52-
53-
module.exports.addAttributeValue = (path, name, value) => {
55+
}
56+
module.exports.addAttributeValue = addAttributeValue;
57+
function addAttributeValue(path, name, value) {
5458
const attributeNode = getAttributeNode(path, name);
5559

5660
if (attributeNode.value.value.includes(value))
5761
return;
5862

5963
setLiteralValue(attributeNode.value, `${attributeNode.value.value} ${value}`);
60-
};
61-
62-
module.exports.removeAttributeValue = (path, name, attributeValue) => {
64+
}
65+
module.exports.removeAttributeValue = removeAttributeValue;
66+
function removeAttributeValue(path, name, attributeValue) {
6367
if (!path)
6468
return;
6569

@@ -70,11 +74,33 @@ module.exports.removeAttributeValue = (path, name, attributeValue) => {
7074

7175
if (value.includes(attributeValue))
7276
setLiteralValue(classAttribute.value, value.replace(RegExp(`\\s?${attributeValue}`), ''));
73-
};
74-
77+
}
7578
module.exports.setAttributeValue = (node, name, value) => {
7679
const attributeNode = getAttributeNode(node, name);
7780

7881
if (attributeNode)
7982
setLiteralValue(attributeNode.value, value);
8083
};
84+
85+
module.exports.addClassName = (path, name) => {
86+
addAttributeValue(path, 'className', name);
87+
};
88+
89+
module.exports.getClassName = getClassName;
90+
function getClassName(path) {
91+
return getAttributeValue(path, 'className');
92+
}
93+
94+
module.exports.removeClassName = (path, name) => {
95+
removeAttributeValue(path, 'className', name);
96+
};
97+
98+
module.exports.containsClassName = (path, className) => {
99+
const classNameValue = getClassName(path);
100+
return classNameValue.includes(className);
101+
};
102+
103+
module.exports.hasDataName = (path, value = '') => {
104+
const attribute = getAttributeValue(path, 'data-name');
105+
return attribute === value;
106+
};

packages/operator-jsx/lib/jsx.spec.js

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ const {
1111
const tryCatch = require('try-catch');
1212

1313
const {
14+
addClassName,
15+
removeClassName,
16+
containsClassName,
17+
hasDataName,
1418
hasTagName,
1519
getAttributePath,
1620
getAttributeNode,
@@ -181,9 +185,54 @@ test('putout: operator: jsx: setAttributeValue', (t) => {
181185
t.end();
182186
});
183187

188+
test('putout: operator: jsx: setAttributeValue: no', (t) => {
189+
const [error] = tryCatch(setAttributeValue, null, 'className', 'world');
190+
191+
t.notOk(error);
192+
t.end();
193+
});
194+
184195
test('putout: operator: jsx: removeAttributeValue: no path', (t) => {
185196
const [error] = tryCatch(removeAttributeValue, null, 'className', 'world');
186197

187198
t.notOk(error);
188199
t.end();
189200
});
201+
202+
test('putout: operator: jsx: addClassName', (t) => {
203+
const node = template.ast.fresh('<hello className="hello"/>');
204+
addClassName(node, 'world');
205+
206+
const result = print(node);
207+
const expected = `<hello className="hello world"/>;\n`;
208+
209+
t.equal(result, expected);
210+
t.end();
211+
});
212+
213+
test('putout: operator: jsx: removeClassName', (t) => {
214+
const node = template.ast.fresh('<hello className="hello world"/>');
215+
removeClassName(node, 'world');
216+
217+
const result = print(node);
218+
const expected = `<hello className="hello"/>;\n`;
219+
220+
t.equal(result, expected);
221+
t.end();
222+
});
223+
224+
test('putout: operator: jsx: containsClassName', (t) => {
225+
const node = template.ast.fresh('<hello className="hello world"/>');
226+
const result = containsClassName(node, 'world');
227+
228+
t.ok(result);
229+
t.end();
230+
});
231+
232+
test('putout: operator: jsx: hasDataName', (t) => {
233+
const node = template.ast.fresh('<hello data-name="hello"/>');
234+
const result = hasDataName(node, 'hello');
235+
236+
t.ok(result);
237+
t.end();
238+
});

0 commit comments

Comments
 (0)