Skip to content

Commit 4f2a2ff

Browse files
committed
[Fix] jsx-no-literals: new config for allowedProps
Fixes #3003
1 parent ae64aa8 commit 4f2a2ff

File tree

3 files changed

+50
-14
lines changed

3 files changed

+50
-14
lines changed

docs/rules/jsx-no-literals.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,13 @@ The supported options are:
3333
- `noStrings` (default: `false`) - Enforces no string literals used as children, wrapped or unwrapped.
3434
- `allowedStrings` - An array of unique string values that would otherwise warn, but will be ignored.
3535
- `ignoreProps` (default: `false`) - When `true` the rule ignores literals used in props, wrapped or unwrapped.
36+
- `allowedProps` - An array of unique property names that would otherwise warn, but will be ignored.
3637
- `noAttributeStrings` (default: `false`) - Enforces no string literals used in attributes when set to `true`.
3738

3839
To use, you can specify as follows:
3940

4041
```js
41-
"react/jsx-no-literals": [<enabled>, {"noStrings": true, "allowedStrings": ["allowed"], "ignoreProps": false, "noAttributeStrings": true }]
42+
"react/jsx-no-literals": [<enabled>, {"noStrings": true, "allowedStrings": ["allowed"], "ignoreProps": false, "allowedProps": ["allowed"], "noAttributeStrings": true }]
4243
```
4344

4445
Examples of **incorrect** code for this rule, with the above configuration:
@@ -116,6 +117,11 @@ var Hello = <Text {...props} />
116117
var Hello = <div class={xx} />
117118
```
118119

120+
```jsx
121+
// an allowed property
122+
var Hello = <div allowed='foo'>allowed</div>
123+
```
124+
119125
```jsx
120126
// cache
121127
class Comp1 extends Component {

lib/rules/jsx-no-literals.js

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,13 @@ module.exports = {
5151
ignoreProps: {
5252
type: 'boolean',
5353
},
54+
allowedProps: {
55+
type: 'array',
56+
uniqueItems: true,
57+
items: {
58+
type: 'string',
59+
},
60+
},
5461
noAttributeStrings: {
5562
type: 'boolean',
5663
},
@@ -63,11 +70,13 @@ module.exports = {
6370
const defaults = {
6471
noStrings: false,
6572
allowedStrings: [],
73+
allowedProps: [],
6674
ignoreProps: false,
6775
noAttributeStrings: false,
6876
};
6977
const config = Object.assign({}, defaults, context.options[0] || {});
7078
config.allowedStrings = new Set(config.allowedStrings.map(trimIfString));
79+
config.allowedProps = new Set(config.allowedProps.map(trimIfString));
7180

7281
function defaultMessageId() {
7382
const ancestorIsJSXElement = arguments.length >= 1 && arguments[0];
@@ -98,8 +107,9 @@ module.exports = {
98107

99108
function isParentNodeStandard() {
100109
if (!/^[\s]+$/.test(node.value) && typeof node.value === 'string' && parent.type.includes('JSX')) {
110+
101111
if (config.noAttributeStrings) {
102-
return parent.type === 'JSXAttribute' || parent.type === 'JSXElement';
112+
return (parent.type === 'JSXAttribute' || parent.type === 'JSXElement') && !config.allowedProps.has(parent.name?.name);
103113
}
104114
if (!config.noAttributeStrings) {
105115
return parent.type !== 'JSXAttribute';
@@ -163,8 +173,9 @@ module.exports = {
163173

164174
JSXAttribute(node) {
165175
const isNodeValueString = node && node.value && node.value.type === 'Literal' && typeof node.value.value === 'string' && !config.allowedStrings.has(node.value.value);
176+
const isAllowedProp = config.allowedProps.has(node.name.name);
166177

167-
if (config.noStrings && !config.ignoreProps && isNodeValueString) {
178+
if (config.noStrings && !config.ignoreProps && isNodeValueString && !isAllowedProp) {
168179
const messageId = 'invalidPropValue';
169180
reportLiteralNode(node, messageId);
170181
}

tests/lib/rules/jsx-no-literals.js

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,23 @@ ruleTester.run('jsx-no-literals', rule, {
296296
`,
297297
options: [{ noStrings: true, allowedStrings: ['&mdash;', '—'] }],
298298
},
299+
{
300+
code: `
301+
<img alt='blank image'></img>
302+
`,
303+
options: [{ noStrings: true, allowedProps: ['alt'] }],
304+
},
305+
{
306+
code: `
307+
class Comp1 extends Component {
308+
asdf() {}
309+
render() {
310+
return <Foo bar={this.asdf} class='xx' />;
311+
}
312+
}
313+
`,
314+
options: [{ noStrings: true, allowedProps: ['class'] }],
315+
},
299316
]),
300317

301318
invalid: parsers.all([
@@ -457,7 +474,7 @@ ruleTester.run('jsx-no-literals', rule, {
457474
},
458475
{
459476
messageId: 'noStringsInJSX',
460-
data: { text: '\'Test\'' },
477+
data: { text: "'Test'" },
461478
},
462479
],
463480
},
@@ -475,7 +492,7 @@ ruleTester.run('jsx-no-literals', rule, {
475492
},
476493
{
477494
messageId: 'noStringsInJSX',
478-
data: { text: '\'Test\'' },
495+
data: { text: "'Test'" },
479496
},
480497
],
481498
},
@@ -542,7 +559,7 @@ ruleTester.run('jsx-no-literals', rule, {
542559
],
543560
},
544561
{
545-
code: '<Foo bar={`foo` + \'bar\'} />',
562+
code: "<Foo bar={`foo` + 'bar'} />",
546563
options: [{ noStrings: true, ignoreProps: false }],
547564
errors: [
548565
{
@@ -551,7 +568,7 @@ ruleTester.run('jsx-no-literals', rule, {
551568
},
552569
{
553570
messageId: 'noStringsInJSX',
554-
data: { text: '\'bar\'' },
571+
data: { text: "'bar'" },
555572
},
556573
],
557574
},
@@ -570,12 +587,12 @@ ruleTester.run('jsx-no-literals', rule, {
570587
],
571588
},
572589
{
573-
code: '<Foo bar={\'foo\' + `bar`} />',
590+
code: "<Foo bar={'foo' + `bar`} />",
574591
options: [{ noStrings: true, ignoreProps: false }],
575592
errors: [
576593
{
577594
messageId: 'noStringsInJSX',
578-
data: { text: '\'foo\'' },
595+
data: { text: "'foo'" },
579596
},
580597
{
581598
messageId: 'noStringsInJSX',
@@ -591,11 +608,13 @@ ruleTester.run('jsx-no-literals', rule, {
591608
}
592609
}
593610
`,
594-
options: [{ noStrings: true, allowedStrings: ['asd'], ignoreProps: false }],
611+
options: [
612+
{ noStrings: true, allowedStrings: ['asd'], ignoreProps: false },
613+
],
595614
errors: [
596615
{
597616
messageId: 'noStringsInJSX',
598-
data: { text: '\'foo\'' },
617+
data: { text: "'foo'" },
599618
},
600619
{
601620
messageId: 'noStringsInJSX',
@@ -604,12 +623,12 @@ ruleTester.run('jsx-no-literals', rule, {
604623
],
605624
},
606625
{
607-
code: '<Foo bar={\'bar\'} />',
626+
code: "<Foo bar={'bar'} />",
608627
options: [{ noStrings: true, ignoreProps: false }],
609628
errors: [
610629
{
611630
messageId: 'noStringsInJSX',
612-
data: { text: '\'bar\'' },
631+
data: { text: "'bar'" },
613632
},
614633
],
615634
},
@@ -621,7 +640,7 @@ ruleTester.run('jsx-no-literals', rule, {
621640
errors: [
622641
{
623642
messageId: 'noStringsInAttributes',
624-
data: { text: '\'blank image\'' },
643+
data: { text: "'blank image'" },
625644
},
626645
],
627646
},

0 commit comments

Comments
 (0)