Skip to content

Commit

Permalink
Merge branch 'master' into strict-boolean-expressions
Browse files Browse the repository at this point in the history
  • Loading branch information
bradzacher committed Jun 28, 2019
2 parents 724ae70 + 430d628 commit 7461986
Show file tree
Hide file tree
Showing 12 changed files with 206 additions and 44 deletions.
2 changes: 1 addition & 1 deletion packages/eslint-plugin/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ Then you should add `airbnb` (or `airbnb-base`) to your `extends` section of `.e
| [`@typescript-eslint/no-array-constructor`](./docs/rules/no-array-constructor.md) | Disallow generic `Array` constructors | :heavy_check_mark: | :wrench: | |
| [`@typescript-eslint/no-empty-function`](./docs/rules/no-empty-function.md) | Disallow empty functions | | | |
| [`@typescript-eslint/no-empty-interface`](./docs/rules/no-empty-interface.md) | Disallow the declaration of empty interfaces | :heavy_check_mark: | | |
| [`@typescript-eslint/no-explicit-any`](./docs/rules/no-explicit-any.md) | Disallow usage of the `any` type | :heavy_check_mark: | | |
| [`@typescript-eslint/no-explicit-any`](./docs/rules/no-explicit-any.md) | Disallow usage of the `any` type | :heavy_check_mark: | :wrench: | |
| [`@typescript-eslint/no-extra-parens`](./docs/rules/no-extra-parens.md) | Disallow unnecessary parentheses | | :wrench: | |
| [`@typescript-eslint/no-extraneous-class`](./docs/rules/no-extraneous-class.md) | Forbids the use of classes as namespaces | | | |
| [`@typescript-eslint/no-floating-promises`](./docs/rules/no-floating-promises.md) | Requires Promise-like values to be handled appropriately. | | | :thought_balloon: |
Expand Down
18 changes: 18 additions & 0 deletions packages/eslint-plugin/docs/rules/no-explicit-any.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,24 @@ function greet(param: Array<string>): string {}
function greet(param: Array<string>): Array<string> {}
```

## Options

The rule accepts an options object with the following properties:

```ts
type Options = {
// if true, auto-fixing will be made available in which the "any" type is converted to an "unknown" type
fixToUnknown: boolean;
// specify if arrays from the rest operator are considered okay
ignoreRestArgs: boolean;
};

const defaults = {
fixToUnknown: false,
ignoreRestArgs: false,
};
```

### ignoreRestArgs

A boolean to specify if arrays from the rest operator are considered okay. `false` by default.
Expand Down
77 changes: 41 additions & 36 deletions packages/eslint-plugin/src/rules/ban-types.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
import {
TSESLint,
TSESTree,
AST_NODE_TYPES,
} from '@typescript-eslint/experimental-utils';
import { TSESLint, TSESTree } from '@typescript-eslint/experimental-utils';
import * as util from '../util';

type Options = [
Expand All @@ -20,6 +16,31 @@ type Options = [
];
type MessageIds = 'bannedTypeMessage';

function stringifyTypeName(
node: TSESTree.EntityName,
sourceCode: TSESLint.SourceCode,
): string {
return sourceCode.getText(node).replace(/ /g, '');
}

function getCustomMessage(
bannedType: null | string | { message?: string; fixWith?: string },
) {
if (bannedType === null) {
return '';
}

if (typeof bannedType === 'string') {
return ` ${bannedType}`;
}

if (bannedType.message) {
return ` ${bannedType.message}`;
}

return '';
}

export default util.createRule<Options, MessageIds>({
name: 'ban-types',
meta: {
Expand Down Expand Up @@ -87,39 +108,23 @@ export default util.createRule<Options, MessageIds>({
],
create(context, [{ types: bannedTypes }]) {
return {
'TSTypeReference Identifier'(node: TSESTree.Identifier) {
if (
node.parent &&
node.parent.type !== AST_NODE_TYPES.TSQualifiedName
) {
if (node.name in bannedTypes) {
let customMessage = '';
const bannedCfgValue = bannedTypes[node.name];
TSTypeReference({ typeName }) {
const name = stringifyTypeName(typeName, context.getSourceCode());

let fix: TSESLint.ReportFixFunction | null = null;
if (name in bannedTypes) {
const bannedType = bannedTypes[name];
const customMessage = getCustomMessage(bannedType);
const fixWith = bannedType && (bannedType as any).fixWith;

if (typeof bannedCfgValue === 'string') {
customMessage += ` ${bannedCfgValue}`;
} else if (bannedCfgValue !== null) {
if (bannedCfgValue.message) {
customMessage += ` ${bannedCfgValue.message}`;
}
if (bannedCfgValue.fixWith) {
const fixWith = bannedCfgValue.fixWith;
fix = fixer => fixer.replaceText(node, fixWith);
}
}

context.report({
node,
messageId: 'bannedTypeMessage',
data: {
name: node.name,
customMessage,
},
fix,
});
}
context.report({
node: typeName,
messageId: 'bannedTypeMessage',
data: {
name: name,
customMessage,
},
fix: fixWith ? fixer => fixer.replaceText(typeName, fixWith) : null,
});
}
},
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ export default util.createRule({
const sourceCode = context.getSourceCode();

return {
// VariableDeclaration with kind type has only one VariableDeclarator
"TSTypeAliasDeclaration[typeAnnotation.type='TSTypeLiteral']"(
node: TSESTree.TSTypeAliasDeclaration,
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1382,6 +1382,10 @@ export default createRule<Options, MessageIds>({
},

VariableDeclaration(node) {
if (node.declarations.length === 0) {
return;
}

let variableIndent = Object.prototype.hasOwnProperty.call(
options.VariableDeclarator,
node.kind,
Expand Down
9 changes: 9 additions & 0 deletions packages/eslint-plugin/src/rules/indent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,15 @@ export default util.createRule<Options, MessageIds>({
}
},

VariableDeclaration(node: TSESTree.VariableDeclaration) {
// https://github.com/typescript-eslint/typescript-eslint/issues/441
if (node.declarations.length === 0) {
return;
}

return rules.VariableDeclaration(node);
},

TSAsExpression(node: TSESTree.TSAsExpression) {
// transform it to a BinaryExpression
return rules['BinaryExpression, LogicalExpression']({
Expand Down
26 changes: 24 additions & 2 deletions packages/eslint-plugin/src/rules/no-explicit-any.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,17 @@ import {
AST_NODE_TYPES,
} from '@typescript-eslint/experimental-utils';
import * as util from '../util';
import { TSESLint } from '@typescript-eslint/experimental-utils';

export default util.createRule({
export type Options = [
{
fixToUnknown?: boolean;
ignoreRestArgs?: boolean;
}
];
export type MessageIds = 'unexpectedAny';

export default util.createRule<Options, MessageIds>({
name: 'no-explicit-any',
meta: {
type: 'suggestion',
Expand All @@ -13,6 +22,7 @@ export default util.createRule({
category: 'Best Practices',
recommended: 'warn',
},
fixable: 'code',
messages: {
unexpectedAny: 'Unexpected any. Specify a different type.',
},
Expand All @@ -21,6 +31,9 @@ export default util.createRule({
type: 'object',
additionalProperties: false,
properties: {
fixToUnknown: {
type: 'boolean',
},
ignoreRestArgs: {
type: 'boolean',
},
Expand All @@ -30,10 +43,11 @@ export default util.createRule({
},
defaultOptions: [
{
fixToUnknown: false,
ignoreRestArgs: false,
},
],
create(context, [{ ignoreRestArgs }]) {
create(context, [{ ignoreRestArgs, fixToUnknown }]) {
/**
* Checks if the node is an arrow function, function declaration or function expression
* @param node the node to be validated.
Expand Down Expand Up @@ -155,9 +169,17 @@ export default util.createRule({
if (ignoreRestArgs && isNodeDescendantOfRestElementInFunction(node)) {
return;
}

let fix: TSESLint.ReportFixFunction | null = null;

if (fixToUnknown) {
fix = fixer => fixer.replaceText(node, 'unknown');
}

context.report({
node,
messageId: 'unexpectedAny',
fix,
});
},
};
Expand Down
5 changes: 4 additions & 1 deletion packages/eslint-plugin/src/rules/prefer-for-of.ts
Original file line number Diff line number Diff line change
Expand Up @@ -186,8 +186,11 @@ export default util.createRule({
return;
}

const [declarator] = node.init.declarations;
const declarator = node.init.declarations[0] as
| TSESTree.VariableDeclarator
| undefined;
if (
!declarator ||
!isZeroInitialized(declarator) ||
declarator.id.type !== AST_NODE_TYPES.Identifier
) {
Expand Down
78 changes: 78 additions & 0 deletions packages/eslint-plugin/tests/rules/ban-types.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ const options: InferOptionsTypeFromRule<typeof rule> = [
Object: "Use '{}' instead.",
Array: null,
F: null,
'NS.Bad': {
message: 'Use NS.Good instead.',
fixWith: 'NS.Good',
},
},
},
];
Expand All @@ -39,6 +43,14 @@ ruleTester.run('ban-types', rule, {
code: 'let e: foo.String;',
options,
},
{
code: 'let a: _.NS.Bad',
options,
},
{
code: 'let a: NS.Bad._',
options,
},
],
invalid: [
{
Expand All @@ -56,6 +68,25 @@ ruleTester.run('ban-types', rule, {
],
options,
},
{
code: 'let aa: Foo;',
errors: [
{
messageId: 'bannedTypeMessage',
data: {
name: 'Foo',
customMessage: '',
},
},
],
options: [
{
types: {
Foo: { message: '' },
},
},
],
},
{
code: 'let b: {c: String};',
output: 'let b: {c: string};',
Expand Down Expand Up @@ -217,5 +248,52 @@ class Foo<F = string> extends Bar<string> implements Baz<Object> {
],
options,
},
{
code: 'let a: NS.Bad;',
output: 'let a: NS.Good;',
errors: [
{
messageId: 'bannedTypeMessage',
data: {
name: 'NS.Bad',
customMessage: ' Use NS.Good instead.',
},
line: 1,
column: 8,
},
],
options,
},
{
code: `
let a: NS.Bad<Foo>;
let b: Foo<NS.Bad>;
`,
output: `
let a: NS.Good<Foo>;
let b: Foo<NS.Good>;
`,
errors: [
{
messageId: 'bannedTypeMessage',
data: {
name: 'NS.Bad',
customMessage: ' Use NS.Good instead.',
},
line: 2,
column: 8,
},
{
messageId: 'bannedTypeMessage',
data: {
name: 'NS.Bad',
customMessage: ' Use NS.Good instead.',
},
line: 3,
column: 12,
},
],
options,
},
],
});
2 changes: 2 additions & 0 deletions packages/eslint-plugin/tests/rules/indent/indent.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -768,6 +768,8 @@ const div: JQuery<HTMLElement> = $('<div>')
`,
options: [2, { VariableDeclarator: { const: 3 } }],
},
// https://github.com/typescript-eslint/typescript-eslint/issues/441
`const;`,
],
invalid: [
...individualNodeTests.invalid,
Expand Down

0 comments on commit 7461986

Please sign in to comment.