From 52606f16f690c116007f1e9383ba30398b1df831 Mon Sep 17 00:00:00 2001 From: hsimah Date: Wed, 5 Jan 2022 12:43:04 -0800 Subject: [PATCH 1/2] create type-annotation-spacing --- src/configs/recommended.json | 6 +- src/index.js | 3 + src/rules/typeAnnotationSpacing.js | 218 ++++++++++++++++++ .../rules/assertions/typeAnnotationSpacing.js | 114 +++++++++ tests/rules/index.js | 1 + 5 files changed, 341 insertions(+), 1 deletion(-) create mode 100644 src/rules/typeAnnotationSpacing.js create mode 100644 tests/rules/assertions/typeAnnotationSpacing.js diff --git a/src/configs/recommended.json b/src/configs/recommended.json index 52bac2d..65740ad 100644 --- a/src/configs/recommended.json +++ b/src/configs/recommended.json @@ -44,6 +44,10 @@ 2, "never" ], + "ft-flow/type-annotation-spacing": [ + "warn", + "never" + ], "ft-flow/type-id-match": 0, "ft-flow/union-intersection-spacing": [ 2, @@ -56,4 +60,4 @@ "onlyFilesWithFlowAnnotation": false } } -} +} \ No newline at end of file diff --git a/src/index.js b/src/index.js index 41e18d1..952c84c 100644 --- a/src/index.js +++ b/src/index.js @@ -44,6 +44,7 @@ import spaceAfterTypeColon from './rules/spaceAfterTypeColon'; import spaceBeforeGenericBracket from './rules/spaceBeforeGenericBracket'; import spaceBeforeTypeColon from './rules/spaceBeforeTypeColon'; import spreadExactType from './rules/spreadExactType'; +import typeAnnotationSpacing from './rules/typeAnnotationSpacing'; import typeIdMatch from './rules/typeIdMatch'; import typeImportStyle from './rules/typeImportStyle'; import unionIntersectionSpacing from './rules/unionIntersectionSpacing'; @@ -98,6 +99,7 @@ const rules = { 'space-before-generic-bracket': spaceBeforeGenericBracket, 'space-before-type-colon': spaceBeforeTypeColon, 'spread-exact-type': spreadExactType, + 'type-annotation-spacing': typeAnnotationSpacing, 'type-id-match': typeIdMatch, 'type-import-style': typeImportStyle, 'union-intersection-spacing': unionIntersectionSpacing, @@ -149,6 +151,7 @@ export default { 'space-before-generic-bracket': 0, 'space-before-type-colon': 0, 'spread-exact-type': 0, + 'type-annotation-spacing': 0, 'type-id-match': 0, 'type-import-style': 0, 'union-intersection-spacing': 0, diff --git a/src/rules/typeAnnotationSpacing.js b/src/rules/typeAnnotationSpacing.js new file mode 100644 index 0000000..2aee586 --- /dev/null +++ b/src/rules/typeAnnotationSpacing.js @@ -0,0 +1,218 @@ +import { + spacingFixers, +} from '../utilities'; + +const schema = [ + { + enum: ['always', 'never'], + type: 'string', + }, +]; + +function isNeverOption(context) { + return (context.options[0] || 'never') === 'never'; +} + +function isWhitespaceCRLF(whitespace) { + return whitespace !== '\n' && whitespace !== '\r'; +} + +function spacesOutside(node, context) { + const { callee, typeArguments } = node; + if (typeArguments == null) { + return; + } + + const sourceCode = context.getSourceCode(); + const { name } = callee; + const never = isNeverOption(context); + const parentheses = sourceCode.getTokenAfter(typeArguments); + + const spacesBefore = typeArguments.range[0] - callee.range[1]; + const spacesAfter = parentheses.range[0] - typeArguments.range[1]; + + if (never) { + if (spacesBefore) { + const whiteSpaceBefore = sourceCode.text[typeArguments.range[0]]; + + if (isWhitespaceCRLF(whiteSpaceBefore)) { + context.report({ + data: { name }, + fix: spacingFixers.stripSpacesBefore(typeArguments, spacesBefore), + message: 'There must be no space before "{{name}}" type annotation', + node, + }); + } + } + + if (spacesAfter) { + const whiteSpaceAfter = sourceCode.text[typeArguments.range[1] - 1]; + + if (isWhitespaceCRLF(whiteSpaceAfter)) { + context.report({ + data: { name }, + fix: spacingFixers.stripSpacesAfter(typeArguments, spacesAfter), + message: 'There must be no space after "{{name}}" type annotation', + node, + }); + } + } + + return; + } + + if (!never) { + if (spacesBefore > 1) { + context.report({ + data: { name }, + fix: spacingFixers.stripSpacesBefore(typeArguments, spacesBefore - 1), + message: 'There must be one space before "{{name}}" generic type annotation bracket', + node, + }); + } + + if (spacesBefore === 0) { + context.report({ + data: { name }, + fix: spacingFixers.addSpaceBefore(typeArguments), + message: 'There must be a space before "{{name}}" generic type annotation bracket', + node, + }); + } + + if (spacesAfter > 1) { + context.report({ + data: { name }, + fix: spacingFixers.stripSpacesAfter(typeArguments, spacesAfter), + message: 'There must be one space before "{{name}}" generic type annotation bracket', + node, + }); + } + + if (spacesAfter === 0) { + context.report({ + data: { name }, + fix: spacingFixers.addSpaceAfter(typeArguments), + message: 'There must be a space before "{{name}}" generic type annotation bracket', + node, + }); + } + } +} + +function spacesInside(node, context) { + const { callee, typeArguments } = node; + if (typeArguments == null) { + return; + } + + const sourceCode = context.getSourceCode(); + const { name } = callee; + const never = isNeverOption(context); + const isNullable = typeArguments.params[0].type === 'NullableTypeAnnotation'; + const [ + opener, + firstInnerToken, + secondInnerToken, + ] = sourceCode.getFirstTokens(typeArguments, 3); + const [ + lastInnerToken, + closer, + ] = sourceCode.getLastTokens(typeArguments, 2); + + const spacesBefore = firstInnerToken.range[0] - opener.range[1]; + const spaceBetweenNullToken = secondInnerToken.range[0] - firstInnerToken.range[1]; + const spacesAfter = closer.range[0] - lastInnerToken.range[1]; + + if (never) { + if (spacesBefore) { + const whiteSpaceBefore = sourceCode.text[opener.range[1]]; + + if (whiteSpaceBefore !== '\n' && whiteSpaceBefore !== '\r') { + context.report({ + data: { name }, + fix: spacingFixers.stripSpacesAfter(opener, spacesBefore), + message: 'There must be no spaces inside at the start of "{{name}}" type annotation', + node, + }); + } + } + + if (isNullable && spaceBetweenNullToken) { + context.report({ + data: { name }, + fix: spacingFixers.stripSpacesAfter(firstInnerToken, spaceBetweenNullToken), + message: 'There must be no spaces inside "{{name}}" type annotation', + node, + }); + } + + if (spacesAfter) { + const whiteSpaceAfter = sourceCode.text[closer.range[0] - 1]; + + if (isWhitespaceCRLF(whiteSpaceAfter)) { + context.report({ + data: { name }, + fix: spacingFixers.stripSpacesAfter(lastInnerToken, spacesAfter), + message: 'There must be no spaces inside at the end of "{{name}}" type annotation', + node, + }); + } + } + + return; + } + + if (!never) { + if (spacesBefore > 1) { + context.report({ + data: { name }, + fix: spacingFixers.stripSpacesBefore(opener, spacesBefore - 1), + message: 'There must be one space before "{{name}}" generic type annotation bracket', + node, + }); + } + + if (spacesBefore === 0) { + context.report({ + data: { name }, + fix: spacingFixers.addSpaceBefore(opener), + message: 'There must be a space before "{{name}}" generic type annotation bracket', + node, + }); + } + + if (spacesAfter > 1) { + context.report({ + data: { name }, + fix: spacingFixers.stripSpacesAfter(closer, spacesAfter), + message: 'There must be one space before "{{name}}" generic type annotation bracket', + node, + }); + } + + if (spacesAfter === 0) { + context.report({ + data: { name }, + fix: spacingFixers.addSpaceAfter(closer), + message: 'There must be a space before "{{name}}" generic type annotation bracket', + node, + }); + } + } +} + +const create = (context) => ({ + CallExpression(node) { + spacesOutside(node, context); + spacesInside(node, context); + }, +}); + +export default { + create, + meta: { + fixable: 'code', + }, + schema, +}; diff --git a/tests/rules/assertions/typeAnnotationSpacing.js b/tests/rules/assertions/typeAnnotationSpacing.js new file mode 100644 index 0000000..e41bb43 --- /dev/null +++ b/tests/rules/assertions/typeAnnotationSpacing.js @@ -0,0 +1,114 @@ +export default { + invalid: [ + // { + // code: 'const [state, setState] = useState(null)', + // errors: [{ message: 'There must be no space at start of type annotations' }], + // output: 'const [state, setState] = useState(null)', + // }, + // { + // code: 'const [state, setState] = useState (null)', + // errors: [{ message: 'There must be no space at start of type annotations' }], + // output: 'const [state, setState] = useState(null)', + // }, + // { + // code: 'const [state, setState] = useState< ?string>(null)', + // errors: [{ message: 'There must be no space at start of type annotations' }], + // output: 'const [state, setState] = useState(null)', + // }, + // { + // code: 'const [state, setState] = useState < ?string>(null)', + // errors: [{ message: 'There must be no space at start of type annotations' }], + // output: 'const [state, setState] = useState(null)', + // }, + // { + // code: 'const [state, setState] = useState(null)', + // errors: [{ message: 'There must be no space at start of type annotations' }], + // output: 'const [state, setState] = useState(null)', + // }, + // { + // code: 'const [state, setState] = useState< ? string>(null)', + // errors: [{ message: 'There must be no space at start of type annotations' }], + // output: 'const [state, setState] = useState(null)', + // }, + // { + // code: 'const [state, setState] = useState< ? string >(null)', + // errors: [{ message: 'There must be no space at start of type annotations' }], + // output: 'const [state, setState] = useState(null)', + // }, + // { + // code: 'const [state, setState] = useState < ? string > (null)', + // errors: [{ message: 'There must be no space at start of type annotations' }], + // output: 'const [state, setState] = useState(null)', + // }, + // { + // code: 'const [state, setState] = useState < ? string > ()', + // errors: [{ message: 'There must be no space at start of type annotations' }], + // output: 'const [state, setState] = useState(null)', + // }, + { + code: 'useState(null)', + errors: [{ message: 'There must be no space at start of type annotations' }], + output: 'useState(null)', + }, + { + code: 'useState< string>(null)', + errors: [{ message: 'There must be no space at start of type annotations' }], + output: 'useState(null)', + }, + { + code: 'useState< string >(null)', + errors: [{ message: 'There must be no space at start of type annotations' }], + output: 'useState(null)', + }, + ], + misconfigured: [ + { + errors: [ + { + data: 'frequently', + instancePath: '/0', + keyword: 'enum', + message: 'must be equal to one of the allowed values', + params: { + allowedValues: [ + 'always', + 'never', + ], + }, + parentSchema: { + enum: [ + 'always', + 'never', + ], + type: 'string', + }, + schema: [ + 'always', + 'never', + ], + schemaPath: '#/items/0/enum', + }, + ], + options: [ + 'frequently', + ], + }, + ], + valid: [ + { + code: 'const [state, setState] = useState(null)', + }, + { + code: 'const [state, setState] = useState("")', + }, + // { + // code: 'const [state, setState] = useState(null)', + // }, + { + code: 'const [state, setState] = useState(null)', + }, + { + code: 'const [state, setState] = useState(2)', + }, + ], +}; diff --git a/tests/rules/index.js b/tests/rules/index.js index 9976b20..2ff6eaf 100644 --- a/tests/rules/index.js +++ b/tests/rules/index.js @@ -66,6 +66,7 @@ const reportingRules = [ 'space-before-generic-bracket', 'space-before-type-colon', 'spread-exact-type', + 'type-annotation-spacing', 'type-id-match', 'type-import-style', 'union-intersection-spacing', From 5333a0c652f4b5923e463264129b9bec764fe56f Mon Sep 17 00:00:00 2001 From: hsimah Date: Sun, 23 Jan 2022 15:16:37 -0800 Subject: [PATCH 2/2] replace new rule with extending `genericSpacing` --- src/configs/recommended.json | 4 - src/index.js | 3 - src/rules/genericSpacing.js | 197 ++++++++++++++++ src/rules/typeAnnotationSpacing.js | 218 ------------------ tests/rules/assertions/genericSpacing.js | 103 ++++++++- .../rules/assertions/typeAnnotationSpacing.js | 114 --------- tests/rules/index.js | 1 - 7 files changed, 298 insertions(+), 342 deletions(-) delete mode 100644 src/rules/typeAnnotationSpacing.js delete mode 100644 tests/rules/assertions/typeAnnotationSpacing.js diff --git a/src/configs/recommended.json b/src/configs/recommended.json index 65740ad..a17882c 100644 --- a/src/configs/recommended.json +++ b/src/configs/recommended.json @@ -44,10 +44,6 @@ 2, "never" ], - "ft-flow/type-annotation-spacing": [ - "warn", - "never" - ], "ft-flow/type-id-match": 0, "ft-flow/union-intersection-spacing": [ 2, diff --git a/src/index.js b/src/index.js index 952c84c..41e18d1 100644 --- a/src/index.js +++ b/src/index.js @@ -44,7 +44,6 @@ import spaceAfterTypeColon from './rules/spaceAfterTypeColon'; import spaceBeforeGenericBracket from './rules/spaceBeforeGenericBracket'; import spaceBeforeTypeColon from './rules/spaceBeforeTypeColon'; import spreadExactType from './rules/spreadExactType'; -import typeAnnotationSpacing from './rules/typeAnnotationSpacing'; import typeIdMatch from './rules/typeIdMatch'; import typeImportStyle from './rules/typeImportStyle'; import unionIntersectionSpacing from './rules/unionIntersectionSpacing'; @@ -99,7 +98,6 @@ const rules = { 'space-before-generic-bracket': spaceBeforeGenericBracket, 'space-before-type-colon': spaceBeforeTypeColon, 'spread-exact-type': spreadExactType, - 'type-annotation-spacing': typeAnnotationSpacing, 'type-id-match': typeIdMatch, 'type-import-style': typeImportStyle, 'union-intersection-spacing': unionIntersectionSpacing, @@ -151,7 +149,6 @@ export default { 'space-before-generic-bracket': 0, 'space-before-type-colon': 0, 'spread-exact-type': 0, - 'type-annotation-spacing': 0, 'type-id-match': 0, 'type-import-style': 0, 'union-intersection-spacing': 0, diff --git a/src/rules/genericSpacing.js b/src/rules/genericSpacing.js index aa9004b..3505250 100644 --- a/src/rules/genericSpacing.js +++ b/src/rules/genericSpacing.js @@ -9,12 +9,209 @@ const schema = [ }, ]; +function isNeverOption(context) { + return (context.options[0] || 'never') === 'never'; +} + +function isWhitespaceCRLF(whitespace) { + return whitespace !== '\n' && whitespace !== '\r'; +} + +function spacesOutside(node, context) { + const { callee, typeArguments } = node; + if (typeArguments == null) { + return; + } + + const sourceCode = context.getSourceCode(); + const { name } = callee; + const never = isNeverOption(context); + const parentheses = sourceCode.getTokenAfter(typeArguments); + + const spacesBefore = typeArguments.range[0] - callee.range[1]; + const spacesAfter = parentheses.range[0] - typeArguments.range[1]; + + if (never) { + if (spacesBefore) { + const whiteSpaceBefore = sourceCode.text[typeArguments.range[0]]; + + if (isWhitespaceCRLF(whiteSpaceBefore)) { + context.report({ + data: { name }, + fix: spacingFixers.stripSpacesBefore(typeArguments, spacesBefore), + message: 'There must be no space before "{{name}}" type annotation', + node, + }); + } + } + + if (spacesAfter) { + const whiteSpaceAfter = sourceCode.text[typeArguments.range[1] - 1]; + + if (isWhitespaceCRLF(whiteSpaceAfter)) { + context.report({ + data: { name }, + fix: spacingFixers.stripSpacesAfter(typeArguments, spacesAfter), + message: 'There must be no space after "{{name}}" type annotation', + node, + }); + } + } + + return; + } + + if (!never) { + if (spacesBefore > 1) { + context.report({ + data: { name }, + fix: spacingFixers.stripSpacesBefore(typeArguments, spacesBefore - 1), + message: 'There must be one space before "{{name}}" generic type annotation bracket', + node, + }); + } + + if (spacesBefore === 0) { + context.report({ + data: { name }, + fix: spacingFixers.addSpaceBefore(typeArguments), + message: 'There must be a space before "{{name}}" generic type annotation bracket', + node, + }); + } + + if (spacesAfter > 1) { + context.report({ + data: { name }, + fix: spacingFixers.stripSpacesAfter(typeArguments, spacesAfter), + message: 'There must be one space before "{{name}}" generic type annotation bracket', + node, + }); + } + + if (spacesAfter === 0) { + context.report({ + data: { name }, + fix: spacingFixers.addSpaceAfter(typeArguments), + message: 'There must be a space before "{{name}}" generic type annotation bracket', + node, + }); + } + } +} + +function spacesInside(node, context) { + const { callee, typeArguments } = node; + if (typeArguments == null) { + return; + } + + const sourceCode = context.getSourceCode(); + const { name } = callee; + const never = isNeverOption(context); + const isNullable = typeArguments.params[0].type === 'NullableTypeAnnotation'; + const [ + opener, + firstInnerToken, + secondInnerToken, + ] = sourceCode.getFirstTokens(typeArguments, 3); + const [ + lastInnerToken, + closer, + ] = sourceCode.getLastTokens(typeArguments, 2); + + const spacesBefore = firstInnerToken.range[0] - opener.range[1]; + const spaceBetweenNullToken = secondInnerToken.range[0] - firstInnerToken.range[1]; + const spacesAfter = closer.range[0] - lastInnerToken.range[1]; + + if (never) { + if (spacesBefore) { + const whiteSpaceBefore = sourceCode.text[opener.range[1]]; + + if (whiteSpaceBefore !== '\n' && whiteSpaceBefore !== '\r') { + context.report({ + data: { name }, + fix: spacingFixers.stripSpacesAfter(opener, spacesBefore), + message: 'There must be no spaces inside at the start of "{{name}}" type annotation', + node, + }); + } + } + + if (isNullable && spaceBetweenNullToken) { + context.report({ + data: { name }, + fix: spacingFixers.stripSpacesAfter(firstInnerToken, spaceBetweenNullToken), + message: 'There must be no spaces inside "{{name}}" type annotation', + node, + }); + } + + if (spacesAfter) { + const whiteSpaceAfter = sourceCode.text[closer.range[0] - 1]; + + if (isWhitespaceCRLF(whiteSpaceAfter)) { + context.report({ + data: { name }, + fix: spacingFixers.stripSpacesAfter(lastInnerToken, spacesAfter), + message: 'There must be no spaces inside at the end of "{{name}}" type annotation', + node, + }); + } + } + + return; + } + + if (!never) { + if (spacesBefore > 1) { + context.report({ + data: { name }, + fix: spacingFixers.stripSpacesBefore(opener, spacesBefore - 1), + message: 'There must be one space before "{{name}}" generic type annotation bracket', + node, + }); + } + + if (spacesBefore === 0) { + context.report({ + data: { name }, + fix: spacingFixers.addSpaceBefore(opener), + message: 'There must be a space before "{{name}}" generic type annotation bracket', + node, + }); + } + + if (spacesAfter > 1) { + context.report({ + data: { name }, + fix: spacingFixers.stripSpacesAfter(closer, spacesAfter), + message: 'There must be one space before "{{name}}" generic type annotation bracket', + node, + }); + } + + if (spacesAfter === 0) { + context.report({ + data: { name }, + fix: spacingFixers.addSpaceAfter(closer), + message: 'There must be a space before "{{name}}" generic type annotation bracket', + node, + }); + } + } +} + const create = (context) => { const sourceCode = context.getSourceCode(); const never = (context.options[0] || 'never') === 'never'; return { + CallExpression(node) { + spacesOutside(node, context); + spacesInside(node, context); + }, GenericTypeAnnotation(node) { const types = node.typeParameters; diff --git a/src/rules/typeAnnotationSpacing.js b/src/rules/typeAnnotationSpacing.js deleted file mode 100644 index 2aee586..0000000 --- a/src/rules/typeAnnotationSpacing.js +++ /dev/null @@ -1,218 +0,0 @@ -import { - spacingFixers, -} from '../utilities'; - -const schema = [ - { - enum: ['always', 'never'], - type: 'string', - }, -]; - -function isNeverOption(context) { - return (context.options[0] || 'never') === 'never'; -} - -function isWhitespaceCRLF(whitespace) { - return whitespace !== '\n' && whitespace !== '\r'; -} - -function spacesOutside(node, context) { - const { callee, typeArguments } = node; - if (typeArguments == null) { - return; - } - - const sourceCode = context.getSourceCode(); - const { name } = callee; - const never = isNeverOption(context); - const parentheses = sourceCode.getTokenAfter(typeArguments); - - const spacesBefore = typeArguments.range[0] - callee.range[1]; - const spacesAfter = parentheses.range[0] - typeArguments.range[1]; - - if (never) { - if (spacesBefore) { - const whiteSpaceBefore = sourceCode.text[typeArguments.range[0]]; - - if (isWhitespaceCRLF(whiteSpaceBefore)) { - context.report({ - data: { name }, - fix: spacingFixers.stripSpacesBefore(typeArguments, spacesBefore), - message: 'There must be no space before "{{name}}" type annotation', - node, - }); - } - } - - if (spacesAfter) { - const whiteSpaceAfter = sourceCode.text[typeArguments.range[1] - 1]; - - if (isWhitespaceCRLF(whiteSpaceAfter)) { - context.report({ - data: { name }, - fix: spacingFixers.stripSpacesAfter(typeArguments, spacesAfter), - message: 'There must be no space after "{{name}}" type annotation', - node, - }); - } - } - - return; - } - - if (!never) { - if (spacesBefore > 1) { - context.report({ - data: { name }, - fix: spacingFixers.stripSpacesBefore(typeArguments, spacesBefore - 1), - message: 'There must be one space before "{{name}}" generic type annotation bracket', - node, - }); - } - - if (spacesBefore === 0) { - context.report({ - data: { name }, - fix: spacingFixers.addSpaceBefore(typeArguments), - message: 'There must be a space before "{{name}}" generic type annotation bracket', - node, - }); - } - - if (spacesAfter > 1) { - context.report({ - data: { name }, - fix: spacingFixers.stripSpacesAfter(typeArguments, spacesAfter), - message: 'There must be one space before "{{name}}" generic type annotation bracket', - node, - }); - } - - if (spacesAfter === 0) { - context.report({ - data: { name }, - fix: spacingFixers.addSpaceAfter(typeArguments), - message: 'There must be a space before "{{name}}" generic type annotation bracket', - node, - }); - } - } -} - -function spacesInside(node, context) { - const { callee, typeArguments } = node; - if (typeArguments == null) { - return; - } - - const sourceCode = context.getSourceCode(); - const { name } = callee; - const never = isNeverOption(context); - const isNullable = typeArguments.params[0].type === 'NullableTypeAnnotation'; - const [ - opener, - firstInnerToken, - secondInnerToken, - ] = sourceCode.getFirstTokens(typeArguments, 3); - const [ - lastInnerToken, - closer, - ] = sourceCode.getLastTokens(typeArguments, 2); - - const spacesBefore = firstInnerToken.range[0] - opener.range[1]; - const spaceBetweenNullToken = secondInnerToken.range[0] - firstInnerToken.range[1]; - const spacesAfter = closer.range[0] - lastInnerToken.range[1]; - - if (never) { - if (spacesBefore) { - const whiteSpaceBefore = sourceCode.text[opener.range[1]]; - - if (whiteSpaceBefore !== '\n' && whiteSpaceBefore !== '\r') { - context.report({ - data: { name }, - fix: spacingFixers.stripSpacesAfter(opener, spacesBefore), - message: 'There must be no spaces inside at the start of "{{name}}" type annotation', - node, - }); - } - } - - if (isNullable && spaceBetweenNullToken) { - context.report({ - data: { name }, - fix: spacingFixers.stripSpacesAfter(firstInnerToken, spaceBetweenNullToken), - message: 'There must be no spaces inside "{{name}}" type annotation', - node, - }); - } - - if (spacesAfter) { - const whiteSpaceAfter = sourceCode.text[closer.range[0] - 1]; - - if (isWhitespaceCRLF(whiteSpaceAfter)) { - context.report({ - data: { name }, - fix: spacingFixers.stripSpacesAfter(lastInnerToken, spacesAfter), - message: 'There must be no spaces inside at the end of "{{name}}" type annotation', - node, - }); - } - } - - return; - } - - if (!never) { - if (spacesBefore > 1) { - context.report({ - data: { name }, - fix: spacingFixers.stripSpacesBefore(opener, spacesBefore - 1), - message: 'There must be one space before "{{name}}" generic type annotation bracket', - node, - }); - } - - if (spacesBefore === 0) { - context.report({ - data: { name }, - fix: spacingFixers.addSpaceBefore(opener), - message: 'There must be a space before "{{name}}" generic type annotation bracket', - node, - }); - } - - if (spacesAfter > 1) { - context.report({ - data: { name }, - fix: spacingFixers.stripSpacesAfter(closer, spacesAfter), - message: 'There must be one space before "{{name}}" generic type annotation bracket', - node, - }); - } - - if (spacesAfter === 0) { - context.report({ - data: { name }, - fix: spacingFixers.addSpaceAfter(closer), - message: 'There must be a space before "{{name}}" generic type annotation bracket', - node, - }); - } - } -} - -const create = (context) => ({ - CallExpression(node) { - spacesOutside(node, context); - spacesInside(node, context); - }, -}); - -export default { - create, - meta: { - fixable: 'code', - }, - schema, -}; diff --git a/tests/rules/assertions/genericSpacing.js b/tests/rules/assertions/genericSpacing.js index 8deb7f3..d4249fe 100644 --- a/tests/rules/assertions/genericSpacing.js +++ b/tests/rules/assertions/genericSpacing.js @@ -1,7 +1,6 @@ export default { invalid: [ // Never - { code: 'type X = Promise< string>', errors: [{ message: 'There must be no space at start of "Promise" generic type annotation' }], @@ -91,6 +90,68 @@ export default { options: ['always'], output: 'type X = Promise< (foo), bar, (((baz))) >', }, + + // Type annotations + { + code: 'const [state, setState] = useState(null)', + errors: [{ message: 'There must be no space at start of type annotations' }], + output: 'const [state, setState] = useState(null)', + }, + { + code: 'const [state, setState] = useState (null)', + errors: [{ message: 'There must be no space at start of type annotations' }], + output: 'const [state, setState] = useState(null)', + }, + { + code: 'const [state, setState] = useState< ?string>(null)', + errors: [{ message: 'There must be no space at start of type annotations' }], + output: 'const [state, setState] = useState(null)', + }, + { + code: 'const [state, setState] = useState < ?string>(null)', + errors: [{ message: 'There must be no space at start of type annotations' }], + output: 'const [state, setState] = useState(null)', + }, + { + code: 'const [state, setState] = useState(null)', + errors: [{ message: 'There must be no space at start of type annotations' }], + output: 'const [state, setState] = useState(null)', + }, + { + code: 'const [state, setState] = useState< ? string>(null)', + errors: [{ message: 'There must be no space at start of type annotations' }], + output: 'const [state, setState] = useState(null)', + }, + { + code: 'const [state, setState] = useState< ? string >(null)', + errors: [{ message: 'There must be no space at start of type annotations' }], + output: 'const [state, setState] = useState(null)', + }, + { + code: 'const [state, setState] = useState < ? string > (null)', + errors: [{ message: 'There must be no space at start of type annotations' }], + output: 'const [state, setState] = useState(null)', + }, + { + code: 'const [state, setState] = useState < ? string > ()', + errors: [{ message: 'There must be no space at start of type annotations' }], + output: 'const [state, setState] = useState(null)', + }, + { + code: 'useState(null)', + errors: [{ message: 'There must be no space at start of type annotations' }], + output: 'useState(null)', + }, + { + code: 'useState< string>(null)', + errors: [{ message: 'There must be no space at start of type annotations' }], + output: 'useState(null)', + }, + { + code: 'useState< string >(null)', + errors: [{ message: 'There must be no space at start of type annotations' }], + output: 'useState(null)', + }, ], misconfigured: [ { @@ -131,7 +192,7 @@ export default { { code: 'type X = Promise<(foo), bar, (((baz)))>' }, { code: -`type X = Promise< + `type X = Promise< (foo), bar, (((baz))) @@ -153,5 +214,43 @@ export default { code: 'type X = Promise< (foo), bar, (((baz))) >', options: ['always'], }, + { + code: 'const [state, setState] = useState< string >("")', + options: ['always'], + }, + { + code: 'const [state, setState] = useState< ?string >(null)', + options: ['always'], + }, + { + code: 'const [state, setState] = useState< string | null >(null)', + options: ['always'], + }, + { + code: 'const [state, setState] = useState< string | number >(2)', + options: ['always'], + }, + + // Never + { + code: 'const [state, setState] = useState(null)', + options: ['never'], + }, + { + code: 'const [state, setState] = useState("")', + options: ['never'], + }, + { + code: 'const [state, setState] = useState(null)', + options: ['never'], + }, + { + code: 'const [state, setState] = useState(null)', + options: ['never'], + }, + { + code: 'const [state, setState] = useState(2)', + options: ['never'], + }, ], }; diff --git a/tests/rules/assertions/typeAnnotationSpacing.js b/tests/rules/assertions/typeAnnotationSpacing.js deleted file mode 100644 index e41bb43..0000000 --- a/tests/rules/assertions/typeAnnotationSpacing.js +++ /dev/null @@ -1,114 +0,0 @@ -export default { - invalid: [ - // { - // code: 'const [state, setState] = useState(null)', - // errors: [{ message: 'There must be no space at start of type annotations' }], - // output: 'const [state, setState] = useState(null)', - // }, - // { - // code: 'const [state, setState] = useState (null)', - // errors: [{ message: 'There must be no space at start of type annotations' }], - // output: 'const [state, setState] = useState(null)', - // }, - // { - // code: 'const [state, setState] = useState< ?string>(null)', - // errors: [{ message: 'There must be no space at start of type annotations' }], - // output: 'const [state, setState] = useState(null)', - // }, - // { - // code: 'const [state, setState] = useState < ?string>(null)', - // errors: [{ message: 'There must be no space at start of type annotations' }], - // output: 'const [state, setState] = useState(null)', - // }, - // { - // code: 'const [state, setState] = useState(null)', - // errors: [{ message: 'There must be no space at start of type annotations' }], - // output: 'const [state, setState] = useState(null)', - // }, - // { - // code: 'const [state, setState] = useState< ? string>(null)', - // errors: [{ message: 'There must be no space at start of type annotations' }], - // output: 'const [state, setState] = useState(null)', - // }, - // { - // code: 'const [state, setState] = useState< ? string >(null)', - // errors: [{ message: 'There must be no space at start of type annotations' }], - // output: 'const [state, setState] = useState(null)', - // }, - // { - // code: 'const [state, setState] = useState < ? string > (null)', - // errors: [{ message: 'There must be no space at start of type annotations' }], - // output: 'const [state, setState] = useState(null)', - // }, - // { - // code: 'const [state, setState] = useState < ? string > ()', - // errors: [{ message: 'There must be no space at start of type annotations' }], - // output: 'const [state, setState] = useState(null)', - // }, - { - code: 'useState(null)', - errors: [{ message: 'There must be no space at start of type annotations' }], - output: 'useState(null)', - }, - { - code: 'useState< string>(null)', - errors: [{ message: 'There must be no space at start of type annotations' }], - output: 'useState(null)', - }, - { - code: 'useState< string >(null)', - errors: [{ message: 'There must be no space at start of type annotations' }], - output: 'useState(null)', - }, - ], - misconfigured: [ - { - errors: [ - { - data: 'frequently', - instancePath: '/0', - keyword: 'enum', - message: 'must be equal to one of the allowed values', - params: { - allowedValues: [ - 'always', - 'never', - ], - }, - parentSchema: { - enum: [ - 'always', - 'never', - ], - type: 'string', - }, - schema: [ - 'always', - 'never', - ], - schemaPath: '#/items/0/enum', - }, - ], - options: [ - 'frequently', - ], - }, - ], - valid: [ - { - code: 'const [state, setState] = useState(null)', - }, - { - code: 'const [state, setState] = useState("")', - }, - // { - // code: 'const [state, setState] = useState(null)', - // }, - { - code: 'const [state, setState] = useState(null)', - }, - { - code: 'const [state, setState] = useState(2)', - }, - ], -}; diff --git a/tests/rules/index.js b/tests/rules/index.js index 2ff6eaf..9976b20 100644 --- a/tests/rules/index.js +++ b/tests/rules/index.js @@ -66,7 +66,6 @@ const reportingRules = [ 'space-before-generic-bracket', 'space-before-type-colon', 'spread-exact-type', - 'type-annotation-spacing', 'type-id-match', 'type-import-style', 'union-intersection-spacing',