Skip to content

Commit

Permalink
fix: annotate fixable rules (#458)
Browse files Browse the repository at this point in the history
...and fix a few lint errors

The latest version of ESLint RuleTester has a hard requirement that all fixable rules declare `meta.fixable`.
I was going to work on an issue, but this was blocking all tests after doing a fresh npm install.
  • Loading branch information
bradzacher committed Feb 18, 2021
1 parent e93f1c0 commit 61c4a3c
Show file tree
Hide file tree
Showing 21 changed files with 137 additions and 84 deletions.
1 change: 1 addition & 0 deletions src/index.js
@@ -1,3 +1,4 @@
/* eslint-disable import/max-dependencies */
import _ from 'lodash';
import recommended from './configs/recommended.json';
import arrayStyleComplexType from './rules/arrayStyleComplexType';
Expand Down
3 changes: 3 additions & 0 deletions src/rules/arrayStyle/index.js
Expand Up @@ -80,6 +80,9 @@ export default (defaultConfig, simpleType) => {

return {
create,
meta: {
fixable: 'code',
},
schema,
};
};
3 changes: 3 additions & 0 deletions src/rules/booleanStyle.js
Expand Up @@ -37,5 +37,8 @@ const create = (context) => {

export default {
create,
meta: {
fixable: 'code',
},
schema,
};
53 changes: 28 additions & 25 deletions src/rules/delimiterDangle.js
Expand Up @@ -15,6 +15,31 @@ const schema = [
},
];

// required for reporting the correct position
const getLast = (property, indexer) => {
if (!property) {
return indexer;
}

if (!indexer) {
return property;
}

if (property.loc.end.line > indexer.loc.end.line) {
return property;
}

if (indexer.loc.end.line > property.loc.end.line) {
return indexer;
}

if (property.loc.end.column > indexer.loc.end.column) {
return property;
}

return indexer;
};

const create = (context) => {
const option = context.options[0] || 'never';
const interfaceOption = context.options[1] || option;
Expand Down Expand Up @@ -97,31 +122,6 @@ const create = (context) => {
}
};

// required for reporting the correct position
const getLast = (property, indexer) => {
if (!property) {
return indexer;
}

if (!indexer) {
return property;
}

if (property.loc.end.line > indexer.loc.end.line) {
return property;
}

if (indexer.loc.end.line > property.loc.end.line) {
return indexer;
}

if (property.loc.end.column > indexer.loc.end.column) {
return property;
}

return indexer;
};

return {
ObjectTypeAnnotation (node) {
evaluate(node, getLast(_.last(node.properties), _.last(node.indexers)));
Expand All @@ -135,5 +135,8 @@ const create = (context) => {

export default {
create,
meta: {
fixable: 'code',
},
schema,
};
3 changes: 3 additions & 0 deletions src/rules/genericSpacing.js
Expand Up @@ -90,5 +90,8 @@ const create = (context) => {

export default {
create,
meta: {
fixable: 'code',
},
schema,
};
3 changes: 3 additions & 0 deletions src/rules/newlineAfterFlowAnnotation.js
Expand Up @@ -71,5 +71,8 @@ const create = (context) => {

export default {
create,
meta: {
fixable: 'code',
},
schema,
};
3 changes: 3 additions & 0 deletions src/rules/noMutableArray.js
Expand Up @@ -58,5 +58,8 @@ const create = (context) => {

export default {
create,
meta: {
fixable: 'code',
},
schema,
};
3 changes: 3 additions & 0 deletions src/rules/objectTypeDelimiter.js
Expand Up @@ -66,5 +66,8 @@ const schema = [

export default {
create,
meta: {
fixable: 'code',
},
schema,
};
3 changes: 3 additions & 0 deletions src/rules/requireIndexerName.js
Expand Up @@ -33,5 +33,8 @@ const create = (context) => {

export default {
create,
meta: {
fixable: 'code',
},
schema,
};
42 changes: 21 additions & 21 deletions src/rules/requireReadonlyReactProps.js
Expand Up @@ -21,6 +21,27 @@ const isReactComponent = (node) => {
);
};

const isReadOnlyObjectType = (node) => {
if (!node || node.type !== 'ObjectTypeAnnotation') {
return false;
}

// we consider `{||}` to be ReadOnly since it's exact AND has no props
if (node.exact && node.properties.length === 0) {
return true;
}

// { +foo: ..., +bar: ..., ... }
return node.properties.length > 0 &&
node.properties.every((prop) => {
return prop.variance && prop.variance.kind === 'plus';
});
};

const isReadOnlyType = (node) => {
return node.right.id && reReadOnly.test(node.right.id.name) || isReadOnlyObjectType(node.right);
};

const create = (context) => {
const readOnlyTypes = [];
const foundTypes = [];
Expand All @@ -32,27 +53,6 @@ const create = (context) => {
return id && !reReadOnly.test(id.name) && !readOnlyTypes.includes(id.name) && foundTypes.includes(id.name);
};

const isReadOnlyObjectType = (node) => {
if (!node || node.type !== 'ObjectTypeAnnotation') {
return false;
}

// we consider `{||}` to be ReadOnly since it's exact AND has no props
if (node.exact && node.properties.length === 0) {
return true;
}

// { +foo: ..., +bar: ..., ... }
return node.properties.length > 0 &&
node.properties.every((prop) => {
return prop.variance && prop.variance.kind === 'plus';
});
};

const isReadOnlyType = (node) => {
return node.right.id && reReadOnly.test(node.right.id.name) || isReadOnlyObjectType(node.right);
};

for (const node of context.getSourceCode().ast.body) {
let idName;
let typeNode;
Expand Down
24 changes: 14 additions & 10 deletions src/rules/requireReturnType.js
Expand Up @@ -35,15 +35,19 @@ const schema = [
},
];

const makeRegExp = (str) => {
return new RegExp(str);
};

const isUndefinedReturnType = (returnNode) => {
return returnNode.argument === null || returnNode.argument.name === 'undefined' || returnNode.argument.operator === 'void';
};

const create = (context) => {
const annotateReturn = (_.get(context, 'options[0]') || 'always') === 'always';
const annotateUndefined = _.get(context, 'options[1].annotateUndefined') || 'never';
const skipArrows = _.get(context, 'options[1].excludeArrowFunctions') || false;

const makeRegExp = (str) => {
return new RegExp(str);
};

const excludeMatching = _.get(context, 'options[1].excludeMatching', []).map(makeRegExp);
const includeOnlyMatching = _.get(context, 'options[1].includeOnlyMatching', []).map(makeRegExp);

Expand All @@ -55,12 +59,9 @@ const create = (context) => {
});
};

const isUndefinedReturnType = (returnNode) => {
return returnNode.argument === null || returnNode.argument.name === 'undefined' || returnNode.argument.operator === 'void';
};

const getIsReturnTypeAnnotationUndefined = (targetNode) => {
const isReturnTypeAnnotationLiteralUndefined = _.get(targetNode, 'functionNode.returnType.typeAnnotation.id.name') === 'undefined' && _.get(targetNode, 'functionNode.returnType.typeAnnotation.type') === 'GenericTypeAnnotation';
const isReturnTypeAnnotationLiteralUndefined = _.get(targetNode, 'functionNode.returnType.typeAnnotation.id.name') === 'undefined' &&
_.get(targetNode, 'functionNode.returnType.typeAnnotation.type') === 'GenericTypeAnnotation';
const isReturnTypeAnnotationVoid = _.get(targetNode, 'functionNode.returnType.typeAnnotation.type') === 'VoidTypeAnnotation';
const isAsyncReturnTypeAnnotationVoid = _.get(targetNode, 'functionNode.async') &&
_.get(targetNode, 'functionNode.returnType.typeAnnotation.id.name') === 'Promise' && (
Expand Down Expand Up @@ -113,7 +114,10 @@ const create = (context) => {

const isArrow = functionNode.type === 'ArrowFunctionExpression';
const isArrowFunctionExpression = functionNode.expression;
const isFunctionReturnUndefined = !isArrowFunctionExpression && !functionNode.generator && (!targetNode.returnStatementNode || isUndefinedReturnType(targetNode.returnStatementNode));
const isFunctionReturnUndefined =
!isArrowFunctionExpression &&
!functionNode.generator &&
(!targetNode.returnStatementNode || isUndefinedReturnType(targetNode.returnStatementNode));
const isReturnTypeAnnotationUndefined = getIsReturnTypeAnnotationUndefined(targetNode);

if (skipArrows === 'expressionsOnly' && isArrowFunctionExpression || skipArrows === true && isArrow || shouldFilterNode(functionNode)) {
Expand Down
3 changes: 3 additions & 0 deletions src/rules/requireValidFileAnnotation.js
Expand Up @@ -156,5 +156,8 @@ const create = (context) => {

export default {
create,
meta: {
fixable: 'code',
},
schema,
};
11 changes: 7 additions & 4 deletions src/rules/semi.js
Expand Up @@ -5,6 +5,10 @@ const schema = [
},
];

const isSemicolon = (token) => {
return token.type === 'Punctuator' && token.value === ';';
};

const create = (context) => {
const never = (context.options[0] || 'always') === 'never';
const sourceCode = context.getSourceCode();
Expand Down Expand Up @@ -37,10 +41,6 @@ const create = (context) => {
});
};

const isSemicolon = (token) => {
return token.type === 'Punctuator' && token.value === ';';
};

const checkForSemicolon = (node) => {
const lastToken = sourceCode.getLastToken(node);
const isLastTokenSemicolon = isSemicolon(lastToken);
Expand All @@ -67,5 +67,8 @@ const create = (context) => {

export default {
create,
meta: {
fixable: 'code',
},
schema,
};
3 changes: 3 additions & 0 deletions src/rules/sortKeys.js
Expand Up @@ -220,5 +220,8 @@ const create = (context) => {

export default {
create,
meta: {
fixable: 'code',
},
schema,
};
3 changes: 3 additions & 0 deletions src/rules/spaceAfterTypeColon.js
Expand Up @@ -26,5 +26,8 @@ const create = (context) => {

export default {
create,
meta: {
fixable: 'code',
},
schema,
};
3 changes: 3 additions & 0 deletions src/rules/spaceBeforeGenericBracket.js
Expand Up @@ -55,5 +55,8 @@ const create = (context) => {

export default {
create,
meta: {
fixable: 'code',
},
schema,
};
3 changes: 3 additions & 0 deletions src/rules/spaceBeforeTypeColon.js
Expand Up @@ -15,5 +15,8 @@ const create = (context) => {

export default {
create,
meta: {
fixable: 'code',
},
schema,
};
3 changes: 3 additions & 0 deletions src/rules/typeImportStyle.js
Expand Up @@ -87,5 +87,8 @@ const create = (context) => {

export default {
create,
meta: {
fixable: 'code',
},
schema,
};
3 changes: 3 additions & 0 deletions src/rules/unionIntersectionSpacing.js
Expand Up @@ -75,5 +75,8 @@ const create = (context) => {

export default {
create,
meta: {
fixable: 'code',
},
schema,
};
1 change: 1 addition & 0 deletions src/utilities/checkFlowFileAnnotation.js
Expand Up @@ -9,5 +9,6 @@ export default (cb, context) => {
return () => {};
}

// eslint-disable-next-line promise/prefer-await-to-callbacks -- not a promise callback
return cb(context);
};

0 comments on commit 61c4a3c

Please sign in to comment.