Skip to content

Commit

Permalink
feat: add no-types-missing-flow-annotation (#222)
Browse files Browse the repository at this point in the history
* feat: disallow types in files missing a file annotation

* chore: add doc entry

* fix: ignore flow files

* fix: renamed to avoid flow auto include the file in some setups

* chore: clean up, add valid test cases

* feat: Allow types in files with an @noflow annotation.
  • Loading branch information
micaste authored and gajus committed Apr 18, 2017
1 parent 636cead commit 4e191b7
Show file tree
Hide file tree
Showing 6 changed files with 127 additions and 4 deletions.
13 changes: 13 additions & 0 deletions .README/rules/no-types-missing-flow-annotation.md
@@ -0,0 +1,13 @@
### `no-types-missing-file-annotation`

Disallows Flow type imports, aliases, and annotations in files missing a valid Flow file declaration (or a @noflow annotation).

```js
{
"rules": {
"flowtype/no-types-missing-file-annotation": 2
}
}
```

<!-- assertions noTypesMissingFileAnnotation -->
8 changes: 7 additions & 1 deletion src/index.js
Expand Up @@ -3,6 +3,7 @@ import {checkFlowFileAnnotation} from './utilities';
import defineFlowType from './rules/defineFlowType';
import genericSpacing from './rules/genericSpacing';
import noWeakTypes from './rules/noWeakTypes';
import noTypesMissingFileAnnotation from './rules/noTypesMissingFileAnnotation';
import requireParameterType from './rules/requireParameterType';
import requireReturnType from './rules/requireReturnType';
import requireValidFileAnnotation from './rules/requireValidFileAnnotation';
Expand Down Expand Up @@ -30,6 +31,7 @@ const rules = {
'generic-spacing': genericSpacing,
'no-dupe-keys': noDupeKeys,
'no-primitive-constructor-types': noPrimitiveConstructorTypes,
'no-types-missing-file-annotation': noTypesMissingFileAnnotation,
'no-weak-types': noWeakTypes,
'object-type-delimiter': objectTypeDelimiter,
'require-parameter-type': requireParameterType,
Expand All @@ -51,7 +53,7 @@ export default {
configs: {
recommended
},
rules: _.mapValues(rules, (rule) => {
rules: _.mapValues(rules, (rule, key) => {
// Support current and deprecated rule formats
if (_.isPlainObject(rule)) {
return {
Expand All @@ -60,6 +62,10 @@ export default {
};
}

if (key === 'no-types-missing-file-annotation') {
return rule;
}

return _.partial(checkFlowFileAnnotation, rule);
}),
rulesConfig: {
Expand Down
39 changes: 39 additions & 0 deletions src/rules/noTypesMissingFileAnnotation.js
@@ -0,0 +1,39 @@
import {isFlowFile} from '../utilities';

/**
* Disallows the use for flow types without a valid file annotation.
* Only checks files without a valid flow annotation.
*/

export default (context) => {
// Skip flow files
if (isFlowFile(context, false)) {
return {};
}

const reporter = (node, type) => {
context.report({
data: {type},
message: 'Type {{type}} require valid Flow declaration.',
node
});
};

return {
ImportDeclaration (node) {
if (node.importKind === 'type') {
reporter(node, 'imports');
}
if (node.importKind === 'value' &&
node.specifiers.some((specifier) => { return specifier.importKind === 'type'; })) {
reporter(node, 'imports');
}
},
TypeAlias (node) {
reporter(node, 'aliases');
},
TypeAnnotation (node) {
reporter(node, 'annotations');
}
};
};
13 changes: 10 additions & 3 deletions src/utilities/isFlowFile.js
@@ -1,6 +1,13 @@
import isFlowFileAnnotation from './isFlowFileAnnotation.js';

export default (context) => {
/* eslint-disable flowtype/require-valid-file-annotation */
/**
* Checks whether a file has an @flow or @noflow annotation.
* @param context
* @param [strict] - By default, the function returns true if the file starts with @flow but not if it
* starts by @noflow. When the strict flag is set to false, the function returns true if the flag has @noflow also.
*/
/* eslint-enable flowtype/require-valid-file-annotation */
export default (context, strict = true) => {
const comments = context.getAllComments();

if (!comments.length) {
Expand All @@ -9,5 +16,5 @@ export default (context) => {

const firstComment = comments[0];

return isFlowFileAnnotation(firstComment.value) && !/no/.test(firstComment.value);
return isFlowFileAnnotation(firstComment.value) && !(strict && /no/.test(firstComment.value));
};
57 changes: 57 additions & 0 deletions tests/rules/assertions/noTypesMissingFileAnnotation.js
@@ -0,0 +1,57 @@
export default {
invalid: [
{
code: 'const x: number = 42;',
errors: [{
message: 'Type annotations require valid Flow declaration.'
}]
},
{
code: 'type FooType = number;',
errors: [{
message: 'Type aliases require valid Flow declaration.'
}]
},
{
code: 'import type A from "a"',
errors: [{
message: 'Type imports require valid Flow declaration.'
}]
},
{
code: 'import type {A} from "a"',
errors: [{
message: 'Type imports require valid Flow declaration.'
}]
},
{
code: 'import {type A} from "a"',
errors: [{
message: 'Type imports require valid Flow declaration.'
}]
},
{
code: 'function t<T>(): T{}',
errors: [{
message: 'Type annotations require valid Flow declaration.'
}]
}
],
valid: [
{
code: '// @flow\nconst x: number = 42;'
},
{
code: '/* @flow weak */\ntype FooType = number;'
},
{
code: '/* @noflow */\ntype FooType = number;'
},
{
code: '/* @noflow */\nimport type A from "a"'
},
{
code: '/* @noflow */\nimport {type A} from "a"'
}
]
};
1 change: 1 addition & 0 deletions tests/rules/index.js
Expand Up @@ -14,6 +14,7 @@ const reportingRules = [
'no-dupe-keys',
'no-weak-types',
'no-primitive-constructor-types',
'no-types-missing-file-annotation',
'object-type-delimiter',
'require-parameter-type',
'require-return-type',
Expand Down

0 comments on commit 4e191b7

Please sign in to comment.