Skip to content
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ Alternatively, you can enable all the recommended rules at once by adding `plugi
- [has-valid-accessibility-states](docs/rules/has-valid-accessibility-states.md): Enforce `accessibilityStates` property value is valid
- [has-valid-accessibility-component-type](docs/rules/has-valid-accessibility-component-type.md): Enforce `accessibilityComponentType` property value is valid
- [has-valid-accessibility-traits](docs/rules/has-valid-accessibility-traits.md): Enforce `accessibilityTraits` and `accessibilityComponentType` prop values must be valid
- [has-valid-accessibility-value](docs/rules/has-valid-accessibility-value.md): Enforce `accessibilityValue` property value is valid
- [has-valid-accessibility-live-region](docs/rules/has-valid-accessibility-live-region.md): Enforce `accessibilityLiveRegion` prop values must be valid
- [has-valid-important-for-accessibility](docs/rules/has-valid-important-for-accessibility.md): Enforce `importantForAccessibility` property value is valid
- [no-nested-touchables](docs/rules/no-nested-touchables.md): Enforce if a view has `accessible={true}`, that there are no touchable elements inside
Expand Down
91 changes: 91 additions & 0 deletions __tests__/src/rules/has-valid-accessibility-value-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/* eslint-env jest */
/**
* @fileoverview Represents the current value of a component.
* @author JP Driver
*/

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

import { RuleTester } from 'eslint';
import parserOptionsMapper from '../../__util__/parserOptionsMapper';
import rule from '../../../src/rules/has-valid-accessibility-value';

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

const ruleTester = new RuleTester();

ruleTester.run('has-valid-accessibility-value', rule, {
valid: [
{
code:
'<TouchableOpacity accessibilityValue={{ min: 0, now: 50, max: 100 }} />'
},
{ code: '<TouchableOpacity accessibilityValue={{ text: "foo" }} />' }
].map(parserOptionsMapper),
invalid: [
{
code:
'<TouchableOpacity accessibilityValue={{ min: 0, now: 50, max: 100, text: "foo" }} />',
errors: [
{
message:
'accessibilityValue object must only contain either min, now, max *or* text',
type: 'JSXAttribute'
}
]
},
{
code: '<TouchableOpacity accessibilityValue={{ now: 50 }} />',
errors: [
{
message: 'accessibilityValue object is missing min value',
type: 'JSXAttribute'
},
{
message: 'accessibilityValue object is missing max value',
type: 'JSXAttribute'
}
]
},
{
code: '<TouchableOpacity accessibilityValue="foo" />',
errors: [
{
message: 'accessibilityValue must be an object',
type: 'JSXAttribute'
}
]
},
{
code:
'<TouchableOpacity accessibilityValue={{ min: "0", now: "50", max: "100" }} />',
errors: [
{
message: 'accessibilityValue min value must be an integer',
type: 'JSXAttribute'
},
{
message: 'accessibilityValue now value must be an integer',
type: 'JSXAttribute'
},
{
message: 'accessibilityValue max value must be an integer',
type: 'JSXAttribute'
}
]
},
{
code: '<TouchableOpacity accessibilityValue={{ text: 0 }} />',
errors: [
{
message: 'accessibilityValue text value must be a string',
type: 'JSXAttribute'
}
]
}
].map(parserOptionsMapper)
});
41 changes: 41 additions & 0 deletions docs/rules/has-valid-accessibility-value.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# has-valid-accessibility-value

Represents the current value of a component.

## `accessibilityValue` is an object. It should contain either one of the following field sets:

NAME|DESCRIPTION|TYPE|REQUIRED
-|-|-|-
min|The minimum value of this component's range.|integer|Required if `now` is set.
max|The maximum value of this component's range.|integer|Required if `now` is set.
now|The current value of this component's range.|integer|No

NAME|DESCRIPTION|TYPE|REQUIRED
-|-|-|-
text|A textual description of this component's value.|string|No


### References

1. [React Native Docs - accessibilityValue (iOS, Android)](https://facebook.github.io/react-native/docs/accessibility#accessibilityvalue-ios-android)

## Rule details

This rule takes no arguments.

### Succeed

```jsx
<TouchableOpacity accessibilityValue={{ min: 0, now: 50, max: 100 }} />
<TouchableOpacity accessibilityValue={{ text: "foo" }} />
```

### Fail

```jsx
<TouchableOpacity accessibilityValue={{ min: 0, now: 50, max: 100, text: "foo" }} />
<TouchableOpacity accessibilityValue={{ now: 50 }} />
<TouchableOpacity accessibilityValue="foo" />
<TouchableOpacity accessibilityValue={{ min: "0", now: "50", max: "100" }} />
<TouchableOpacity accessibilityValue={{ text: 0 }} />
```
2 changes: 2 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ module.exports = {
'has-valid-accessibility-state': require('./rules/has-valid-accessibility-state'),
'has-valid-accessibility-states': require('./rules/has-valid-accessibility-states'),
'has-valid-accessibility-traits': require('./rules/has-valid-accessibility-traits'),
'has-valid-accessibility-value': require('./rules/has-valid-accessibility-value'),
'has-valid-important-for-accessibility': require('./rules/has-valid-important-for-accessibility'),
'no-nested-touchables': require('./rules/no-nested-touchables')
},
Expand All @@ -28,6 +29,7 @@ module.exports = {
'react-native-a11y/has-valid-accessibility-role': 'error',
'react-native-a11y/has-valid-accessibility-states': 'error',
'react-native-a11y/has-valid-accessibility-traits': 'error',
'react-native-a11y/has-valid-accessibility-value': 'error',
'react-native-a11y/has-valid-important-for-accessibility': 'error',
'react-native-a11y/no-nested-touchables': 'error'
}
Expand Down
77 changes: 77 additions & 0 deletions src/rules/has-valid-accessibility-value.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/**
* @fileoverview Represents the current value of a component.
* @author JP Driver
* @flow
*/

import type { JSXAttribute } from 'ast-types-flow';
import { elementType, getPropValue, getLiteralPropValue } from 'jsx-ast-utils';
import { generateObjSchema } from '../util/schemas';
import type { ESLintContext } from '../../flow/eslint';

// ----------------------------------------------------------------------------
// Rule Definition
// ----------------------------------------------------------------------------

module.exports = {
meta: {
docs: {},
schema: [generateObjSchema()]
},

create: (context: ESLintContext) => ({
JSXAttribute: (node: JSXAttribute) => {
const attrName = elementType(node);
if (attrName === 'accessibilityValue') {
const attrValue = getPropValue(node);

const error = message =>
context.report({
node,
message
});

if (typeof attrValue !== 'object' || Array.isArray(attrValue)) {
error('accessibilityValue must be an object');
} else {
const keys = Object.keys(attrValue);
if (keys.indexOf('now') > -1 && keys.indexOf('min') < 0) {
error('accessibilityValue object is missing min value');
}
if (keys.indexOf('now') > -1 && keys.indexOf('max') < 0) {
error('accessibilityValue object is missing max value');
}
if (keys.indexOf('text') > -1 && keys.length > 1) {
error(
'accessibilityValue object must only contain either min, now, max *or* text'
);
}
if (
keys.indexOf('min') > -1 &&
typeof attrValue['min'] !== 'number'
) {
error('accessibilityValue min value must be an integer');
}
if (
keys.indexOf('now') > -1 &&
typeof attrValue['now'] !== 'number'
) {
error('accessibilityValue now value must be an integer');
}
if (
keys.indexOf('max') > -1 &&
typeof attrValue['max'] !== 'number'
) {
error('accessibilityValue max value must be an integer');
}
if (
keys.indexOf('text') > -1 &&
typeof attrValue['text'] !== 'string'
) {
error('accessibilityValue text value must be a string');
}
}
}
}
})
};