Skip to content

Commit ade9e77

Browse files
gitimyannickcr
authored andcommitted
Add self-closing-comp option to check html tags (fixes #572)
1 parent dae6761 commit ade9e77

File tree

3 files changed

+177
-3
lines changed

3 files changed

+177
-3
lines changed

docs/rules/self-closing-comp.md

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,56 @@ var contentContainer = <div className="content"></div>;
1717

1818
var HelloJohn = <Hello name="John" />;
1919

20-
var Profile = <Hello name="John"><img src="picture.png" /></Hello>;
20+
var Profile = <Hello name="John"><img src="picture.png" /></Hello>;
21+
```
22+
23+
## Rule Options
24+
25+
The rule can take one argument to select types of tags, which should be self-closed when this is possible. By default only custom components tags should be self-closed.
26+
27+
```js
28+
...
29+
"self-closing-comp": ["error", {
30+
"component": true,
31+
"html": false
32+
}]
33+
...
34+
```
35+
36+
### `component`
37+
38+
When `true`, custom components tags should be self-closed.
39+
40+
The following patterns are considered warnings:
41+
42+
```js
43+
var HelloJohn = <Hello name="John"></Hello>;
44+
```
45+
46+
The following patterns are not considered warnings:
47+
48+
```js
49+
var contentContainer = <div className="content"></div>;
50+
51+
var HelloJohn = <Hello name="John" />;
52+
53+
var Profile = <Hello name="John"><img src="picture.png" /></Hello>;
54+
```
55+
56+
### `html`
57+
58+
When `true`, html components tags should be self-closed.
59+
60+
The following patterns are considered warnings:
61+
62+
```js
63+
var contentContainer = <div className="content"></div>;
64+
```
65+
66+
The following patterns are not considered warnings:
67+
68+
```js
69+
var contentContainer = <div className="content" />;
70+
71+
var contentContainer = <div className="content"><div /></div>;
2172
```

lib/rules/self-closing-comp.js

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,23 @@ module.exports = function(context) {
3030
return true;
3131
}
3232

33+
function isShouldBeSelfClosed(node) {
34+
var configuration = context.options[0] || {component: true};
35+
return (
36+
configuration.component && isComponent(node) ||
37+
configuration.html && isTagName(node.name.name)
38+
) && !node.selfClosing && !hasChildren(node);
39+
}
40+
3341
// --------------------------------------------------------------------------
3442
// Public
3543
// --------------------------------------------------------------------------
3644

3745
return {
3846

3947
JSXOpeningElement: function(node) {
40-
if (!isComponent(node) || node.selfClosing || hasChildren(node)) {
48+
49+
if (!isShouldBeSelfClosed(node)) {
4150
return;
4251
}
4352
context.report({
@@ -49,4 +58,17 @@ module.exports = function(context) {
4958

5059
};
5160

52-
module.exports.schema = [];
61+
module.exports.schema = [{
62+
type: 'object',
63+
properties: {
64+
component: {
65+
default: true,
66+
type: 'boolean'
67+
},
68+
html: {
69+
default: false,
70+
type: 'boolean'
71+
}
72+
},
73+
additionalProperties: false
74+
}];

tests/lib/rules/self-closing-comp.js

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,64 @@ ruleTester.run('self-closing-comp', rule, {
5050
}, {
5151
code: 'var HelloJohn = <Hello name="John">&nbsp;</Hello>;',
5252
parserOptions: parserOptions
53+
}, {
54+
code: 'var contentContainer = <div className="content"></div>;',
55+
options: [],
56+
parserOptions: parserOptions
57+
}, {
58+
code: 'var HelloJohn = <Hello name="John" />;',
59+
options: [],
60+
parserOptions: parserOptions
61+
}, {
62+
code: 'var Profile = <Hello name="John"><img src="picture.png" /></Hello>;',
63+
options: [],
64+
parserOptions: parserOptions
65+
}, {
66+
code: '\
67+
<Hello>\
68+
<Hello name="John" />\
69+
</Hello>',
70+
options: [],
71+
parserOptions: parserOptions
72+
}, {
73+
code: 'var HelloJohn = <div>&nbsp;</div>;',
74+
options: [],
75+
parserOptions: parserOptions
76+
}, {
77+
code: 'var HelloJohn = <div>{\' \'}</div>;',
78+
options: [],
79+
parserOptions: parserOptions
80+
}, {
81+
code: 'var HelloJohn = <Hello name="John">&nbsp;</Hello>;',
82+
options: [],
83+
parserOptions: parserOptions
84+
}, {
85+
code: 'var HelloJohn = <Hello name="John"></Hello>;',
86+
options: [{component: false}],
87+
parserOptions: parserOptions
88+
}, {
89+
code: 'var HelloJohn = <Hello name="John">\n</Hello>;',
90+
options: [{component: false}],
91+
parserOptions: parserOptions
92+
}, {
93+
code: 'var HelloJohn = <Hello name="John"> </Hello>;',
94+
options: [{component: false}],
95+
parserOptions: parserOptions
96+
}, {
97+
code: 'var contentContainer = <div className="content" />;',
98+
options: [{html: true}],
99+
parserOptions: parserOptions
100+
}, {
101+
code: 'var contentContainer = <div className="content"><img src="picture.png" /></div>;',
102+
options: [{html: true}],
103+
parserOptions: parserOptions
104+
}, {
105+
code: '\
106+
<div>\
107+
<div className="content" />\
108+
</div>',
109+
options: [{html: true}],
110+
parserOptions: parserOptions
53111
}
54112
],
55113

@@ -72,6 +130,49 @@ ruleTester.run('self-closing-comp', rule, {
72130
errors: [{
73131
message: 'Empty components are self-closing'
74132
}]
133+
},
134+
{
135+
code: 'var HelloJohn = <Hello name="John"></Hello>;',
136+
options: [],
137+
parserOptions: parserOptions,
138+
errors: [{
139+
message: 'Empty components are self-closing'
140+
}]
141+
}, {
142+
code: 'var HelloJohn = <Hello name="John">\n</Hello>;',
143+
options: [],
144+
parserOptions: parserOptions,
145+
errors: [{
146+
message: 'Empty components are self-closing'
147+
}]
148+
}, {
149+
code: 'var HelloJohn = <Hello name="John"> </Hello>;',
150+
options: [],
151+
parserOptions: parserOptions,
152+
errors: [{
153+
message: 'Empty components are self-closing'
154+
}]
155+
}, {
156+
code: 'var contentContainer = <div className="content"></div>;',
157+
options: [{html: true}],
158+
parserOptions: parserOptions,
159+
errors: [{
160+
message: 'Empty components are self-closing'
161+
}]
162+
}, {
163+
code: 'var contentContainer = <div className="content">\n</div>;',
164+
options: [{html: true}],
165+
parserOptions: parserOptions,
166+
errors: [{
167+
message: 'Empty components are self-closing'
168+
}]
169+
}, {
170+
code: 'var contentContainer = <div className="content"> </div>;',
171+
options: [{html: true}],
172+
parserOptions: parserOptions,
173+
errors: [{
174+
message: 'Empty components are self-closing'
175+
}]
75176
}
76177
]
77178
});

0 commit comments

Comments
 (0)