Skip to content

Commit

Permalink
feat: add type-import-style rule (#320)
Browse files Browse the repository at this point in the history
  • Loading branch information
danwang authored and gajus committed Feb 21, 2018
1 parent 74bcb8c commit 3c67223
Show file tree
Hide file tree
Showing 6 changed files with 118 additions and 0 deletions.
1 change: 1 addition & 0 deletions .README/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ When `true`, only checks files with a [`@flow` annotation](http://flowtype.org/d
{"gitdown": "include", "file": "./rules/space-before-generic-bracket.md"}
{"gitdown": "include", "file": "./rules/space-before-type-colon.md"}
{"gitdown": "include", "file": "./rules/type-id-match.md"}
{"gitdown": "include", "file": "./rules/type-import-style.md"}
{"gitdown": "include", "file": "./rules/union-intersection-spacing.md"}
{"gitdown": "include", "file": "./rules/use-flow-type.md"}
{"gitdown": "include", "file": "./rules/valid-syntax.md"}
22 changes: 22 additions & 0 deletions .README/rules/type-import-style.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
### `type-import-style`

_The `--fix` option on the command line automatically fixes problems reported by this rule._

Enforces a particular style for type imports:

```
// 'identifier' style
import {type T, type U, type V} from '...';
// 'declaration' style
import type {T, U, V} from '...';
```

The rule has a string option:

* `"identifier"` (default): Enforces that type imports are all in the
'identifier' style.
* `"declaration"`: Enforces that type imports are all in the 'declaration'
style.

<!-- assertions typeImportStyle -->
3 changes: 3 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import spaceAfterTypeColon from './rules/spaceAfterTypeColon';
import spaceBeforeGenericBracket from './rules/spaceBeforeGenericBracket';
import spaceBeforeTypeColon from './rules/spaceBeforeTypeColon';
import typeIdMatch from './rules/typeIdMatch';
import typeImportStyle from './rules/typeImportStyle';
import unionIntersectionSpacing from './rules/unionIntersectionSpacing';
import useFlowType from './rules/useFlowType';
import validSyntax from './rules/validSyntax';
Expand Down Expand Up @@ -58,6 +59,7 @@ const rules = {
'space-before-generic-bracket': spaceBeforeGenericBracket,
'space-before-type-colon': spaceBeforeTypeColon,
'type-id-match': typeIdMatch,
'type-import-style': typeImportStyle,
'union-intersection-spacing': unionIntersectionSpacing,
'use-flow-type': useFlowType,
'valid-syntax': validSyntax
Expand Down Expand Up @@ -98,6 +100,7 @@ export default {
'space-before-generic-bracket': 0,
'space-before-type-colon': 0,
'type-id-match': 0,
'type-import-style': 0,
'union-intersection-spacing': 0,
'use-flow-type': 0,
'valid-syntax': 0
Expand Down
53 changes: 53 additions & 0 deletions src/rules/typeImportStyle.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
const schema = [
{
enum: ['declaration', 'identifier'],
type: 'string'
}
];

const create = (context) => {
if (context.options[0] === 'declaration') {
return {
ImportDeclaration (node) {
if (node.importKind !== 'type') {
node.specifiers.forEach((specifier) => {
if (specifier.importKind === 'type') {
context.report({
message: 'Unexpected type import',
node
});
}
});
}
}
};
} else {
// Default to 'identifier'
return {
ImportDeclaration (node) {
if (node.importKind === 'type') {
context.report({
fix (fixer) {
const imports = node.specifiers.map((specifier) => {
return 'type ' + specifier.local.name;
});
const source = node.source.value;

return fixer.replaceText(node,
'import {' + imports.join(', ') + '} from \'' + source + '\';'
);
},
message: 'Unexpected "import type"',
node
});
}
}
};
}
};

export default {
create,
schema
};

38 changes: 38 additions & 0 deletions tests/rules/assertions/typeImportStyle.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
export default {
invalid: [
{
code: 'import type {A, B} from \'a\';',
errors: [{message: 'Unexpected "import type"'}],
output: 'import {type A, type B} from \'a\';'
},
{
code: 'import type {A, B} from \'a\';',
errors: [{message: 'Unexpected "import type"'}],
options: ['identifier'],
output: 'import {type A, type B} from \'a\';'
},
{
code: 'import {type A, type B} from \'a\';',
errors: [
{message: 'Unexpected type import'},
{message: 'Unexpected type import'}
],
options: ['declaration']
}
],
valid: [
{
code: 'import {type A, type B} from \'a\';'
},
{
code: 'import {type A, type B} from \'a\';',
options: ['identifier']
},
{
code: 'import type {A, B} from \'a\';',
options: ['declaration']
}
]
};


1 change: 1 addition & 0 deletions tests/rules/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ const reportingRules = [
'space-before-generic-bracket',
'space-before-type-colon',
'type-id-match',
'type-import-style',
'union-intersection-spacing',
'use-flow-type',
'valid-syntax'
Expand Down

0 comments on commit 3c67223

Please sign in to comment.