From 58796dbd9e2001ff4816db36a6a5fbecd3900b12 Mon Sep 17 00:00:00 2001 From: Brian Chen Date: Thu, 29 Jul 2021 00:37:12 +1000 Subject: [PATCH 1/4] add suppression code rule --- .README/README.md | 1 + .README/rules/enforce-suppression-code.md | 5 ++ src/index.js | 2 + src/rules/enforceSuppressionCode.js | 54 +++++++++++++++++++ .../assertions/enforceSuppressionCode.js | 31 +++++++++++ tests/rules/index.js | 1 + 6 files changed, 94 insertions(+) create mode 100644 .README/rules/enforce-suppression-code.md create mode 100644 src/rules/enforceSuppressionCode.js create mode 100644 tests/rules/assertions/enforceSuppressionCode.js diff --git a/.README/README.md b/.README/README.md index 056df1a..e8a9352 100644 --- a/.README/README.md +++ b/.README/README.md @@ -161,6 +161,7 @@ When `true`, only checks files with a [`@flow` annotation](http://flowtype.org/d {"gitdown": "include", "file": "./rules/define-flow-type.md"} {"gitdown": "include", "file": "./rules/delimiter-dangle.md"} {"gitdown": "include", "file": "./rules/enforce-line-break.md"} +{"gitdown": "include", "file": "./rules/enforce-suppression-code.md"} {"gitdown": "include", "file": "./rules/generic-spacing.md"} {"gitdown": "include", "file": "./rules/newline-after-flow-annotation.md"} {"gitdown": "include", "file": "./rules/no-dupe-keys.md"} diff --git a/.README/rules/enforce-suppression-code.md b/.README/rules/enforce-suppression-code.md new file mode 100644 index 0000000..bc694c0 --- /dev/null +++ b/.README/rules/enforce-suppression-code.md @@ -0,0 +1,5 @@ +### `enforce-suppression-code` + +This rule enforces a suppression code on flow suppression comments such as `$FlowFixMe` and `$FlowExpectedError`. + + diff --git a/src/index.js b/src/index.js index 04b2973..888cc5a 100644 --- a/src/index.js +++ b/src/index.js @@ -7,6 +7,7 @@ import booleanStyle from './rules/booleanStyle'; import defineFlowType from './rules/defineFlowType'; import delimiterDangle from './rules/delimiterDangle'; import enforceLineBreak from './rules/enforceLineBreak'; +import enforceSuppressionCode from './rules/enforceSuppressionCode'; import genericSpacing from './rules/genericSpacing'; import newlineAfterFlowAnnotation from './rules/newlineAfterFlowAnnotation'; import noDupeKeys from './rules/noDupeKeys'; @@ -55,6 +56,7 @@ const rules = { 'define-flow-type': defineFlowType, 'delimiter-dangle': delimiterDangle, 'enforce-line-break': enforceLineBreak, + 'enforce-suppression-code': enforceSuppressionCode, 'generic-spacing': genericSpacing, 'newline-after-flow-annotation': newlineAfterFlowAnnotation, 'no-dupe-keys': noDupeKeys, diff --git a/src/rules/enforceSuppressionCode.js b/src/rules/enforceSuppressionCode.js new file mode 100644 index 0000000..c98b8fe --- /dev/null +++ b/src/rules/enforceSuppressionCode.js @@ -0,0 +1,54 @@ +const schema = [ + { + type: 'string', + }, +]; + +const message = (suppression = '$FlowFixMe') => { + return `${suppression} is missing a suppression code`; +}; + +const create = (context) => { + const isMissingSuppressionCode = function (value) { + if (value.startsWith('$FlowFixMe') && + !value.startsWith('$FlowFixMe[') && + !value.endsWith(']')) { + return '$FlowFixMe'; + } + if (value.startsWith('$FlowExpectedError') && + !value.startsWith('$FlowExpectedError[') && + !value.endsWith(']')) { + return '$FlowExpectedError'; + } + + return undefined; + }; + + const handleComment = function (comment) { + const value = comment.value.trim().split(' ').filter((arg) => { + return arg.length > 0; + })[0]; + const failedType = isMissingSuppressionCode(value); + + if (failedType) { + context.report(comment, message(failedType)); + } + }; + + return { + Program () { + context + .getSourceCode() + .getAllComments() + .filter((comment) => { + return comment.type === 'Block' || comment.type === 'Line'; + }) + .forEach(handleComment); + }, + }; +}; + +export default { + create, + schema, +}; diff --git a/tests/rules/assertions/enforceSuppressionCode.js b/tests/rules/assertions/enforceSuppressionCode.js new file mode 100644 index 0000000..423515f --- /dev/null +++ b/tests/rules/assertions/enforceSuppressionCode.js @@ -0,0 +1,31 @@ +export default { + invalid: [ + { + code: '// $FlowFixMe I am doing something evil here\nconst text = \'HELLO\';', + errors: [ + { + message: '$FlowFixMe is missing a suppression code', + }, + ], + }, + { + code: '// $FlowExpectedError I am doing something evil here\nconst text = \'HELLO\';', + errors: [ + { + message: '$FlowExpectedError is missing a suppression code', + }, + ], + }, + ], + valid: [ + { + code: 'const text = \'HELLO\';', + }, + { + code: '// $FlowFixMe[incompatible-call] TODO 48\nconst text = \'HELLO\';', + }, + { + code: '// $FlowExpectedError[incompatible-call] TODO 48\nconst text = \'HELLO\';', + }, + ], +}; diff --git a/tests/rules/index.js b/tests/rules/index.js index 7fddff4..ee4f8b7 100644 --- a/tests/rules/index.js +++ b/tests/rules/index.js @@ -18,6 +18,7 @@ const reportingRules = [ 'define-flow-type', 'delimiter-dangle', 'enforce-line-break', + 'enforce-suppression-code', 'generic-spacing', 'newline-after-flow-annotation', 'no-dupe-keys', From d3a004e4982023ae11971f20c8f5e6d979857c04 Mon Sep 17 00:00:00 2001 From: Brian Chen Date: Thu, 29 Jul 2021 00:43:52 +1000 Subject: [PATCH 2/4] make more concise logic --- src/rules/enforceSuppressionCode.js | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/rules/enforceSuppressionCode.js b/src/rules/enforceSuppressionCode.js index c98b8fe..e389fc9 100644 --- a/src/rules/enforceSuppressionCode.js +++ b/src/rules/enforceSuppressionCode.js @@ -4,24 +4,24 @@ const schema = [ }, ]; -const message = (suppression = '$FlowFixMe') => { +const message = (suppression = '') => { return `${suppression} is missing a suppression code`; }; const create = (context) => { const isMissingSuppressionCode = function (value) { - if (value.startsWith('$FlowFixMe') && - !value.startsWith('$FlowFixMe[') && - !value.endsWith(']')) { - return '$FlowFixMe'; - } - if (value.startsWith('$FlowExpectedError') && - !value.startsWith('$FlowExpectedError[') && - !value.endsWith(']')) { - return '$FlowExpectedError'; - } + const suppressionTypes = ['$FlowFixMe', '$FlowExpectedError']; + + let failedType; + suppressionTypes.forEach((cur) => { + if (value.startsWith(cur) && + !value.startsWith(`${cur}[`) && + !value.endsWith(']')) { + failedType = cur; + } + }); - return undefined; + return failedType; }; const handleComment = function (comment) { From f8260f393ee6d6555b1fc6e6d2c11009e0c74376 Mon Sep 17 00:00:00 2001 From: Brian Chen Date: Thu, 29 Jul 2021 07:27:59 +1000 Subject: [PATCH 3/4] add more suppression types and more test cases --- src/rules/enforceSuppressionCode.js | 9 ++- .../assertions/enforceSuppressionCode.js | 59 +++++++++++++++++++ 2 files changed, 65 insertions(+), 3 deletions(-) diff --git a/src/rules/enforceSuppressionCode.js b/src/rules/enforceSuppressionCode.js index e389fc9..c8b750c 100644 --- a/src/rules/enforceSuppressionCode.js +++ b/src/rules/enforceSuppressionCode.js @@ -10,7 +10,7 @@ const message = (suppression = '') => { const create = (context) => { const isMissingSuppressionCode = function (value) { - const suppressionTypes = ['$FlowFixMe', '$FlowExpectedError']; + const suppressionTypes = ['$FlowFixMe', '$FlowExpectedError', '$FlowIssue', '$FlowIgnore']; let failedType; suppressionTypes.forEach((cur) => { @@ -25,10 +25,13 @@ const create = (context) => { }; const handleComment = function (comment) { - const value = comment.value.trim().split(' ').filter((arg) => { + const value = comment.type === 'Block' ? + comment.value.replace(/\*/g, '') : + comment.value; + const suppression = value.trim().split(' ').filter((arg) => { return arg.length > 0; })[0]; - const failedType = isMissingSuppressionCode(value); + const failedType = isMissingSuppressionCode(suppression); if (failedType) { context.report(comment, message(failedType)); diff --git a/tests/rules/assertions/enforceSuppressionCode.js b/tests/rules/assertions/enforceSuppressionCode.js index 423515f..8b67303 100644 --- a/tests/rules/assertions/enforceSuppressionCode.js +++ b/tests/rules/assertions/enforceSuppressionCode.js @@ -16,6 +16,48 @@ export default { }, ], }, + { + code: '// $FlowIssue I am doing something evil here\nconst text = \'HELLO\';', + errors: [ + { + message: '$FlowIssue is missing a suppression code', + }, + ], + }, + { + code: '// $FlowIgnore I am doing something evil here\nconst text = \'HELLO\';', + errors: [ + { + message: '$FlowIgnore is missing a suppression code', + }, + ], + }, + { + code: '/* $FlowIgnore I am doing something evil here */', + errors: [ + { + message: '$FlowIgnore is missing a suppression code', + }, + ], + }, + { + code: '{ /* $FlowIgnore I am doing something evil here */ }', + errors: [ + { + message: '$FlowIgnore is missing a suppression code', + }, + ], + }, + { + code: `/** + * $FlowIgnore I am doing something evil here + */`, + errors: [ + { + message: '$FlowIgnore is missing a suppression code', + }, + ], + }, ], valid: [ { @@ -27,5 +69,22 @@ export default { { code: '// $FlowExpectedError[incompatible-call] TODO 48\nconst text = \'HELLO\';', }, + { + code: '// $FlowIssue[incompatible-call] TODO 48\nconst text = \'HELLO\';', + }, + { + code: '// $FlowIgnore[incompatible-call] TODO 48\nconst text = \'HELLO\';', + }, + { + code: '/* $FlowIgnore[incompatible-call] TODO 48 */', + }, + { + code: `/** + * $FlowIgnore[incompatible-call] TODO 48 + */`, + }, + { + code: '/* $FlowIgnore[incompatible-call] TODO 48 */', + }, ], }; From 65423874d80cabda9efefc2472e2968fa37c4f36 Mon Sep 17 00:00:00 2001 From: Brian Chen Date: Wed, 25 Aug 2021 11:48:28 +1000 Subject: [PATCH 4/4] update error messaging --- src/rules/enforceSuppressionCode.js | 2 +- tests/rules/assertions/enforceSuppressionCode.js | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/rules/enforceSuppressionCode.js b/src/rules/enforceSuppressionCode.js index c8b750c..fd8fb84 100644 --- a/src/rules/enforceSuppressionCode.js +++ b/src/rules/enforceSuppressionCode.js @@ -5,7 +5,7 @@ const schema = [ ]; const message = (suppression = '') => { - return `${suppression} is missing a suppression code`; + return `${suppression} is missing a suppression error code. Please update this suppression to use an error code: ${suppression}[…]`; }; const create = (context) => { diff --git a/tests/rules/assertions/enforceSuppressionCode.js b/tests/rules/assertions/enforceSuppressionCode.js index 8b67303..3f64f4d 100644 --- a/tests/rules/assertions/enforceSuppressionCode.js +++ b/tests/rules/assertions/enforceSuppressionCode.js @@ -4,7 +4,7 @@ export default { code: '// $FlowFixMe I am doing something evil here\nconst text = \'HELLO\';', errors: [ { - message: '$FlowFixMe is missing a suppression code', + message: '$FlowFixMe is missing a suppression error code. Please update this suppression to use an error code: $FlowFixMe[…]', }, ], }, @@ -12,7 +12,7 @@ export default { code: '// $FlowExpectedError I am doing something evil here\nconst text = \'HELLO\';', errors: [ { - message: '$FlowExpectedError is missing a suppression code', + message: '$FlowExpectedError is missing a suppression error code. Please update this suppression to use an error code: $FlowExpectedError[…]', }, ], }, @@ -20,7 +20,7 @@ export default { code: '// $FlowIssue I am doing something evil here\nconst text = \'HELLO\';', errors: [ { - message: '$FlowIssue is missing a suppression code', + message: '$FlowIssue is missing a suppression error code. Please update this suppression to use an error code: $FlowIssue[…]', }, ], }, @@ -28,7 +28,7 @@ export default { code: '// $FlowIgnore I am doing something evil here\nconst text = \'HELLO\';', errors: [ { - message: '$FlowIgnore is missing a suppression code', + message: '$FlowIgnore is missing a suppression error code. Please update this suppression to use an error code: $FlowIgnore[…]', }, ], }, @@ -36,7 +36,7 @@ export default { code: '/* $FlowIgnore I am doing something evil here */', errors: [ { - message: '$FlowIgnore is missing a suppression code', + message: '$FlowIgnore is missing a suppression error code. Please update this suppression to use an error code: $FlowIgnore[…]', }, ], }, @@ -44,7 +44,7 @@ export default { code: '{ /* $FlowIgnore I am doing something evil here */ }', errors: [ { - message: '$FlowIgnore is missing a suppression code', + message: '$FlowIgnore is missing a suppression error code. Please update this suppression to use an error code: $FlowIgnore[…]', }, ], }, @@ -54,7 +54,7 @@ export default { */`, errors: [ { - message: '$FlowIgnore is missing a suppression code', + message: '$FlowIgnore is missing a suppression error code. Please update this suppression to use an error code: $FlowIgnore[…]', }, ], },