Skip to content

Commit

Permalink
feat: Implement fixation in array style rules
Browse files Browse the repository at this point in the history
  • Loading branch information
pnevyk committed Sep 29, 2017
1 parent afd4210 commit 4a6f03d
Show file tree
Hide file tree
Showing 8 changed files with 88 additions and 26 deletions.
2 changes: 2 additions & 0 deletions .README/rules/array-style-complex-type.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
### `array-style-complex-type`

_The `--fix` option on the command line automatically fixes problems reported by this rule._

Enforces a particular style for array type annotations for complex types. Type is considered complex in these cases:

* [Maybe type](https://flow.org/en/docs/types/maybe/)
Expand Down
2 changes: 2 additions & 0 deletions .README/rules/array-style-simple-type.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
### `array-style-simple-type`

_The `--fix` option on the command line automatically fixes problems reported by this rule._

Enforces a particular style for array type annotations for complex types. Type is considered simple in these cases:

* Primitive types
Expand Down
26 changes: 24 additions & 2 deletions src/rules/arrayStyle/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import isSimpleType from './isSimpleType';
import needWrap from './needWrap';

const schema = [
{
Expand All @@ -7,20 +8,41 @@ const schema = [
}
];

const fixShorthand = (context, node) => {
return (fixer) => {
const rawElementType = context.getSourceCode().getText(node.elementType);

return fixer.replaceText(node, 'Array<' + rawElementType + '>');
};
};

const fixVerbose = (context, node) => {
return (fixer) => {
const elementTypeNode = node.typeParameters.params[0];
const rawElementType = context.getSourceCode().getText(elementTypeNode);

if (needWrap(elementTypeNode)) {
return fixer.replaceText(node, '(' + rawElementType + ')[]');
} else {
return fixer.replaceText(node, rawElementType + '[]');
}
};
};

export default (defaultConfig, shorthandHandler, verboseHandler) => {
const create = (context) => {
const verbose = (context.options[0] || defaultConfig) === 'verbose';

return {
// shorthand
ArrayTypeAnnotation (node) {
shorthandHandler(isSimpleType(node.elementType), verbose, context, node);
shorthandHandler(isSimpleType(node.elementType), verbose, context, node, fixShorthand(context, node));
},
// verbose
GenericTypeAnnotation (node) {
if (node.id.name === 'Array') {
if (node.typeParameters.params.length === 1) {
verboseHandler(isSimpleType(node.typeParameters.params[0]), verbose, context, node);
verboseHandler(isSimpleType(node.typeParameters.params[0]), verbose, context, node, fixVerbose(context, node));
}
}
}
Expand Down
7 changes: 7 additions & 0 deletions src/rules/arrayStyle/needWrap.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import isSimpleType from './isSimpleType';

const complexTypesWithoutWrap = ['TupleTypeAnnotation', 'ObjectTypeAnnotation'];

export default (node) => {
return !isSimpleType(node) && complexTypesWithoutWrap.indexOf(node.type) === -1;
};
6 changes: 4 additions & 2 deletions src/rules/arrayStyleComplexType.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
import makeArrayStyleRule from './arrayStyle';

const shorthandHandler = (isSimpleType, verbose, context, node) => {
const shorthandHandler = (isSimpleType, verbose, context, node, fix) => {
if (!isSimpleType && verbose) {
context.report({
fix,
message: 'Use "Array<ComplexType>", not "ComplexType[]"',
node
});
}
};

const verboseHandler = (isSimpleType, verbose, context, node) => {
const verboseHandler = (isSimpleType, verbose, context, node, fix) => {
if (!isSimpleType && !verbose) {
context.report({
fix,
message: 'Use "ComplexType[]", not "Array<ComplexType>"',
node
});
Expand Down
6 changes: 4 additions & 2 deletions src/rules/arrayStyleSimpleType.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
import makeArrayStyleRule from './arrayStyle';

const shorthandHandler = (isSimpleType, verbose, context, node) => {
const shorthandHandler = (isSimpleType, verbose, context, node, fix) => {
if (isSimpleType && verbose) {
context.report({
fix,
message: 'Use "Array<SimpleType>", not "SimpleType[]"',
node
});
}
};

const verboseHandler = (isSimpleType, verbose, context, node) => {
const verboseHandler = (isSimpleType, verbose, context, node, fix) => {
if (isSimpleType && !verbose) {
context.report({
fix,
message: 'Use "SimpleType[]", not "Array<SimpleType>"',
node
});
Expand Down
32 changes: 23 additions & 9 deletions tests/rules/assertions/arrayStyleComplexType.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,37 +2,51 @@ export default {
invalid: [
{
code: 'type X = (?string)[]',
errors: [{message: 'Use "Array<ComplexType>", not "ComplexType[]"'}]
errors: [{message: 'Use "Array<ComplexType>", not "ComplexType[]"'}],
output: 'type X = Array<?string>'
},
{
code: 'type X = (?string)[]',
errors: [{message: 'Use "Array<ComplexType>", not "ComplexType[]"'}],
options: ['verbose']
options: ['verbose'],
output: 'type X = Array<?string>'
},
{
code: 'type X = Array<?string>',
errors: [{message: 'Use "ComplexType[]", not "Array<ComplexType>"'}],
options: ['shorthand']
options: ['shorthand'],
output: 'type X = (?string)[]'
},
{
code: 'type X = Array<{foo: string}>',
errors: [{message: 'Use "ComplexType[]", not "Array<ComplexType>"'}],
options: ['shorthand'],
output: 'type X = {foo: string}[]'
},
{
code: 'type X = (string | number)[]',
errors: [{message: 'Use "Array<ComplexType>", not "ComplexType[]"'}]
errors: [{message: 'Use "Array<ComplexType>", not "ComplexType[]"'}],
output: 'type X = Array<string | number>'
},
{
code: 'type X = (string & number)[]',
errors: [{message: 'Use "Array<ComplexType>", not "ComplexType[]"'}]
errors: [{message: 'Use "Array<ComplexType>", not "ComplexType[]"'}],
output: 'type X = Array<string & number>'
},
{
code: 'type X = [string, number][]',
errors: [{message: 'Use "Array<ComplexType>", not "ComplexType[]"'}]
errors: [{message: 'Use "Array<ComplexType>", not "ComplexType[]"'}],
output: 'type X = Array<[string, number]>'
},
{
code: 'type X = ({foo: string})[]',
errors: [{message: 'Use "Array<ComplexType>", not "ComplexType[]"'}]
code: 'type X = {foo: string}[]',
errors: [{message: 'Use "Array<ComplexType>", not "ComplexType[]"'}],
output: 'type X = Array<{foo: string}>'
},
{
code: 'type X = (string => number)[]',
errors: [{message: 'Use "Array<ComplexType>", not "ComplexType[]"'}]
errors: [{message: 'Use "Array<ComplexType>", not "ComplexType[]"'}],
output: 'type X = Array<string => number>'
}
],
misconfigured: [
Expand Down
33 changes: 22 additions & 11 deletions tests/rules/assertions/arrayStyleSimpleType.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,49 +2,60 @@ export default {
invalid: [
{
code: 'type X = Array<string>',
errors: [{message: 'Use "SimpleType[]", not "Array<SimpleType>"'}]
errors: [{message: 'Use "SimpleType[]", not "Array<SimpleType>"'}],
output: 'type X = string[]'
},
{
code: 'type X = string[]',
errors: [{message: 'Use "Array<SimpleType>", not "SimpleType[]"'}],
options: ['verbose']
options: ['verbose'],
output: 'type X = Array<string>'
},
{
code: 'type X = Array<string>',
errors: [{message: 'Use "SimpleType[]", not "Array<SimpleType>"'}],
options: ['shorthand']
options: ['shorthand'],
output: 'type X = string[]'
},
{
code: 'type X = Array<Date>',
errors: [{message: 'Use "SimpleType[]", not "Array<SimpleType>"'}]
errors: [{message: 'Use "SimpleType[]", not "Array<SimpleType>"'}],
output: 'type X = Date[]'
},
{
code: 'type X = Array<Promise<string>>',
errors: [{message: 'Use "SimpleType[]", not "Array<SimpleType>"'}]
errors: [{message: 'Use "SimpleType[]", not "Array<SimpleType>"'}],
output: 'type X = Promise<string>[]'
},
{
code: 'type X = Array<$Keys<{ foo: string }>>',
errors: [{message: 'Use "SimpleType[]", not "Array<SimpleType>"'}]
errors: [{message: 'Use "SimpleType[]", not "Array<SimpleType>"'}],
output: 'type X = $Keys<{ foo: string }>[]'
},
{
code: 'type X = Array<any>',
errors: [{message: 'Use "SimpleType[]", not "Array<SimpleType>"'}]
errors: [{message: 'Use "SimpleType[]", not "Array<SimpleType>"'}],
output: 'type X = any[]'
},
{
code: 'type X = Array<mixed>',
errors: [{message: 'Use "SimpleType[]", not "Array<SimpleType>"'}]
errors: [{message: 'Use "SimpleType[]", not "Array<SimpleType>"'}],
output: 'type X = mixed[]'
},
{
code: 'type X = Array<void>',
errors: [{message: 'Use "SimpleType[]", not "Array<SimpleType>"'}]
errors: [{message: 'Use "SimpleType[]", not "Array<SimpleType>"'}],
output: 'type X = void[]'
},
{
code: 'type X = Array<null>',
errors: [{message: 'Use "SimpleType[]", not "Array<SimpleType>"'}]
errors: [{message: 'Use "SimpleType[]", not "Array<SimpleType>"'}],
output: 'type X = null[]'
},
{
code: 'type X = Array<string[]>',
errors: [{message: 'Use "SimpleType[]", not "Array<SimpleType>"'}]
errors: [{message: 'Use "SimpleType[]", not "Array<SimpleType>"'}],
output: 'type X = string[][]'
}
],
misconfigured: [
Expand Down

0 comments on commit 4a6f03d

Please sign in to comment.