Skip to content

Commit

Permalink
feat: Interface Id Match rule (#492)
Browse files Browse the repository at this point in the history
* create rule and tests

* reset readme

* update naming conventions
  • Loading branch information
Jermayy committed Aug 2, 2021
1 parent c40937a commit d7abd9f
Show file tree
Hide file tree
Showing 7 changed files with 128 additions and 6 deletions.
5 changes: 5 additions & 0 deletions .README/README.md
Expand Up @@ -54,6 +54,10 @@ npm install eslint babel-eslint eslint-plugin-flowtype --save-dev
2,
"never"
],
"flowtype/interface-id-match": [
2,
"^([A-Z][a-z0-9]+)+Type$"
],
"flowtype/no-mixed": 2,
"flowtype/no-primitive-constructor-types": 2,
"flowtype/no-types-missing-file-annotation": 2,
Expand Down Expand Up @@ -162,6 +166,7 @@ When `true`, only checks files with a [`@flow` annotation](http://flowtype.org/d
{"gitdown": "include", "file": "./rules/delimiter-dangle.md"}
{"gitdown": "include", "file": "./rules/enforce-line-break.md"}
{"gitdown": "include", "file": "./rules/generic-spacing.md"}
{"gitdown": "include", "file": "./rules/interface-id-match.md"}
{"gitdown": "include", "file": "./rules/newline-after-flow-annotation.md"}
{"gitdown": "include", "file": "./rules/no-dupe-keys.md"}
{"gitdown": "include", "file": "./rules/no-existential-type.md"}
Expand Down
22 changes: 22 additions & 0 deletions .README/rules/interface-id-match.md
@@ -0,0 +1,22 @@
### `interface-id-match`

Enforces a consistent naming pattern for interfaces.

#### Options

This rule requires a text RegExp:

```js
{
"rules": {
"flowtype/interface-id-match": [
2,
"^([A-Z][a-z0-9]*)+Type$"
]
}
}
```

`'^([A-Z][a-z0-9]*)+Type$$'` is the default pattern.

<!-- assertions interfaceIdMatch -->
11 changes: 5 additions & 6 deletions README.md
Expand Up @@ -1870,7 +1870,7 @@ import Foo from './foo';
// Message: Expected newline after flow annotation

// Options: ["always-windows"]
// @flow
// @flow
import Foo from './foo';
// Message: Expected newline after flow annotation

Expand All @@ -1890,8 +1890,8 @@ The following patterns are not considered problems:
import Foo from './foo';

// Options: ["always-windows"]
// @flow

// @flow

import Foo from './foo';

// Options: ["never"]
Expand Down Expand Up @@ -3028,7 +3028,7 @@ The rule has two options:
}
```
* `allowNull` allows compound types where one of the members is a `null`, e.g. `string | null`.
* `allowNull` allows compound types where one of the members is a `null`, e.g. `string | null`.
The following patterns are considered problems:
Expand Down Expand Up @@ -5392,7 +5392,7 @@ The following patterns are not considered problems:
{ a: string, b: number }) => {}
// Options: ["always",{"allowLineBreak":true}]
(foo:
(foo:
{ a: string, b: number }) => {}
// Options: ["never"]
Expand Down Expand Up @@ -6719,4 +6719,3 @@ function x(foo: Type = bar()) {}
```
3 changes: 3 additions & 0 deletions src/index.js
Expand Up @@ -8,6 +8,7 @@ import defineFlowType from './rules/defineFlowType';
import delimiterDangle from './rules/delimiterDangle';
import enforceLineBreak from './rules/enforceLineBreak';
import genericSpacing from './rules/genericSpacing';
import interfaceIdMatch from './rules/interfaceIdMatch';
import newlineAfterFlowAnnotation from './rules/newlineAfterFlowAnnotation';
import noDupeKeys from './rules/noDupeKeys';
import noExistentialType from './rules/noExistentialType';
Expand Down Expand Up @@ -56,6 +57,7 @@ const rules = {
'delimiter-dangle': delimiterDangle,
'enforce-line-break': enforceLineBreak,
'generic-spacing': genericSpacing,
'interface-id-match': interfaceIdMatch,
'newline-after-flow-annotation': newlineAfterFlowAnnotation,
'no-dupe-keys': noDupeKeys,
'no-existential-type': noExistentialType,
Expand Down Expand Up @@ -113,6 +115,7 @@ export default {
'define-flow-type': 0,
'delimiter-dangle': 0,
'generic-spacing': 0,
'interface-id-match': 0,
'newline-after-flow-annotation': 0,
'no-dupe-keys': 0,
'no-flow-fix-me-comments': 0,
Expand Down
29 changes: 29 additions & 0 deletions src/rules/interfaceIdMatch.js
@@ -0,0 +1,29 @@
const schema = [
{
type: 'string',
},
];

const create = (context) => {
const pattern = new RegExp(context.options[0] || '^([A-Z][a-z0-9]*)+Type$');

const checkInterface = (interfaceDeclarationNode) => {
const interfaceIdentifierName = interfaceDeclarationNode.id.name;

if (!pattern.test(interfaceIdentifierName)) {
context.report(interfaceDeclarationNode, 'Interface identifier \'{{name}}\' does not match pattern \'{{pattern}}\'.', {
name: interfaceIdentifierName,
pattern: pattern.toString(),
});
}
};

return {
InterfaceDeclaration: checkInterface,
};
};

export default {
create,
schema,
};
63 changes: 63 additions & 0 deletions tests/rules/assertions/interfaceIdMatch.js
@@ -0,0 +1,63 @@
export default {
invalid: [
{
code: 'interface foo{};',
errors: [
{
message: 'Interface identifier \'foo\' does not match pattern \'/^([A-Z][a-z0-9]*)+Type$/\'.',
},
],
},
{
code: 'interface FooType{};',
errors: [
{
message: 'Interface identifier \'FooType\' does not match pattern \'/^foo$/\'.',
},
],
options: [
'^foo$',
],
},
],
misconfigured: [
{
errors: [
{
data: 7,
dataPath: '[0]',
keyword: 'type',
message: 'should be string',
params: {
type: 'string',
},
parentSchema: {
type: 'string',
},
schema: 'string',
schemaPath: '#/items/0/type',
},
],
options: [7],
},
],
valid: [
{
code: 'interface FooType {};',
},
{
code: 'interface foo {};',
options: [
'^foo$',
],
},
{
code: 'interface foo {};',
settings: {
flowtype: {
onlyFilesWithFlowAnnotation: true,
},
},
},
],
};
1 change: 1 addition & 0 deletions tests/rules/index.js
Expand Up @@ -19,6 +19,7 @@ const reportingRules = [
'delimiter-dangle',
'enforce-line-break',
'generic-spacing',
'interface-id-match',
'newline-after-flow-annotation',
'no-dupe-keys',
'no-existential-type',
Expand Down

0 comments on commit d7abd9f

Please sign in to comment.