Skip to content

Commit

Permalink
feat: add require-indexer-name rule (#425)
Browse files Browse the repository at this point in the history
* Add require-indexer-name rule

* Add require-indexer-name docs
  • Loading branch information
goodmind authored and gajus committed Aug 9, 2019
1 parent 091fbf3 commit 83b48d5
Show file tree
Hide file tree
Showing 7 changed files with 110 additions and 0 deletions.
1 change: 1 addition & 0 deletions .README/README.md
Expand Up @@ -174,6 +174,7 @@ When `true`, only checks files with a [`@flow` annotation](http://flowtype.org/d
{"gitdown": "include", "file": "./rules/object-type-delimiter.md"}
{"gitdown": "include", "file": "./rules/require-compound-type-alias.md"}
{"gitdown": "include", "file": "./rules/require-exact-type.md"}
{"gitdown": "include", "file": "./rules/require-indexer-name.md"}
{"gitdown": "include", "file": "./rules/require-inexact-type.md"}
{"gitdown": "include", "file": "./rules/require-parameter-type.md"}
{"gitdown": "include", "file": "./rules/require-readonly-react-props.md"}
Expand Down
23 changes: 23 additions & 0 deletions .README/rules/require-indexer-name.md
@@ -0,0 +1,23 @@
### `require-indexer-name`

This rule validates Flow object indexer name.

#### Options

The rule has a string option:

* `"never"` (default): Never report files that are missing an indexer key name.
* `"always"`: Always report files that are missing an indexer key name.

```js
{
"rules": {
"flowtype/require-indexer-name": [
2,
"always"
]
}
}
```

<!-- assertions requireIndexerName -->
2 changes: 2 additions & 0 deletions src/index.js
Expand Up @@ -17,6 +17,7 @@ import noUnusedExpressions from './rules/noUnusedExpressions';
import noWeakTypes from './rules/noWeakTypes';
import noMixed from './rules/noMixed';
import objectTypeDelimiter from './rules/objectTypeDelimiter';
import requireIndexerName from './rules/requireIndexerName';
import requireCompoundTypeAlias from './rules/requireCompoundTypeAlias';
import requireInexactType from './rules/requireInexactType';
import requireExactType from './rules/requireExactType';
Expand Down Expand Up @@ -61,6 +62,7 @@ const rules = {
'object-type-delimiter': objectTypeDelimiter,
'require-compound-type-alias': requireCompoundTypeAlias,
'require-exact-type': requireExactType,
'require-indexer-name': requireIndexerName,
'require-inexact-type': requireInexactType,
'require-parameter-type': requireParameterType,
'require-readonly-react-props': requireReadonlyReactProps,
Expand Down
33 changes: 33 additions & 0 deletions src/rules/requireIndexerName.js
@@ -0,0 +1,33 @@
import {getParameterName} from '../utilities';

const schema = [
{
enum: ['always', 'never'],
type: 'string',
},
];

const create = (context) => {
const always = (context.options[0] || 'always') === 'always';

if (always) {
return {
ObjectTypeIndexer (node) {
const id = getParameterName(node, context);
if (id === null) {
context.report({
message: 'All indexers must be declared with key name.',
node,
});
}
},
};
} else {
return {};
}
};

export default {
create,
schema,
};
24 changes: 24 additions & 0 deletions src/utilities/getParameterName.js
Expand Up @@ -33,6 +33,30 @@ export default (identifierNode, context) => {
return context.getSourceCode().getFirstToken(identifierNode, tokenIndex).value;
}

if (identifierNode.type === 'ObjectTypeIndexer') {
let tokenIndex;

tokenIndex = 0;

if (identifierNode.static) {
tokenIndex++;
}

if (identifierNode.variance) {
tokenIndex++;
}

tokenIndex++;

const id = context.getSourceCode().getFirstToken(identifierNode, tokenIndex);
const colonOrBrace = context.getSourceCode().getTokenAfter(id);
if (colonOrBrace.value === ':') {
return id.value;
} else {
return null;
}
}

if (identifierNode.type === 'FunctionTypeParam') {
return context.getSourceCode().getFirstToken(identifierNode).value;
}
Expand Down
26 changes: 26 additions & 0 deletions tests/rules/assertions/requireIndexerName.js
@@ -0,0 +1,26 @@
export default {
invalid: [
{
code: 'type foo = { [string]: number };',
errors: [
{message: 'All indexers must be declared with key name.'},
],
},
],
valid: [
{
code: 'type foo = { [key: string]: number };',
errors: [],
},
{
code: 'type foo = { [key: string]: number };',
errors: [],
options: ['never'],
},
{
code: 'type foo = { [string]: number };',
errors: [],
options: ['never'],
},
],
};
1 change: 1 addition & 0 deletions tests/rules/index.js
Expand Up @@ -31,6 +31,7 @@ const reportingRules = [
'object-type-delimiter',
'require-compound-type-alias',
'require-inexact-type',
'require-indexer-name',
'require-exact-type',
'require-parameter-type',
'require-readonly-react-props',
Expand Down

0 comments on commit 83b48d5

Please sign in to comment.