Skip to content

Commit

Permalink
[New] no-unescaped-entities: more friendly error message; add confi…
Browse files Browse the repository at this point in the history
…g to adjust
  • Loading branch information
stevemao authored and ljharb committed Oct 13, 2018
1 parent dd0757f commit 76b6742
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 14 deletions.
10 changes: 10 additions & 0 deletions docs/rules/no-unescaped-entities.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,14 @@ Overwrite the default forbidden entities array `['>', '"', '\'', '}']` with your

```js
"react/no-unescaped-entities": ["error", {"forbid": [">", "}"]}],
// or
"react/no-unescaped-entities": ["error", {"forbid": [{
char: ">",
alternatives: ['>']
}, {
char: "}",
alternatives: ['}']
}]}],
```

Where `char` is a special character and `alternatives` is the correct escapes.
44 changes: 40 additions & 4 deletions lib/rules/no-unescaped-entities.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,19 @@ const jsxUtil = require('../util/jsx');
// NOTE: '<' and '{' are also problematic characters, but they do not need
// to be included here because it is a syntax error when these characters are
// included accidentally.
const DEFAULTS = ['>', '"', '\'', '}'];
const DEFAULTS = [{
char: '>',
alternatives: ['&gt;']
}, {
char: '"',
alternatives: ['&quot;', '&ldquo;', '&#34;', '&rdquo;']
}, {
char: '\'',
alternatives: ['&apos;', '&lsquo;', '&#39;', '&rsquo;']
}, {
char: '}',
alternatives: ['&#125;']
}];

module.exports = {
meta: {
Expand All @@ -30,7 +42,23 @@ module.exports = {
forbid: {
type: 'array',
items: {
type: 'string'
oneOf: [{
type: 'string'
}, {
type: 'object',
properties: {
char: {
type: 'string'
},
alternatives: {
type: 'array',
uniqueItems: true,
items: {
type: 'string'
}
}
}
}]
}
}
},
Expand Down Expand Up @@ -59,10 +87,18 @@ module.exports = {
for (let j = 0; j < entities.length; j++) {
for (let index = 0; index < rawLine.length; index++) {
const c = rawLine[index];
if (c === entities[j]) {
if (typeof entities[j] === 'string') {
if (c === entities[j]) {
context.report({
loc: {line: i, column: start + index},
message: `HTML entity, \`${entities[j]}\` , must be escaped.`,
node: node
});
}
} else if (c === entities[j].char) {
context.report({
loc: {line: i, column: start + index},
message: 'HTML entities must be escaped.',
message: `\`${entities[j].char}\` can be escaped with ${entities[j].alternatives.map(alt => `\`${alt}\``).join(', ')}.`,
node: node
});
}
Expand Down
60 changes: 50 additions & 10 deletions tests/lib/rules/no-unescaped-entities.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ ruleTester.run('no-unescaped-entities', rule, {
}
});
`,
errors: [{message: 'HTML entities must be escaped.'}]
errors: [{message: '`>` can be escaped with `&gt;`.'}]
}, {
code: `
var Hello = createReactClass({
Expand All @@ -122,7 +122,7 @@ ruleTester.run('no-unescaped-entities', rule, {
});
`,
parser: 'babel-eslint',
errors: [{message: 'HTML entities must be escaped.'}]
errors: [{message: '`>` can be escaped with `&gt;`.'}]
}, {
code: `
var Hello = createReactClass({
Expand All @@ -133,7 +133,7 @@ ruleTester.run('no-unescaped-entities', rule, {
}
});
`,
errors: [{message: 'HTML entities must be escaped.'}]
errors: [{message: '`>` can be escaped with `&gt;`.'}]
}, {
code: `
var Hello = createReactClass({
Expand All @@ -145,7 +145,7 @@ ruleTester.run('no-unescaped-entities', rule, {
});
`,
parser: 'babel-eslint',
errors: [{message: 'HTML entities must be escaped.'}]
errors: [{message: '`>` can be escaped with `&gt;`.'}]
}, {
code: `
var Hello = createReactClass({
Expand All @@ -154,7 +154,7 @@ ruleTester.run('no-unescaped-entities', rule, {
}
});
`,
errors: [{message: 'HTML entities must be escaped.'}]
errors: [{message: '`\'` can be escaped with `&apos;`, `&lsquo;`, `&#39;`, `&rsquo;`.'}]
}, {
code: `
var Hello = createReactClass({
Expand All @@ -164,9 +164,9 @@ ruleTester.run('no-unescaped-entities', rule, {
});
`,
errors: [
{message: 'HTML entities must be escaped.'},
{message: 'HTML entities must be escaped.'},
{message: 'HTML entities must be escaped.'}
{message: '`\'` can be escaped with `&apos;`, `&lsquo;`, `&#39;`, `&rsquo;`.'},
{message: '`>` can be escaped with `&gt;`.'},
{message: '`>` can be escaped with `&gt;`.'}
]
}, {
code: `
Expand All @@ -176,7 +176,7 @@ ruleTester.run('no-unescaped-entities', rule, {
}
});
`,
errors: [{message: 'HTML entities must be escaped.'}]
errors: [{message: '`}` can be escaped with `&#125;`.'}]
}, {
code: `
var Hello = createReactClass({
Expand All @@ -186,7 +186,47 @@ ruleTester.run('no-unescaped-entities', rule, {
});
`,
parser: 'babel-eslint',
errors: [{message: 'HTML entities must be escaped.'}]
errors: [{message: '`}` can be escaped with `&#125;`.'}]
}, {
code: `
var Hello = createReactClass({
render: function() {
return <>foo & bar</>;
}
});
`,
parser: 'babel-eslint',
errors: [{message: 'HTML entity, \`&\` , must be escaped.'}],
options: [{
forbid: ['&']
}]
}, {
code: `
var Hello = createReactClass({
render: function() {
return <span>foo & bar</span>;
}
});
`,
errors: [{message: 'HTML entity, \`&\` , must be escaped.'}],
options: [{
forbid: ['&']
}]
}, {
code: `
var Hello = createReactClass({
render: function() {
return <span>foo & bar</span>;
}
});
`,
errors: [{message: '`&` can be escaped with `&amp;`.'}],
options: [{
forbid: [{
char: '&',
alternatives: ['&amp;']
}]
}]
}
]
});

0 comments on commit 76b6742

Please sign in to comment.