Skip to content

Commit

Permalink
feat: add require-compound-type-alias (#365)
Browse files Browse the repository at this point in the history
  • Loading branch information
pnevyk authored and gajus committed Oct 26, 2018
1 parent 5e2bbe9 commit 6585121
Show file tree
Hide file tree
Showing 5 changed files with 148 additions and 0 deletions.
14 changes: 14 additions & 0 deletions .README/rules/require-compound-type-alias.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
### `require-compound-type-alias`

Requires to make a type alias for all [union](https://flow.org/en/docs/types/unions/) and [intersection](https://flow.org/en/docs/types/intersections/) types. If these are used in "raw" forms it might be tempting to just copy&paste them around the code. However, this brings sort of a source code pollution and unnecessary changes on several parts when these compound types need to be changed.

#### Options

The rule has a string option:

* `"never"`
* `"always"`

The default value is `"always"`.

<!-- assertions require-compound-type-alias -->
3 changes: 3 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import noTypesMissingFileAnnotation from './rules/noTypesMissingFileAnnotation';
import noUnusedExpressions from './rules/noUnusedExpressions';
import noWeakTypes from './rules/noWeakTypes';
import objectTypeDelimiter from './rules/objectTypeDelimiter';
import requireCompoundTypeAlias from './rules/requireCompoundTypeAlias';
import requireExactType from './rules/requireExactType';
import requireParameterType from './rules/requireParameterType';
import requireReturnType from './rules/requireReturnType';
Expand Down Expand Up @@ -51,6 +52,7 @@ const rules = {
'no-unused-expressions': noUnusedExpressions,
'no-weak-types': noWeakTypes,
'object-type-delimiter': objectTypeDelimiter,
'require-compound-type-alias': requireCompoundTypeAlias,
'require-exact-type': requireExactType,
'require-parameter-type': requireParameterType,
'require-return-type': requireReturnType,
Expand Down Expand Up @@ -94,6 +96,7 @@ export default {
'no-mutable-array': 0,
'no-weak-types': 0,
'object-type-delimiter': 0,
'require-compound-type-alias': 0,
'require-exact-type': 0,
'require-parameter-type': 0,
'require-return-type': 0,
Expand Down
38 changes: 38 additions & 0 deletions src/rules/requireCompoundTypeAlias.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
const schema = [
{
enum: ['always', 'never'],
type: 'string'
}
];

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

if (always) {
return {
IntersectionTypeAnnotation (node) {
if (node.parent.type !== 'TypeAlias') {
context.report({
message: 'All intersection types must be declared with named type alias.',
node
});
}
},
UnionTypeAnnotation (node) {
if (node.parent.type !== 'TypeAlias') {
context.report({
message: 'All union types must be declared with named type alias.',
node
});
}
}
};
} else {
return {};
}
};

export default {
create,
schema
};
92 changes: 92 additions & 0 deletions tests/rules/assertions/requireCompoundTypeAlias.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
export default {
invalid: [
{
code: 'function foo(bar: "A" | "B") {}',
errors: [{message: 'All union types must be declared with named type alias.'}]
},
{
code: 'const foo: "A" | "B" = "A";',
errors: [{message: 'All union types must be declared with named type alias.'}]
},
{
code: 'type Foo = { bar: "A" | "B" };',
errors: [{message: 'All union types must be declared with named type alias.'}]
},
{
code: 'function foo(bar: { n: number } | { s: string }) {}',
errors: [{message: 'All union types must be declared with named type alias.'}]
},
{
code: 'function foo(bar: { n: number } & { s: string }) {}',
errors: [{message: 'All intersection types must be declared with named type alias.'}]
},
{
code: 'const foo: { n: number } & { s: string } = { n: 0, s: "" };',
errors: [{message: 'All intersection types must be declared with named type alias.'}]
},
{
code: 'type Foo = { bar: { n: number } & { s: string } };',
errors: [{message: 'All intersection types must be declared with named type alias.'}]
},
{
code: 'function foo(bar: { n: number } & { s: string }) {}',
errors: [{message: 'All intersection types must be declared with named type alias.'}]
}
],
misconfigured: [
{
errors: [
{
data: 'sometimes',
dataPath: '[0]',
keyword: 'enum',
message: 'should be equal to one of the allowed values',
params: {
allowedValues: [
'always',
'never'
]
},
parentSchema: {
enum: [
'always',
'never'
],
type: 'string'
},
schema: [
'always',
'never'
],
schemaPath: '#/items/0/enum'
}
],
options: ['sometimes']
}
],
valid: [
{
code: 'type Foo = "A" | "B";'
},
{
code: 'type Bar = "A" | "B"; function foo(bar: Bar) {}'
},
{
code: 'type Foo = { disjoint: "A", n: number } | { disjoint: "B", s: string };'
},
{
code: 'type Foo = { n: number } & { s: string };'
},
{
code: 'type Bar = { n: number } & { s: string }; function foo(bar: Bar) {}'
},
{
code: 'function foo(bar: "A" | "B") {}',
options: ['never']
},
{
code: 'function foo(bar: { n: number } & { s: string }) {}',
options: ['never']
}
]
};
1 change: 1 addition & 0 deletions tests/rules/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const reportingRules = [
'no-unused-expressions',
'no-weak-types',
'object-type-delimiter',
'require-compound-type-alias',
'require-exact-type',
'require-parameter-type',
'require-return-type',
Expand Down

0 comments on commit 6585121

Please sign in to comment.