diff --git a/.README/README.md b/.README/README.md index ec7c293..056df1a 100644 --- a/.README/README.md +++ b/.README/README.md @@ -160,6 +160,7 @@ When `true`, only checks files with a [`@flow` annotation](http://flowtype.org/d {"gitdown": "include", "file": "./rules/boolean-style.md"} {"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/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-line-break.md b/.README/rules/enforce-line-break.md new file mode 100644 index 0000000..d790661 --- /dev/null +++ b/.README/rules/enforce-line-break.md @@ -0,0 +1,5 @@ +### `enforce-line-break` + +This rule enforces line breaks between type definitions. + + diff --git a/README.md b/README.md index ae748d3..6e6b24a 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ * [`boolean-style`](#eslint-plugin-flowtype-rules-boolean-style) * [`define-flow-type`](#eslint-plugin-flowtype-rules-define-flow-type) * [`delimiter-dangle`](#eslint-plugin-flowtype-rules-delimiter-dangle) + * [`enforce-line-break`](#eslint-plugin-flowtype-rules-enforce-line-break) * [`generic-spacing`](#eslint-plugin-flowtype-rules-generic-spacing) * [`newline-after-flow-annotation`](#eslint-plugin-flowtype-rules-newline-after-flow-annotation) * [`no-dupe-keys`](#eslint-plugin-flowtype-rules-no-dupe-keys) @@ -1662,6 +1663,83 @@ type X = [] + +### enforce-line-break + +This rule enforces line breaks between type definitions. + +The following patterns are considered problems: + +```js +type baz = 6; +const hi = 2; +// Message: New line required below type declaration + +const foo = 6; +type hi = 2; + +// Message: New line required above type declaration + +const som = "jes"; +// a comment +type fed = "hed"; + +// Message: New line required above type declaration + +type som = "jes"; +// a comment +const fed = "hed"; + +// Message: New line required below type declaration + +type hello = 34; +const som = "jes"; +type fed = "hed"; + +// Message: New line required below type declaration +// Message: New line required above type declaration +``` + +The following patterns are not considered problems: + +```js +type gjs = 6; + +type gjs = 6; + +type hi = 2; + + +type X = 4; + +const red = "serpent"; +console.log("hello"); + +// number or string +type Y = string | number; + +// resting + sleep +type snooze = "dreaming" | ""; + +type Props = { + accountBalance: string | number, + accountNumber: string | number, +}; + +const x = 4; +const y = 489; + +// Some Comment +type Props = { + accountBalance: string | number, + accountNumber: string | number, +}; + +type RoadT = "grass" | "gravel" | "cement"; +``` + + + ### generic-spacing diff --git a/src/index.js b/src/index.js index 51292ea..04b2973 100644 --- a/src/index.js +++ b/src/index.js @@ -6,6 +6,7 @@ import arrayStyleSimpleType from './rules/arrayStyleSimpleType'; import booleanStyle from './rules/booleanStyle'; import defineFlowType from './rules/defineFlowType'; import delimiterDangle from './rules/delimiterDangle'; +import enforceLineBreak from './rules/enforceLineBreak'; import genericSpacing from './rules/genericSpacing'; import newlineAfterFlowAnnotation from './rules/newlineAfterFlowAnnotation'; import noDupeKeys from './rules/noDupeKeys'; @@ -53,6 +54,7 @@ const rules = { 'boolean-style': booleanStyle, 'define-flow-type': defineFlowType, 'delimiter-dangle': delimiterDangle, + 'enforce-line-break': enforceLineBreak, 'generic-spacing': genericSpacing, 'newline-after-flow-annotation': newlineAfterFlowAnnotation, 'no-dupe-keys': noDupeKeys, diff --git a/src/rules/enforceLineBreak.js b/src/rules/enforceLineBreak.js new file mode 100644 index 0000000..e898bd8 --- /dev/null +++ b/src/rules/enforceLineBreak.js @@ -0,0 +1,63 @@ +const schema = []; + +const breakLineMessage = (direction) => { + return `New line required ${direction} type declaration`; +}; + +const create = (context) => { + return { + TypeAlias (node) { + const sourceCode = context.getSourceCode(); + if (sourceCode.lines.length === 1) { + return; + } + + if (node.loc.start.line !== 1) { + if (node.leadingComments && node.leadingComments[0].loc.start.line !== 1) { + const lineAboveComment = sourceCode.lines[node.leadingComments[0].loc.start.line - 2]; + if (lineAboveComment !== '') { + context.report({ + fix (fixer) { + return fixer.insertTextBeforeRange(node.leadingComments[0].range, '\n'); + }, + message: breakLineMessage('above'), + node, + }); + } + } else if (!node.leadingComments) { + const isLineAbove = sourceCode.lines[node.loc.start.line - 2]; + if (isLineAbove !== '') { + context.report({ + fix (fixer) { + return fixer.insertTextBefore(node, '\n'); + }, + message: breakLineMessage('above'), + node, + }); + } + } + } + + if (sourceCode.lines.length !== node.loc.end.line) { + const isLineBelow = sourceCode.lines[node.loc.end.line]; + if (isLineBelow !== '') { + context.report({ + fix (fixer) { + return fixer.insertTextAfter(node, '\n'); + }, + message: breakLineMessage('below'), + node, + }); + } + } + }, + }; +}; + +export default { + create, + meta: { + fixable: 'code', + }, + schema, +}; diff --git a/tests/rules/assertions/enforceLineBreak.js b/tests/rules/assertions/enforceLineBreak.js new file mode 100644 index 0000000..291174a --- /dev/null +++ b/tests/rules/assertions/enforceLineBreak.js @@ -0,0 +1,81 @@ +export default { + invalid: [ + { + code: 'type baz = 6;\nconst hi = 2;', + errors: [{ + message: 'New line required below type declaration', + }], + output: 'type baz = 6;\n\nconst hi = 2;', + }, + { + code: 'const foo = 6;\ntype hi = 2;\n', + errors: [ + {message: 'New line required above type declaration'}, + ], + output: 'const foo = 6;\n\ntype hi = 2;\n', + }, + { + code: 'const som = "jes";\n// a comment\ntype fed = "hed";\n', + errors: [ + {message: 'New line required above type declaration'}, + ], + output: 'const som = "jes";\n\n// a comment\ntype fed = "hed";\n', + }, + { + code: 'type som = "jes";\n// a comment\nconst fed = "hed";\n', + errors: [ + {message: 'New line required below type declaration'}, + ], + output: 'type som = "jes";\n\n// a comment\nconst fed = "hed";\n', + }, + { + code: 'type hello = 34;\nconst som = "jes";\ntype fed = "hed";\n', + errors: [ + {message: 'New line required below type declaration'}, + {message: 'New line required above type declaration'}, + ], + output: 'type hello = 34;\n\nconst som = "jes";\n\ntype fed = "hed";\n', + }, + ], + valid: [ + { + code: 'type gjs = 6;', + }, + { + code: 'type gjs = 6;\n\ntype hi = 2;\n', + }, + { + code: +`type X = 4; + +const red = "serpent"; +console.log("hello"); + +// number or string +type Y = string | number; + +// resting + sleep +type snooze = "dreaming" | "";`, + }, + { + code: +`type Props = { + accountBalance: string | number, + accountNumber: string | number, +};`, + }, + { + code: +`const x = 4; +const y = 489; + +// Some Comment +type Props = { + accountBalance: string | number, + accountNumber: string | number, +}; + +type RoadT = "grass" | "gravel" | "cement";`, + }, + ], +}; diff --git a/tests/rules/index.js b/tests/rules/index.js index b030073..7fddff4 100644 --- a/tests/rules/index.js +++ b/tests/rules/index.js @@ -17,6 +17,7 @@ const reportingRules = [ 'boolean-style', 'define-flow-type', 'delimiter-dangle', + 'enforce-line-break', 'generic-spacing', 'newline-after-flow-annotation', 'no-dupe-keys',