Skip to content

Commit e913c1e

Browse files
committed
feature: @putout/operator-jsx: addAttribute
1 parent 7d694f9 commit e913c1e

File tree

3 files changed

+80
-13
lines changed

3 files changed

+80
-13
lines changed

packages/operator-jsx/README.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,26 @@ hasAttributeValue(node, 'data-menu-index', '1');
185185
true;
186186
```
187187

188+
### addAttribute(path: Path | Node, name: string, value: string)
189+
190+
For next jsx:
191+
192+
```jsx
193+
<section/>;
194+
```
195+
196+
check:
197+
198+
```js
199+
addAttribute(node, 'data-menu-index', '1');
200+
```
201+
202+
result is:
203+
204+
```jsx
205+
<section data-menu-index="1"/>;
206+
```
207+
188208
## License
189209

190210
MIT

packages/operator-jsx/lib/jsx.js

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,17 @@
22

33
const {setLiteralValue} = require('@putout/operate');
44
const {types} = require('@putout/babel');
5-
const {isJSXElement} = types;
5+
const {
6+
isJSXElement,
7+
jsxAttribute,
8+
jsxIdentifier,
9+
stringLiteral,
10+
} = types;
11+
12+
const getNode = (a) => a.node || a;
613

714
module.exports.hasTagName = (path, name) => {
8-
const node = path.node || path;
15+
const node = getNode(path);
916

1017
if (!isJSXElement(path))
1118
return false;
@@ -27,11 +34,7 @@ module.exports.getAttributePath = (path, name) => {
2734
module.exports.getAttributeNode = getAttributeNode;
2835
function getAttributeNode(path, name) {
2936
let result = null;
30-
31-
if (!path)
32-
return result;
33-
34-
const node = path.node || path;
37+
const node = getNode(path);
3538
const {attributes} = node.openingElement;
3639

3740
for (const attr of attributes) {
@@ -58,12 +61,26 @@ module.exports.addAttributeValue = addAttributeValue;
5861
function addAttributeValue(path, name, value) {
5962
const attributeNode = getAttributeNode(path, name);
6063

64+
if (!attributeNode)
65+
return addAttribute(path, name, value);
66+
6167
if (attributeNode.value.value.includes(value))
6268
return;
6369

6470
setLiteralValue(attributeNode.value, `${attributeNode.value.value} ${value}`);
6571
}
6672

73+
module.exports.addAttribute = addAttribute;
74+
function addAttribute(path, name, value) {
75+
const node = getNode(path);
76+
let attributeNode = getAttributeNode(node, name);
77+
78+
if (!attributeNode) {
79+
attributeNode = jsxAttribute(jsxIdentifier(name), stringLiteral(value));
80+
node.openingElement.attributes.push(attributeNode);
81+
}
82+
}
83+
6784
module.exports.removeAttributeValue = removeAttributeValue;
6885
function removeAttributeValue(path, name, attributeValue) {
6986
if (!path)
@@ -78,11 +95,13 @@ function removeAttributeValue(path, name, attributeValue) {
7895
setLiteralValue(classAttribute.value, value.replace(RegExp(`\\s?${attributeValue}`), ''));
7996
}
8097

81-
module.exports.setAttributeValue = (node, name, value) => {
82-
const attributeNode = getAttributeNode(node, name);
98+
module.exports.setAttributeValue = (path, name, value) => {
99+
const attributeNode = getAttributeNode(path, name);
100+
101+
if (!attributeNode)
102+
return addAttribute(path, name, value);
83103

84-
if (attributeNode)
85-
setLiteralValue(attributeNode.value, value);
104+
setLiteralValue(attributeNode.value, value);
86105
};
87106

88107
module.exports.addClassName = (path, name) => {

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

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ const tryCatch = require('try-catch');
1212

1313
const {
1414
addClassName,
15+
addAttribute,
1516
removeClassName,
1617
containsClassName,
1718
hasDataName,
@@ -137,6 +138,17 @@ test('putout: operator: jsx: addAttributeValue', (t) => {
137138
t.end();
138139
});
139140

141+
test('putout: operator: jsx: addAttributeValue: no attribute', (t) => {
142+
const node = template.ast.fresh('<hello/>');
143+
addAttributeValue(node, 'className', 'abc');
144+
145+
const result = print(node);
146+
const expected = '<hello className="abc"/>;\n';
147+
148+
t.equal(result, expected);
149+
t.end();
150+
});
151+
140152
test('putout: operator: jsx: addAttributeValue: exists', (t) => {
141153
const node = template.ast.fresh('<hello className="world"/>');
142154
addAttributeValue(node, 'className', 'world');
@@ -187,9 +199,14 @@ test('putout: operator: jsx: setAttributeValue', (t) => {
187199
});
188200

189201
test('putout: operator: jsx: setAttributeValue: no', (t) => {
190-
const [error] = tryCatch(setAttributeValue, null, 'className', 'world');
202+
const node = template.ast.fresh('<hello/>');
191203

192-
t.notOk(error);
204+
setAttributeValue(node, 'className', 'world');
205+
206+
const result = print(node);
207+
const expected = `<hello className="world"/>;\n`;
208+
209+
t.equal(result, expected);
193210
t.end();
194211
});
195212

@@ -245,3 +262,14 @@ test('putout: operator: jsx: hasAttribute', (t) => {
245262
t.ok(result);
246263
t.end();
247264
});
265+
266+
test('putout: operator: jsx: addAtribute', (t) => {
267+
const node = template.ast.fresh('<hello/>');
268+
269+
addAttribute(node, 'data-menu-index', '1');
270+
271+
const result = print(node);
272+
273+
t.ok(result);
274+
t.end();
275+
});

0 commit comments

Comments
 (0)