Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(eslint-plugin): apply final v6 changes to configs #7110

Merged
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 4 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ module.exports = {
// make sure we're not leveraging any deprecated APIs
'deprecation/deprecation': 'error',

// Pending: https://github.com/typescript-eslint/typescript-eslint/issues/4820
// (too many false positives)
'@typescript-eslint/prefer-nullish-coalescing': 'off',
JoshuaKGoldberg marked this conversation as resolved.
Show resolved Hide resolved

//
// our plugin :D
//
Expand Down Expand Up @@ -85,7 +89,6 @@ module.exports = {
'@typescript-eslint/no-non-null-assertion': 'off',
'@typescript-eslint/no-var-requires': 'off',
'@typescript-eslint/prefer-for-of': 'error',
'@typescript-eslint/prefer-nullish-coalescing': 'error',
'@typescript-eslint/prefer-optional-chain': 'error',
'@typescript-eslint/unbound-method': 'off',
'@typescript-eslint/prefer-as-const': 'error',
Expand Down
5 changes: 1 addition & 4 deletions packages/ast-spec/tests/util/serialize-error.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,7 @@ import { codeFrameColumns } from '@babel/code-frame';

import { TSError } from './parsers/typescript-estree-import';

export function serializeError(
error: unknown,
contents: string,
): unknown | string {
export function serializeError(error: unknown, contents: string): unknown {
if (!(error instanceof TSError)) {
return error;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ export = {
'@typescript-eslint/ban-types': 'error',
'no-array-constructor': 'off',
'@typescript-eslint/no-array-constructor': 'error',
'@typescript-eslint/no-base-to-string': 'error',
'@typescript-eslint/no-duplicate-enum-values': 'error',
'@typescript-eslint/no-duplicate-type-constituents': 'error',
'@typescript-eslint/no-extra-non-null-assertion': 'error',
'@typescript-eslint/no-floating-promises': 'error',
'@typescript-eslint/no-for-in-array': 'error',
Expand All @@ -23,14 +25,18 @@ export = {
'@typescript-eslint/no-loss-of-precision': 'error',
'@typescript-eslint/no-misused-new': 'error',
'@typescript-eslint/no-misused-promises': 'error',
'@typescript-eslint/no-mixed-enums': 'error',
'@typescript-eslint/no-namespace': 'error',
'@typescript-eslint/no-non-null-asserted-optional-chain': 'error',
'@typescript-eslint/no-redundant-type-constituents': 'error',
'@typescript-eslint/no-this-alias': 'error',
'@typescript-eslint/no-unnecessary-type-assertion': 'error',
'@typescript-eslint/no-unnecessary-type-constraint': 'error',
'@typescript-eslint/no-unsafe-argument': 'error',
'@typescript-eslint/no-unsafe-assignment': 'error',
'@typescript-eslint/no-unsafe-call': 'error',
'@typescript-eslint/no-unsafe-declaration-merging': 'error',
'@typescript-eslint/no-unsafe-enum-comparison': 'error',
'@typescript-eslint/no-unsafe-member-access': 'error',
'@typescript-eslint/no-unsafe-return': 'error',
'no-unused-vars': 'off',
Expand Down
1 change: 1 addition & 0 deletions packages/eslint-plugin/src/configs/recommended.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export = {
'@typescript-eslint/no-non-null-asserted-optional-chain': 'error',
'@typescript-eslint/no-this-alias': 'error',
'@typescript-eslint/no-unnecessary-type-constraint': 'error',
'@typescript-eslint/no-unsafe-declaration-merging': 'error',
'no-unused-vars': 'off',
'@typescript-eslint/no-unused-vars': 'error',
'@typescript-eslint/no-var-requires': 'error',
Expand Down
2 changes: 2 additions & 0 deletions packages/eslint-plugin/src/configs/strict-type-checked.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export = {
'@typescript-eslint/no-array-constructor': 'error',
'@typescript-eslint/no-base-to-string': 'error',
'@typescript-eslint/no-duplicate-enum-values': 'error',
'@typescript-eslint/no-duplicate-type-constituents': 'error',
'@typescript-eslint/no-dynamic-delete': 'error',
'@typescript-eslint/no-explicit-any': 'error',
'@typescript-eslint/no-extra-non-null-assertion': 'error',
Expand All @@ -34,6 +35,7 @@ export = {
'@typescript-eslint/no-non-null-asserted-nullish-coalescing': 'error',
'@typescript-eslint/no-non-null-asserted-optional-chain': 'error',
'@typescript-eslint/no-non-null-assertion': 'error',
'@typescript-eslint/no-redundant-type-constituents': 'error',
'@typescript-eslint/no-this-alias': 'error',
'no-throw-literal': 'off',
'@typescript-eslint/no-throw-literal': 'error',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export = {
'dot-notation': 'off',
'@typescript-eslint/dot-notation': 'error',
'@typescript-eslint/no-confusing-non-null-assertion': 'error',
'@typescript-eslint/no-confusing-void-expression': 'error',
'no-empty-function': 'off',
'@typescript-eslint/no-empty-function': 'error',
'@typescript-eslint/no-empty-interface': 'error',
Expand Down
1 change: 1 addition & 0 deletions packages/eslint-plugin/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export = {
'disable-type-checked': disableTypeChecked,
'eslint-recommended': eslintRecommended,
recommended,
/** @deprecated - please use "recommended-type-checked" instead. */
'recommended-requiring-type-checking': recommendedTypeChecked,
'recommended-type-checked': recommendedTypeChecked,
strict,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ export default util.createRule<Options, MessageIds>({
const symbol = services.getSymbolAtLocation(specifier.exported);
const aliasedSymbol = checker.getAliasedSymbol(symbol!);

// eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison
if (!aliasedSymbol || aliasedSymbol.escapedName === 'unknown') {
JoshuaKGoldberg marked this conversation as resolved.
Show resolved Hide resolved
return undefined;
}
Expand Down
4 changes: 2 additions & 2 deletions packages/eslint-plugin/src/rules/no-base-to-string.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import * as ts from 'typescript';
import * as util from '../util';

enum Usefulness {
Always,
Always = 'always',
Never = 'will',
Sometimes = 'may',
}
JoshuaKGoldberg marked this conversation as resolved.
Show resolved Hide resolved
Expand All @@ -23,7 +23,7 @@ export default util.createRule<Options, MessageIds>({
docs: {
description:
'Require `.toString()` to only be called on objects which provide useful information when stringified',
recommended: 'strict',
recommended: 'recommended',
requiresTypeChecking: true,
},
messages: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export default util.createRule<Options, MessageId>({
docs: {
description:
'Require expressions of type void to appear in statement position',
recommended: 'stylistic',
requiresTypeChecking: true,
},
messages: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ export default util.createRule<Options, MessageIds>({
docs: {
description:
'Disallow duplicate constituents of union or intersection types',
recommended: 'recommended',
requiresTypeChecking: true,
},
fixable: 'code',
Expand Down
1 change: 1 addition & 0 deletions packages/eslint-plugin/src/rules/no-empty-interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ export default util.createRule<Options, MessageIds>({

const isInAmbientDeclaration = !!(
util.isDefinitionFile(filename) &&
// eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison
scope.type === 'tsModule' &&
JoshuaKGoldberg marked this conversation as resolved.
Show resolved Hide resolved
scope.block.declare
);
Expand Down
1 change: 1 addition & 0 deletions packages/eslint-plugin/src/rules/no-implied-eval.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ export default util.createRule({
return true;
}

// eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison
if (symbol && symbol.escapedName === FUNCTION_CONSTRUCTOR) {
const declarations = symbol.getDeclarations() ?? [];
for (const declaration of declarations) {
Expand Down
2 changes: 1 addition & 1 deletion packages/eslint-plugin/src/rules/no-mixed-enums.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export default util.createRule({
meta: {
docs: {
description: 'Disallow enums from having both number and string members',
recommended: 'strict',
recommended: 'recommended',
requiresTypeChecking: true,
},
messages: {
Expand Down
1 change: 1 addition & 0 deletions packages/eslint-plugin/src/rules/no-redeclare.ts
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,7 @@ export default util.createRule<Options, MessageIds>({

// Node.js or ES modules has a special scope.
if (
// eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison
scope.type === 'global' &&
JoshuaKGoldberg marked this conversation as resolved.
Show resolved Hide resolved
scope.childScopes[0] &&
// The special scope's block is the Program node.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ function describeLiteralType(type: ts.Type): string {
}

if (type.isLiteral()) {
// eslint-disable-next-line @typescript-eslint/no-base-to-string
return type.value.toString();
}

Expand Down Expand Up @@ -182,6 +183,7 @@ export default util.createRule({
docs: {
description:
'Disallow members of unions and intersections that do nothing or override type information',
recommended: 'recommended',
requiresTypeChecking: true,
},
messages: {
Expand Down
1 change: 1 addition & 0 deletions packages/eslint-plugin/src/rules/no-shadow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,7 @@ export default util.createRule<Options, MessageIds>({
): TSESLint.Scope.Scope | null {
const upper = scope.upper;

// eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison
if (upper?.type === 'function-expression-name') {
JoshuaKGoldberg marked this conversation as resolved.
Show resolved Hide resolved
return upper.upper;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export default util.createRule({
type: 'problem',
docs: {
description: 'Disallow unsafe declaration merging',
recommended: 'strict',
recommended: 'recommended',
requiresTypeChecking: false,
},
messages: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export default util.createRule({
type: 'suggestion',
docs: {
description: 'Disallow comparing an enum value with a non-enum value',
recommended: 'strict',
recommended: 'recommended',
requiresTypeChecking: true,
},
messages: {
Expand Down
6 changes: 3 additions & 3 deletions packages/eslint-plugin/src/rules/prefer-nullish-coalescing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,9 @@ export default util.createRule<Options, MessageIds>({
},
defaultOptions: [
{
ignoreConditionalTests: true,
ignoreTernaryTests: true,
ignoreMixedLogicalExpressions: true,
ignoreConditionalTests: false,
ignoreTernaryTests: false,
ignoreMixedLogicalExpressions: false,
allowRuleToRunWithoutStrictNullChecksIKnowWhatIAmDoing: false,
},
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export default util.createRule<Options, MessageIds>({
name: 'require-array-sort-compare',
defaultOptions: [
{
ignoreStringArrays: false,
ignoreStringArrays: true,
},
],

Expand Down
7 changes: 6 additions & 1 deletion packages/eslint-plugin/src/rules/restrict-plus-operands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,19 +72,24 @@ export default util.createRule<Options, MessageIds>({
},
defaultOptions: [
{
allowAny: true,
allowBoolean: true,
allowNullish: true,
allowNumberAndString: true,
allowRegExp: true,
Comment on lines +75 to +79
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JoshuaKGoldberg i don't remember our discussion here - why did we turn all of the options on?
I thought we discussed that turning all the rule options on was bad as it made the rule effectively useless.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The issue was that it was chafing a lot of users by being very strict by default. A lot of folks are intentionally e.g. logging template literal strings with various primitives inside.

This does bring up the idea of having different configs in the strict ruleset than recommended... that would be a nice way to still get folks using the rule to its fullest if they want to be more strict. 🤔 #7318

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your example is template strings - but this is restrict-plus-operands.

So was this an accidental mix-up?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it applies to both of them. I've seen both happen with users. Which is why I keep mixing them up in comments 😅 to me, they're similar -just not exactly the same- cases.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess the question is - why even have these turned on at all if all the options are on by default?
The rules enforce pretty nothing like this so it's just wasted lint time.

Eg for RPO there's the following cases. Of these 16 cases the default options mean the rule only matches FOUR cases - two of which are TS already errors.

So we're recommending a rule to everyone to stop them from doing: string + object and string + unknown. The former is also banned under no-base-to-string, and one could argue the latter should be allowed under the allowAny option.

tl;dr - why are we even turning on the rules in the recommended set if they don't do anything with an overly permissive default option?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A couple reasons swayed me:

  • (lesser) There is benefit to string + unknown
  • (greater) I've seen a projects turn off no-base-to-string without turning off restrict-plus-operands

From a performance perspective, if one of these two rules is already asking for the types of these, I some level of caching on the TypeScript side would make the other rule not a significant change.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The thing I'd point to is that we added this big caution block to the RPO docs because we didn't think people using the options was good - and yet it's the default that everyone uses these options?
https://typescript-eslint.io/rules/restrict-plus-operands#:~:text=%2C%0A%5D%3B-,CAUTION,-We%20generally%20recommend

Just seems like we're contradicting ourselves "don't use these options but also they're all turned on by default"

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah :/ agreed. I don't like this.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personal preference:
Given this rule is really doing nothing and a lot of people don't like it - we should just undo this change and only include it in strict-type-checked

skipCompoundAssignments: false,
},
],
create(
context,
[
{
skipCompoundAssignments,
allowAny,
allowBoolean,
allowNullish,
allowNumberAndString,
allowRegExp,
skipCompoundAssignments,
},
],
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,11 @@ export default util.createRule<Options, MessageId>({
},
defaultOptions: [
{
allowAny: true,
allowBoolean: true,
allowNullish: true,
allowNumber: true,
allowRegExp: true,
},
],
create(context, [options]) {
Expand Down
1 change: 1 addition & 0 deletions packages/eslint-plugin/src/rules/unbound-method.ts
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,7 @@ function checkMethod(
const firstParam = decl.parameters[0];
const firstParamIsThis =
firstParam?.name.kind === ts.SyntaxKind.Identifier &&
// eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison
firstParam?.name.escapedText === 'this';
const thisArgIsVoid =
firstParamIsThis &&
Expand Down
1 change: 1 addition & 0 deletions packages/eslint-plugin/src/util/collectUnusedVariables.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ class UnusedVarsVisitor<
const scope = this.#scopeManager.acquire(node, inner);

if (scope) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison
if (scope.type === 'function-expression-name') {
JoshuaKGoldberg marked this conversation as resolved.
Show resolved Hide resolved
return scope.childScopes[0] as T;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,19 +138,37 @@ ruleTester.run('require-array-sort-compare', rule, {
},
{
code: `
function f(a: string[]) {
function f(a: number[]) {
a.sort();
}
`,
errors: [{ messageId: 'requireCompare' }],
},
{
code: `
function f(a: number[]) {
a.sort();
}
`,
errors: [{ messageId: 'requireCompare' }],
options: [{ ignoreStringArrays: false }],
},
{
code: `
function f(a: number | number[]) {
if (Array.isArray(a)) a.sort();
}
`,
errors: [{ messageId: 'requireCompare' }],
},
{
code: `
function f(a: string | string[]) {
if (Array.isArray(a)) a.sort();
}
`,
errors: [{ messageId: 'requireCompare' }],
options: [{ ignoreStringArrays: false }],
},
{
code: `
Expand Down Expand Up @@ -179,32 +197,32 @@ ruleTester.run('require-array-sort-compare', rule, {
// optional chain
{
code: `
function f(a: string[]) {
function f(a: number[]) {
a?.sort();
}
`,
errors: [{ messageId: 'requireCompare' }],
},
{
code: `
['foo', 'bar', 'baz'].sort();
[1, 2, 3].sort();
`,
errors: [{ messageId: 'requireCompare' }],
},
{
code: `
function getString() {
return 'foo';
function getNumber() {
return 1;
}
[getString(), getString()].sort();
[getNumber(), getNumber()].sort();
`,
errors: [{ messageId: 'requireCompare' }],
},
{
code: `
const foo = 'foo';
const bar = 'bar';
const baz = 'baz';
const foo = 1;
const bar = 2;
const baz = 3;
[foo, bar, baz].sort();
`,
errors: [{ messageId: 'requireCompare' }],
Expand Down