Skip to content

Added no-raw-text rule #201

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 6, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,5 @@ build/Release
# Dependency directory
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
node_modules

.idea
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ Finally, enable all of the rules that you would like to use.
"react-native/split-platform-components": 2,
"react-native/no-inline-styles": 2,
"react-native/no-color-literals": 2,
"react-native/no-raw-text": 2,
}
}
```
Expand All @@ -81,6 +82,7 @@ Finally, enable all of the rules that you would like to use.
* [split-platform-components](docs/rules/split-platform-components.md): Enforce using platform specific filenames when necessary
* [no-inline-styles](docs/rules/no-inline-styles.md): Detect JSX components with inline styles that contain literal values
* [no-color-literals](docs/rules/no-color-literals.md): Detect `StyleSheet` rules and inline styles containing color literals instead of variables
* [no-raw-text](docs/rules/no-raw-text.md): Detect raw text outside of `Text` component

[npm-url]: https://npmjs.org/package/eslint-plugin-react-native
[npm-image]: http://img.shields.io/npm/v/eslint-plugin-react-native.svg?style=flat-square
Expand Down
26 changes: 26 additions & 0 deletions docs/rules/no-raw-text.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Detect raw text outside of Text component
All strings in React Native should be wrapped with a Text component.

## Rule Details

The following patterns are considered warnings:

```js
<View>some text</View>
```

```js
const text = 'some text';
<View>{`${text}`}</View>
```

The following patterns are not considered warnings:

```js
<View><Text>some text</Text></View>
```

```js
const text = 'some text';
<View><Text>{`${text}`}</Text></View>
```
2 changes: 2 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const allRules = {
'no-inline-styles': require('./lib/rules/no-inline-styles'),
'no-color-literals': require('./lib/rules/no-color-literals'),
'split-platform-components': require('./lib/rules/split-platform-components'),
'no-raw-text': require('./lib/rules/no-raw-text'),
};

function configureAsError(rules) {
Expand All @@ -30,6 +31,7 @@ module.exports = {
'no-inline-styles': 0,
'no-color-literals': 0,
'split-platform-components': 0,
'no-raw-text': 0,
},
environments: {
'react-native': {
Expand Down
63 changes: 63 additions & 0 deletions lib/rules/no-raw-text.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/**
* @fileoverview Detects raw text outside of Text component
* @author Alex Zhukov
*/

'use strict';

module.exports = (context) => {
const elementName = node => (
node.openingElement &&
node.openingElement.name &&
node.openingElement.name.type === 'JSXIdentifier' &&
node.openingElement.name.name
);

const report = (node) => {
const errorValue = node.type === 'TemplateLiteral'
? `TemplateLiteral: ${node.expressions[0].name}`
: node.value;
context.report({
node,
message: `Raw text (${errorValue.trim()}) cannot be used outside of a <Text> tag`,
});
};

const getValidation = node => elementName(node.parent) !== 'Text';

return {
Literal(node) {
const parentType = node.parent.type;
const onlyFor = ['JSXExpressionContainer', 'JSXElement'];
if (/^[\s]+$/.test(node.value) ||
typeof node.value !== 'string' ||
!onlyFor.includes(parentType) ||
(node.parent.parent && node.parent.parent.type === 'JSXAttribute')
) return;

const isStringLiteral = parentType === 'JSXExpressionContainer';
if (getValidation(isStringLiteral ? node.parent : node)) {
report(node);
}
},

JSXText(node) {
if (getValidation(node)) {
report(node);
}
},

TemplateLiteral(node) {
if (
node.parent.type !== 'JSXExpressionContainer' ||
(node.parent.parent && node.parent.parent.type === 'JSXAttribute')
) return;

if (getValidation(node.parent)) {
report(node);
}
},
};
};

module.exports.schema = [];
108 changes: 108 additions & 0 deletions tests/lib/rules/no-raw-text.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/**
* @fileoverview Detects raw text outside of Text component
* @author Alex Zhukov
*/

'use strict';

// ------------------------------------------------------------------------------
// Requirements
// ------------------------------------------------------------------------------

const rule = require('../../../lib/rules/no-raw-text');
const RuleTester = require('eslint').RuleTester;

require('babel-eslint');

// ------------------------------------------------------------------------------
// Tests
// ------------------------------------------------------------------------------

const ruleTester = new RuleTester();

const tests = {
valid: [
{
code: `
export default class MyComponent extends Component {
render() {
return (<View><Text>some text</Text></View>);
}
}
`,
},
{
code: `
export default class MyComponent extends Component {
render() {
const text = 'some text';
return (<View><Text>{\`\${text}\`}</Text></View>);
}
}
`,
},
{
code: `
export default class MyComponent extends Component {
render() {
return (<View><Text>{'some text'}</Text></View>);
}
}
`,
},
],
invalid: [
{
code: `
export default class MyComponent extends Component {
render() {
return (<View>some text</View>);
}
}
`,
errors: [{
message: 'Raw text (some text) cannot be used outside of a <Text> tag',
}],
},
{
code: `
export default class MyComponent extends Component {
render() {
const text = 'some text';
return (<View>{\`\${text}\`}</View>);
}
}
`,
errors: [{
message: 'Raw text (TemplateLiteral: text) cannot be used outside of a <Text> tag',
}],
},
{
code: `
export default class MyComponent extends Component {
render() {
return (<View>{'some text'}</View>);
}
}
`,
errors: [{
message: 'Raw text (some text) cannot be used outside of a <Text> tag',
}],
},
],
};

const config = {
parser: 'babel-eslint',
parserOptions: {
ecmaFeatures: {
classes: true,
jsx: true,
},
},
};

tests.valid.forEach(t => Object.assign(t, config));
tests.invalid.forEach(t => Object.assign(t, config));

ruleTester.run('no-raw-text', rule, tests);