Skip to content

Commit 59f41ca

Browse files
Added no-raw-text rule
- added new rule to prevent error of raw text, eg facebook/react-native#15870 react-native-maps/react-native-maps#1791 - added .idea folder to gitignore
1 parent 0df66ec commit 59f41ca

File tree

6 files changed

+203
-0
lines changed

6 files changed

+203
-0
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,5 @@ build/Release
2525
# Dependency directory
2626
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
2727
node_modules
28+
29+
.idea

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ Finally, enable all of the rules that you would like to use.
7171
"react-native/split-platform-components": 2,
7272
"react-native/no-inline-styles": 2,
7373
"react-native/no-color-literals": 2,
74+
"react-native/no-raw-text": 2,
7475
}
7576
}
7677
```
@@ -81,6 +82,7 @@ Finally, enable all of the rules that you would like to use.
8182
* [split-platform-components](docs/rules/split-platform-components.md): Enforce using platform specific filenames when necessary
8283
* [no-inline-styles](docs/rules/no-inline-styles.md): Detect JSX components with inline styles that contain literal values
8384
* [no-color-literals](docs/rules/no-color-literals.md): Detect `StyleSheet` rules and inline styles containing color literals instead of variables
85+
* [no-raw-text](docs/rules/no-raw-text.md): Detect raw text outside of `Text` component
8486

8587
[npm-url]: https://npmjs.org/package/eslint-plugin-react-native
8688
[npm-image]: http://img.shields.io/npm/v/eslint-plugin-react-native.svg?style=flat-square

docs/rules/no-raw-text.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Detect raw text outside of Text component
2+
All strings in React Native should be wrapped with a Text component.
3+
4+
## Rule Details
5+
6+
The following patterns are considered warnings:
7+
8+
```js
9+
<View>some text</View>
10+
```
11+
12+
```js
13+
const text = 'some text';
14+
<View>{`${text}`}</View>
15+
```
16+
17+
The following patterns are not considered warnings:
18+
19+
```js
20+
<View><Text>some text</Text></View>
21+
```
22+
23+
```js
24+
const text = 'some text';
25+
<View><Text>{`${text}`}</Text></View>
26+
```

index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ const allRules = {
77
'no-inline-styles': require('./lib/rules/no-inline-styles'),
88
'no-color-literals': require('./lib/rules/no-color-literals'),
99
'split-platform-components': require('./lib/rules/split-platform-components'),
10+
'no-raw-text': require('./lib/rules/no-raw-text'),
1011
};
1112

1213
function configureAsError(rules) {
@@ -30,6 +31,7 @@ module.exports = {
3031
'no-inline-styles': 0,
3132
'no-color-literals': 0,
3233
'split-platform-components': 0,
34+
'no-raw-text': 0,
3335
},
3436
environments: {
3537
'react-native': {

lib/rules/no-raw-text.js

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/**
2+
* @fileoverview Detects raw text outside of Text component
3+
* @author Alex Zhukov
4+
*/
5+
6+
'use strict';
7+
8+
module.exports = (context) => {
9+
const elementName = node => (
10+
node.openingElement &&
11+
node.openingElement.name &&
12+
node.openingElement.name.type === 'JSXIdentifier' &&
13+
node.openingElement.name.name
14+
);
15+
16+
const report = (node) => {
17+
const errorValue = node.type === 'TemplateLiteral'
18+
? `TemplateLiteral: ${node.expressions[0].name}`
19+
: node.value;
20+
context.report({
21+
node,
22+
message: `Raw text (${errorValue.trim()}) cannot be used outside of a <Text> tag`,
23+
});
24+
};
25+
26+
const getValidation = node => elementName(node.parent) !== 'Text';
27+
28+
return {
29+
Literal(node) {
30+
const parentType = node.parent.type;
31+
const onlyFor = ['JSXExpressionContainer', 'JSXElement'];
32+
if (/^[\s]+$/.test(node.value) ||
33+
typeof node.value !== 'string' ||
34+
!onlyFor.includes(parentType) ||
35+
(node.parent.parent && node.parent.parent.type === 'JSXAttribute')
36+
) return;
37+
38+
const isStringLiteral = parentType === 'JSXExpressionContainer';
39+
if (getValidation(isStringLiteral ? node.parent : node)) {
40+
report(node);
41+
}
42+
},
43+
44+
JSXText(node) {
45+
if (getValidation(node)) {
46+
report(node);
47+
}
48+
},
49+
50+
TemplateLiteral(node) {
51+
if (
52+
node.parent.type !== 'JSXExpressionContainer' ||
53+
(node.parent.parent && node.parent.parent.type === 'JSXAttribute')
54+
) return;
55+
56+
if (getValidation(node.parent)) {
57+
report(node);
58+
}
59+
},
60+
};
61+
};
62+
63+
module.exports.schema = [];

tests/lib/rules/no-raw-text.js

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
/**
2+
* @fileoverview Detects raw text outside of Text component
3+
* @author Alex Zhukov
4+
*/
5+
6+
'use strict';
7+
8+
// ------------------------------------------------------------------------------
9+
// Requirements
10+
// ------------------------------------------------------------------------------
11+
12+
const rule = require('../../../lib/rules/no-raw-text');
13+
const RuleTester = require('eslint').RuleTester;
14+
15+
require('babel-eslint');
16+
17+
// ------------------------------------------------------------------------------
18+
// Tests
19+
// ------------------------------------------------------------------------------
20+
21+
const ruleTester = new RuleTester();
22+
23+
const tests = {
24+
valid: [
25+
{
26+
code: `
27+
export default class MyComponent extends Component {
28+
render() {
29+
return (<View><Text>some text</Text></View>);
30+
}
31+
}
32+
`,
33+
},
34+
{
35+
code: `
36+
export default class MyComponent extends Component {
37+
render() {
38+
const text = 'some text';
39+
return (<View><Text>{\`\${text}\`}</Text></View>);
40+
}
41+
}
42+
`,
43+
},
44+
{
45+
code: `
46+
export default class MyComponent extends Component {
47+
render() {
48+
return (<View><Text>{'some text'}</Text></View>);
49+
}
50+
}
51+
`,
52+
},
53+
],
54+
invalid: [
55+
{
56+
code: `
57+
export default class MyComponent extends Component {
58+
render() {
59+
return (<View>some text</View>);
60+
}
61+
}
62+
`,
63+
errors: [{
64+
message: 'Raw text (some text) cannot be used outside of a <Text> tag',
65+
}],
66+
},
67+
{
68+
code: `
69+
export default class MyComponent extends Component {
70+
render() {
71+
const text = 'some text';
72+
return (<View>{\`\${text}\`}</View>);
73+
}
74+
}
75+
`,
76+
errors: [{
77+
message: 'Raw text (TemplateLiteral: text) cannot be used outside of a <Text> tag',
78+
}],
79+
},
80+
{
81+
code: `
82+
export default class MyComponent extends Component {
83+
render() {
84+
return (<View>{'some text'}</View>);
85+
}
86+
}
87+
`,
88+
errors: [{
89+
message: 'Raw text (some text) cannot be used outside of a <Text> tag',
90+
}],
91+
},
92+
],
93+
};
94+
95+
const config = {
96+
parser: 'babel-eslint',
97+
parserOptions: {
98+
ecmaFeatures: {
99+
classes: true,
100+
jsx: true,
101+
},
102+
},
103+
};
104+
105+
tests.valid.forEach(t => Object.assign(t, config));
106+
tests.invalid.forEach(t => Object.assign(t, config));
107+
108+
ruleTester.run('no-raw-text', rule, tests);

0 commit comments

Comments
 (0)