Skip to content

Commit d806fc8

Browse files
committed
more friendly message for no-unescaped-entities
1 parent 78e9ea7 commit d806fc8

File tree

3 files changed

+84
-17
lines changed

3 files changed

+84
-17
lines changed

docs/rules/no-unescaped-entities.md

+10
Original file line numberDiff line numberDiff line change
@@ -83,4 +83,14 @@ Overwrite the default forbidden entities array `['>', '"', '\'', '}']` with your
8383

8484
```js
8585
"react/no-unescaped-entities": ["error", {"forbid": [">", "}"]}],
86+
// or
87+
"react/no-unescaped-entities": ["error", {"forbid": [{
88+
char: ">",
89+
alternatives: ['>']
90+
}, {
91+
char: "}",
92+
alternatives: ['}']
93+
}]}],
8694
```
95+
96+
Where `char` is a special character and `alternatives` is the correct escapes.

lib/rules/no-unescaped-entities.js

+24-7
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,19 @@ const jsxUtil = require('../util/jsx');
1414
// NOTE: '<' and '{' are also problematic characters, but they do not need
1515
// to be included here because it is a syntax error when these characters are
1616
// included accidentally.
17-
const DEFAULTS = ['>', '"', '\'', '}'];
17+
const DEFAULTS = [{
18+
char: '>',
19+
alternatives: ['&gt;']
20+
}, {
21+
char: '"',
22+
alternatives: ['&quot;', '&ldquo;', '&#34;', '&rdquo;']
23+
}, {
24+
char: '\'',
25+
alternatives: ['&apos;', '&lsquo;', '&#39;', '&rsquo;']
26+
}, {
27+
char: '}',
28+
alternatives: ['&#125;']
29+
}];
1830

1931
module.exports = {
2032
meta: {
@@ -28,10 +40,7 @@ module.exports = {
2840
type: 'object',
2941
properties: {
3042
forbid: {
31-
type: 'array',
32-
items: {
33-
type: 'string'
34-
}
43+
type: 'array'
3544
}
3645
},
3746
additionalProperties: false
@@ -59,10 +68,18 @@ module.exports = {
5968
for (let j = 0; j < entities.length; j++) {
6069
for (let index = 0; index < rawLine.length; index++) {
6170
const c = rawLine[index];
62-
if (c === entities[j]) {
71+
if (typeof entities[j] === 'string') {
72+
if (c === entities[j]) {
73+
context.report({
74+
loc: {line: i, column: start + index},
75+
message: `HTML entity, \`${entities[j]}\` , must be escaped.`,
76+
node: node
77+
});
78+
}
79+
} else if (c === entities[j].char) {
6380
context.report({
6481
loc: {line: i, column: start + index},
65-
message: 'HTML entities must be escaped.',
82+
message: `\`${entities[j].char}\` can be escaped with ${entities[j].alternatives.map(alt => `\`${alt}\``).join(', ')}.`,
6683
node: node
6784
});
6885
}

tests/lib/rules/no-unescaped-entities.js

+50-10
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ ruleTester.run('no-unescaped-entities', rule, {
112112
}
113113
});
114114
`,
115-
errors: [{message: 'HTML entities must be escaped.'}]
115+
errors: [{message: '`>` can be escaped with `&gt;`.'}]
116116
}, {
117117
code: `
118118
var Hello = createReactClass({
@@ -122,7 +122,7 @@ ruleTester.run('no-unescaped-entities', rule, {
122122
});
123123
`,
124124
parser: 'babel-eslint',
125-
errors: [{message: 'HTML entities must be escaped.'}]
125+
errors: [{message: '`>` can be escaped with `&gt;`.'}]
126126
}, {
127127
code: `
128128
var Hello = createReactClass({
@@ -133,7 +133,7 @@ ruleTester.run('no-unescaped-entities', rule, {
133133
}
134134
});
135135
`,
136-
errors: [{message: 'HTML entities must be escaped.'}]
136+
errors: [{message: '`>` can be escaped with `&gt;`.'}]
137137
}, {
138138
code: `
139139
var Hello = createReactClass({
@@ -145,7 +145,7 @@ ruleTester.run('no-unescaped-entities', rule, {
145145
});
146146
`,
147147
parser: 'babel-eslint',
148-
errors: [{message: 'HTML entities must be escaped.'}]
148+
errors: [{message: '`>` can be escaped with `&gt;`.'}]
149149
}, {
150150
code: `
151151
var Hello = createReactClass({
@@ -154,7 +154,7 @@ ruleTester.run('no-unescaped-entities', rule, {
154154
}
155155
});
156156
`,
157-
errors: [{message: 'HTML entities must be escaped.'}]
157+
errors: [{message: '`\'` can be escaped with `&apos;`, `&lsquo;`, `&#39;`, `&rsquo;`.'}]
158158
}, {
159159
code: `
160160
var Hello = createReactClass({
@@ -164,9 +164,9 @@ ruleTester.run('no-unescaped-entities', rule, {
164164
});
165165
`,
166166
errors: [
167-
{message: 'HTML entities must be escaped.'},
168-
{message: 'HTML entities must be escaped.'},
169-
{message: 'HTML entities must be escaped.'}
167+
{message: '`\'` can be escaped with `&apos;`, `&lsquo;`, `&#39;`, `&rsquo;`.'},
168+
{message: '`>` can be escaped with `&gt;`.'},
169+
{message: '`>` can be escaped with `&gt;`.'}
170170
]
171171
}, {
172172
code: `
@@ -176,7 +176,7 @@ ruleTester.run('no-unescaped-entities', rule, {
176176
}
177177
});
178178
`,
179-
errors: [{message: 'HTML entities must be escaped.'}]
179+
errors: [{message: '`}` can be escaped with `&#125;`.'}]
180180
}, {
181181
code: `
182182
var Hello = createReactClass({
@@ -186,7 +186,47 @@ ruleTester.run('no-unescaped-entities', rule, {
186186
});
187187
`,
188188
parser: 'babel-eslint',
189-
errors: [{message: 'HTML entities must be escaped.'}]
189+
errors: [{message: '`}` can be escaped with `&#125;`.'}]
190+
}, {
191+
code: `
192+
var Hello = createReactClass({
193+
render: function() {
194+
return <>foo & bar</>;
195+
}
196+
});
197+
`,
198+
parser: 'babel-eslint',
199+
errors: [{message: 'HTML entity, \`&\` , must be escaped.'}],
200+
options: [{
201+
forbid: ['&']
202+
}]
203+
}, {
204+
code: `
205+
var Hello = createReactClass({
206+
render: function() {
207+
return <span>foo & bar</span>;
208+
}
209+
});
210+
`,
211+
errors: [{message: 'HTML entity, \`&\` , must be escaped.'}],
212+
options: [{
213+
forbid: ['&']
214+
}]
215+
}, {
216+
code: `
217+
var Hello = createReactClass({
218+
render: function() {
219+
return <span>foo & bar</span>;
220+
}
221+
});
222+
`,
223+
errors: [{message: '`&` can be escaped with `&amp;`.'}],
224+
options: [{
225+
forbid: [{
226+
char: '&',
227+
alternatives: ['&amp;']
228+
}]
229+
}]
190230
}
191231
]
192232
});

0 commit comments

Comments
 (0)