From e93f1c0102c03b465bce260b6e085b04e1a0f934 Mon Sep 17 00:00:00 2001 From: andrejs-sisojevs-accenture Date: Tue, 30 Jun 2020 15:29:51 +0300 Subject: [PATCH] feat: add respect to `@noflow` annotation (#451) * fix: general filter for all rules - should be either @flow file, or `onlyFilesWithFlowAnnotation` should not be enabled and file not marked with @noflow * fix: require-valid-file-annotation tests broken with new `checkFlowFileAnnotation` - respect onlyFilesWithFlowAnnotation == true Co-authored-by: Gajus Kuizinas --- src/index.js | 2 +- src/rules/requireValidFileAnnotation.js | 2 +- src/utilities/checkFlowFileAnnotation.js | 3 ++- src/utilities/index.js | 1 + src/utilities/isNoFlowFile.js | 21 +++++++++++++++++++++ src/utilities/isNoFlowFileAnnotation.js | 17 +++++++++++++++++ tests/rules/assertions/requireReturnType.js | 14 ++++++++++++++ 7 files changed, 57 insertions(+), 3 deletions(-) create mode 100644 src/utilities/isNoFlowFile.js create mode 100644 src/utilities/isNoFlowFileAnnotation.js diff --git a/src/index.js b/src/index.js index 33c460dc..6b3fcb77 100644 --- a/src/index.js +++ b/src/index.js @@ -88,7 +88,7 @@ export default { recommended, }, rules: _.mapValues(rules, (rule, key) => { - if (key === 'no-types-missing-file-annotation') { + if (['no-types-missing-file-annotation', 'require-valid-file-annotation'].includes(key)) { return rule; } diff --git a/src/rules/requireValidFileAnnotation.js b/src/rules/requireValidFileAnnotation.js index 51265988..fb0f6ae7 100644 --- a/src/rules/requireValidFileAnnotation.js +++ b/src/rules/requireValidFileAnnotation.js @@ -113,7 +113,7 @@ const create = (context) => { } else { context.report(potentialFlowFileAnnotation, 'Malformed Flow file annotation.'); } - } else if (always) { + } else if (always && !_.get(context, 'settings.flowtype.onlyFilesWithFlowAnnotation')) { context.report({ fix: (fixer) => { let annotation; diff --git a/src/utilities/checkFlowFileAnnotation.js b/src/utilities/checkFlowFileAnnotation.js index 7e923b63..48a32245 100644 --- a/src/utilities/checkFlowFileAnnotation.js +++ b/src/utilities/checkFlowFileAnnotation.js @@ -1,8 +1,9 @@ import _ from 'lodash'; import isFlowFile from './isFlowFile'; +import isNoFlowFile from './isNoFlowFile'; export default (cb, context) => { - const checkThisFile = !_.get(context, 'settings.flowtype.onlyFilesWithFlowAnnotation') || isFlowFile(context); + const checkThisFile = (!_.get(context, 'settings.flowtype.onlyFilesWithFlowAnnotation') && !isNoFlowFile(context)) || isFlowFile(context); // eslint-disable-line no-extra-parens, max-len if (!checkThisFile) { return () => {}; diff --git a/src/utilities/index.js b/src/utilities/index.js index 23c7b2ec..64d80c5f 100644 --- a/src/utilities/index.js +++ b/src/utilities/index.js @@ -9,6 +9,7 @@ export {default as getParameterName} from './getParameterName'; export {default as getTokenAfterParens} from './getTokenAfterParens'; export {default as getTokenBeforeParens} from './getTokenBeforeParens'; export {default as isFlowFile} from './isFlowFile'; +export {default as isNoFlowFile} from './isNoFlowFile'; export {default as isFlowFileAnnotation} from './isFlowFileAnnotation'; export {default as iterateFunctionNodes} from './iterateFunctionNodes'; export {default as quoteName} from './quoteName'; diff --git a/src/utilities/isNoFlowFile.js b/src/utilities/isNoFlowFile.js new file mode 100644 index 00000000..16f905f6 --- /dev/null +++ b/src/utilities/isNoFlowFile.js @@ -0,0 +1,21 @@ +import isNoFlowFileAnnotation from './isNoFlowFileAnnotation'; + +/** + * 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. + */ + +export default (context, strict = true) => { + const comments = context.getAllComments(); + + if (!comments.length) { + return false; + } + + return comments.some((comment) => { + return isNoFlowFileAnnotation(comment.value, strict); + }); +}; diff --git a/src/utilities/isNoFlowFileAnnotation.js b/src/utilities/isNoFlowFileAnnotation.js new file mode 100644 index 00000000..027ba515 --- /dev/null +++ b/src/utilities/isNoFlowFileAnnotation.js @@ -0,0 +1,17 @@ +import _ from 'lodash'; + +const FLOW_MATCHER = /^@noflow$/; + +export default (comment, strict) => { + // The flow parser splits comments with the following regex to look for the @flow flag. + // See https://github.com/facebook/flow/blob/a96249b93541f2f7bfebd8d62085bf7a75de02f2/src/parsing/docblock.ml#L39 + return _.some(comment.split(/[\t\n\r */\\]+/), (commentPart) => { + const match = commentPart.match(FLOW_MATCHER); + + if (match === null) { + return false; + } + + return !strict || match[0] === '@noflow'; + }); +}; diff --git a/tests/rules/assertions/requireReturnType.js b/tests/rules/assertions/requireReturnType.js index 1f6a6daa..b17d2a05 100644 --- a/tests/rules/assertions/requireReturnType.js +++ b/tests/rules/assertions/requireReturnType.js @@ -38,6 +38,14 @@ export default { }, ], }, + { + code: '/* @flow */\n(foo) => { return 1; }', + errors: [ + { + message: 'Missing return type annotation.', + }, + ], + }, { code: '(foo): undefined => { return; }', errors: [ @@ -692,6 +700,12 @@ export default { }, }, }, + { + code: '/* @noflow */\n(foo) => { return 1; }', + options: [ + 'always', + ], + }, { code: '(foo) => { return undefined; }', options: [