diff --git a/CHANGELOG.md b/CHANGELOG.md index 1045baf1cf99..84b1f8dc5b04 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.60.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.59.11...v5.60.0) (2023-06-19) + + +### Features + +* **eslint-plugin:** [restrict-plus-operands] add allow* options ([#6161](https://github.com/typescript-eslint/typescript-eslint/issues/6161)) ([def09f8](https://github.com/typescript-eslint/typescript-eslint/commit/def09f88cdb4a85cebb8619b45931f7e2c88dfc0)) + + + + + ## [5.59.11](https://github.com/typescript-eslint/typescript-eslint/compare/v5.59.10...v5.59.11) (2023-06-12) **Note:** Version bump only for package @typescript-eslint/typescript-eslint diff --git a/lerna.json b/lerna.json index bf1dc32ac6a1..c073d4c97103 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "5.59.11", + "version": "5.60.0", "npmClient": "yarn", "stream": true } diff --git a/packages/ast-spec/CHANGELOG.md b/packages/ast-spec/CHANGELOG.md index 350a927fbe84..e90aab762098 100644 --- a/packages/ast-spec/CHANGELOG.md +++ b/packages/ast-spec/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.60.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.59.11...v5.60.0) (2023-06-19) + +**Note:** Version bump only for package @typescript-eslint/ast-spec + + + + + ## [5.59.11](https://github.com/typescript-eslint/typescript-eslint/compare/v5.59.10...v5.59.11) (2023-06-12) **Note:** Version bump only for package @typescript-eslint/ast-spec diff --git a/packages/ast-spec/package.json b/packages/ast-spec/package.json index 9809284864c0..5724d13c62ff 100644 --- a/packages/ast-spec/package.json +++ b/packages/ast-spec/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/ast-spec", - "version": "5.59.11", + "version": "5.60.0", "description": "Complete specification for the TypeScript-ESTree AST", "private": true, "keywords": [ diff --git a/packages/eslint-plugin-internal/CHANGELOG.md b/packages/eslint-plugin-internal/CHANGELOG.md index a10095803a79..95e999545856 100644 --- a/packages/eslint-plugin-internal/CHANGELOG.md +++ b/packages/eslint-plugin-internal/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.60.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.59.11...v5.60.0) (2023-06-19) + +**Note:** Version bump only for package @typescript-eslint/eslint-plugin-internal + + + + + ## [5.59.11](https://github.com/typescript-eslint/typescript-eslint/compare/v5.59.10...v5.59.11) (2023-06-12) **Note:** Version bump only for package @typescript-eslint/eslint-plugin-internal diff --git a/packages/eslint-plugin-internal/package.json b/packages/eslint-plugin-internal/package.json index 4c063f0db6b1..a02a93688aeb 100644 --- a/packages/eslint-plugin-internal/package.json +++ b/packages/eslint-plugin-internal/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/eslint-plugin-internal", - "version": "5.59.11", + "version": "5.60.0", "private": true, "main": "dist/index.js", "scripts": { @@ -14,9 +14,9 @@ }, "dependencies": { "@types/prettier": "*", - "@typescript-eslint/scope-manager": "5.59.11", - "@typescript-eslint/type-utils": "5.59.11", - "@typescript-eslint/utils": "5.59.11", + "@typescript-eslint/scope-manager": "5.60.0", + "@typescript-eslint/type-utils": "5.60.0", + "@typescript-eslint/utils": "5.60.0", "prettier": "*" } } diff --git a/packages/eslint-plugin-tslint/CHANGELOG.md b/packages/eslint-plugin-tslint/CHANGELOG.md index db003145677a..3acf56156a6c 100644 --- a/packages/eslint-plugin-tslint/CHANGELOG.md +++ b/packages/eslint-plugin-tslint/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.60.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.59.11...v5.60.0) (2023-06-19) + +**Note:** Version bump only for package @typescript-eslint/eslint-plugin-tslint + + + + + ## [5.59.11](https://github.com/typescript-eslint/typescript-eslint/compare/v5.59.10...v5.59.11) (2023-06-12) **Note:** Version bump only for package @typescript-eslint/eslint-plugin-tslint diff --git a/packages/eslint-plugin-tslint/package.json b/packages/eslint-plugin-tslint/package.json index c881849d9c7b..8f5159a87a7e 100644 --- a/packages/eslint-plugin-tslint/package.json +++ b/packages/eslint-plugin-tslint/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/eslint-plugin-tslint", - "version": "5.59.11", + "version": "5.60.0", "main": "dist/index.js", "typings": "src/index.ts", "description": "ESLint plugin that wraps a TSLint configuration and lints the whole source using TSLint", @@ -38,7 +38,7 @@ "typecheck": "tsc -p tsconfig.json --noEmit" }, "dependencies": { - "@typescript-eslint/utils": "5.59.11" + "@typescript-eslint/utils": "5.60.0" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0", @@ -47,6 +47,6 @@ }, "devDependencies": { "@types/lodash": "*", - "@typescript-eslint/parser": "5.59.11" + "@typescript-eslint/parser": "5.60.0" } } diff --git a/packages/eslint-plugin/CHANGELOG.md b/packages/eslint-plugin/CHANGELOG.md index d4d2d5b78224..25721e8765c1 100644 --- a/packages/eslint-plugin/CHANGELOG.md +++ b/packages/eslint-plugin/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.60.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.59.11...v5.60.0) (2023-06-19) + + +### Features + +* **eslint-plugin:** [restrict-plus-operands] add allow* options ([#6161](https://github.com/typescript-eslint/typescript-eslint/issues/6161)) ([def09f8](https://github.com/typescript-eslint/typescript-eslint/commit/def09f88cdb4a85cebb8619b45931f7e2c88dfc0)) + + + + + ## [5.59.11](https://github.com/typescript-eslint/typescript-eslint/compare/v5.59.10...v5.59.11) (2023-06-12) **Note:** Version bump only for package @typescript-eslint/eslint-plugin diff --git a/packages/eslint-plugin/docs/rules/restrict-plus-operands.md b/packages/eslint-plugin/docs/rules/restrict-plus-operands.md index fc823f6da9f8..7abf7dc38c37 100644 --- a/packages/eslint-plugin/docs/rules/restrict-plus-operands.md +++ b/packages/eslint-plugin/docs/rules/restrict-plus-operands.md @@ -18,70 +18,180 @@ This rule reports when a `+` operation combines two values of different types, o ### ❌ Incorrect ```ts -var foo = '5.5' + 5; -var foo = 1n + 1; +let foo = '5.5' + 5; +let foo = 1n + 1; ``` ### ✅ Correct ```ts -var foo = parseInt('5.5', 10) + 10; -var foo = 1n + 1n; +let foo = parseInt('5.5', 10) + 10; +let foo = 1n + 1n; ``` ## Options -### `checkCompoundAssignments` +:::caution +We generally recommend against using these options, as they limit which varieties of incorrect `+` usage can be checked. +This in turn severely limits the validation that the rule can do to ensure that resulting strings and numbers are correct. + +Safer alternatives to using the `allow*` options include: + +- Using variadic forms of logging APIs to avoid needing to `+` values. + ```ts + // Remove this line + console.log('The result is ' + true); + // Add this line + console.log('The result is', true); + ``` +- Using `.toFixed()` to coerce numbers to well-formed string representations: + ```ts + const number = 1.123456789; + const result = 'The number is ' + number.toFixed(2); + // result === 'The number is 1.12' + ``` +- Calling `.toString()` on other types to mark explicit and intentional string coercion: + ```ts + const arg = '11'; + const regex = /[0-9]/; + const result = + 'The result of ' + + regex.toString() + + '.test("' + + arg + + '") is ' + + regex.test(arg).toString(); + // result === 'The result of /[0-9]/.test("11") is true' + ``` + +::: -Examples of code for this rule with `{ checkCompoundAssignments: true }`: +### `allowAny` + +Examples of code for this rule with `{ allowAny: true }`: #### ❌ Incorrect ```ts -/*eslint @typescript-eslint/restrict-plus-operands: ["error", { "checkCompoundAssignments": true }]*/ +let fn = (a: number, b: []) => a + b; +let fn = (a: string, b: []) => a + b; +``` -let foo: string | undefined; -foo += 'some data'; +#### ✅ Correct -let bar: string = ''; -bar += 0; +```ts +let fn = (a: number, b: any) => a + b; +let fn = (a: string, b: any) => a + b; +``` + +### `allowBoolean` + +Examples of code for this rule with `{ allowBoolean: true }`: + + + +#### ❌ Incorrect + +```ts +let fn = (a: number, b: unknown) => a + b; +let fn = (a: string, b: unknown) => a + b; ``` #### ✅ Correct ```ts -/*eslint @typescript-eslint/restrict-plus-operands: ["error", { "checkCompoundAssignments": true }]*/ +let fn = (a: number, b: boolean) => a + b; +let fn = (a: string, b: boolean) => a + b; +``` -let foo: number = 0; -foo += 1; +### `allowNullish` -let bar = ''; -bar += 'test'; +Examples of code for this rule with `{ allowNullish: true }`: + + + +#### ❌ Incorrect + +```ts +let fn = (a: number, b: unknown) => a + b; +let fn = (a: number, b: never) => a + b; +let fn = (a: string, b: unknown) => a + b; +let fn = (a: string, b: never) => a + b; ``` -### `allowAny` +#### ✅ Correct -Examples of code for this rule with `{ allowAny: true }`: +```ts +let fn = (a: number, b: undefined) => a + b; +let fn = (a: number, b: null) => a + b; +let fn = (a: string, b: undefined) => a + b; +let fn = (a: string, b: null) => a + b; +``` + +### `allowNumberAndString` + +Examples of code for this rule with `{ allowNumberAndString: true }`: #### ❌ Incorrect ```ts -var fn = (a: any, b: boolean) => a + b; -var fn = (a: any, b: []) => a + b; -var fn = (a: any, b: {}) => a + b; +let fn = (a: number, b: unknown) => a + b; +let fn = (a: number, b: never) => a + b; ``` #### ✅ Correct ```ts -var fn = (a: any, b: any) => a + b; -var fn = (a: any, b: string) => a + b; -var fn = (a: any, b: bigint) => a + b; -var fn = (a: any, b: number) => a + b; +let fn = (a: number, b: string) => a + b; +let fn = (a: number, b: number | string) => a + b; +``` + +### `allowRegExp` + +Examples of code for this rule with `{ allowRegExp: true }`: + + + +#### ❌ Incorrect + +```ts +let fn = (a: number, b: RegExp) => a + b; +``` + +#### ✅ Correct + +```ts +let fn = (a: string, b: RegExp) => a + b; +``` + +### `checkCompoundAssignments` + +Examples of code for this rule with `{ checkCompoundAssignments: true }`: + + + +#### ❌ Incorrect + +```ts +let foo: string | undefined; +foo += 'some data'; + +let bar: string = ''; +bar += 0; +``` + +#### ✅ Correct + +```ts +let foo: number = 0; +foo += 1; + +let bar = ''; +bar += 'test'; ``` ## When Not To Use It diff --git a/packages/eslint-plugin/package.json b/packages/eslint-plugin/package.json index c928955311e6..64ec32d9f293 100644 --- a/packages/eslint-plugin/package.json +++ b/packages/eslint-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/eslint-plugin", - "version": "5.59.11", + "version": "5.60.0", "description": "TypeScript plugin for ESLint", "keywords": [ "eslint", @@ -45,9 +45,9 @@ }, "dependencies": { "@eslint-community/regexpp": "^4.4.0", - "@typescript-eslint/scope-manager": "5.59.11", - "@typescript-eslint/type-utils": "5.59.11", - "@typescript-eslint/utils": "5.59.11", + "@typescript-eslint/scope-manager": "5.60.0", + "@typescript-eslint/type-utils": "5.60.0", + "@typescript-eslint/utils": "5.60.0", "debug": "^4.3.4", "grapheme-splitter": "^1.0.4", "ignore": "^5.2.0", diff --git a/packages/eslint-plugin/src/rules/restrict-plus-operands.ts b/packages/eslint-plugin/src/rules/restrict-plus-operands.ts index ad5d0a832b75..2170bf44cc7a 100644 --- a/packages/eslint-plugin/src/rules/restrict-plus-operands.ts +++ b/packages/eslint-plugin/src/rules/restrict-plus-operands.ts @@ -1,20 +1,21 @@ import type { TSESTree } from '@typescript-eslint/utils'; +import * as tsutils from 'tsutils'; import * as ts from 'typescript'; import * as util from '../util'; type Options = [ { - checkCompoundAssignments?: boolean; allowAny?: boolean; + allowBoolean?: boolean; + allowNullish?: boolean; + allowNumberAndString?: boolean; + allowRegExp?: boolean; + checkCompoundAssignments?: boolean; }, ]; -type MessageIds = - | 'notNumbers' - | 'notStrings' - | 'notBigInts' - | 'notValidAnys' - | 'notValidTypes'; + +type MessageIds = 'bigintAndNumber' | 'invalid' | 'mismatched'; export default util.createRule({ name: 'restrict-plus-operands', @@ -27,29 +28,44 @@ export default util.createRule({ requiresTypeChecking: true, }, messages: { - notNumbers: - "Operands of '+' operation must either be both strings or both numbers.", - notStrings: - "Operands of '+' operation must either be both strings or both numbers. Consider using a template literal.", - notBigInts: "Operands of '+' operation must be both bigints.", - notValidAnys: - "Operands of '+' operation with any is possible only with string, number, bigint or any", - notValidTypes: - "Operands of '+' operation must either be one of string, number, bigint or any (if allowed by option)", + bigintAndNumber: + "Numeric '+' operations must either be both bigints or both numbers. Got `{{left}}` + `{{right}}`.", + invalid: + "Invalid operand for a '+' operation. Operands must each be a number or {{stringLike}}. Got `{{type}}`.", + mismatched: + "Operands of '+' operations must be a number or {{stringLike}}. Got `{{left}}` + `{{right}}`.", }, schema: [ { type: 'object', additionalProperties: false, properties: { - checkCompoundAssignments: { - description: 'Whether to check compound assignments such as `+=`.', - type: 'boolean', - }, allowAny: { description: 'Whether to allow `any` typed values.', type: 'boolean', }, + allowBoolean: { + description: 'Whether to allow `boolean` typed values.', + type: 'boolean', + }, + allowNullish: { + description: + 'Whether to allow potentially `null` or `undefined` typed values.', + type: 'boolean', + }, + allowNumberAndString: { + description: + 'Whether to allow `bigint`/`number` typed values and `string` typed values to be added together.', + type: 'boolean', + }, + allowRegExp: { + description: 'Whether to allow `regexp` typed values.', + type: 'boolean', + }, + checkCompoundAssignments: { + description: 'Whether to check compound assignments such as `+=`.', + type: 'boolean', + }, }, }, ], @@ -57,136 +73,159 @@ export default util.createRule({ defaultOptions: [ { checkCompoundAssignments: false, - allowAny: false, }, ], - create(context, [{ checkCompoundAssignments, allowAny }]) { + create( + context, + [ + { + checkCompoundAssignments, + allowAny, + allowBoolean, + allowNullish, + allowNumberAndString, + allowRegExp, + }, + ], + ) { const service = util.getParserServices(context); const typeChecker = service.program.getTypeChecker(); - type BaseLiteral = 'string' | 'number' | 'bigint' | 'invalid' | 'any'; - - /** - * Helper function to get base type of node - */ - function getBaseTypeOfLiteralType(type: ts.Type): BaseLiteral { - if (type.isNumberLiteral()) { - return 'number'; - } - if ( - type.isStringLiteral() || - util.isTypeFlagSet(type, ts.TypeFlags.TemplateLiteral) - ) { - return 'string'; - } - // is BigIntLiteral - if (type.flags & ts.TypeFlags.BigIntLiteral) { - return 'bigint'; - } - if (type.isUnion()) { - const types = type.types.map(getBaseTypeOfLiteralType); - - return types.every(value => value === types[0]) ? types[0] : 'invalid'; - } - - if (type.isIntersection()) { - const types = type.types.map(getBaseTypeOfLiteralType); - - if (types.some(value => value === 'string')) { - return 'string'; - } - - if (types.some(value => value === 'number')) { - return 'number'; - } - - if (types.some(value => value === 'bigint')) { - return 'bigint'; - } - - return 'invalid'; - } + const stringLikes = [ + allowAny && '`any`', + allowBoolean && '`boolean`', + allowNullish && '`null`', + allowRegExp && '`RegExp`', + allowNullish && '`undefined`', + ].filter((value): value is string => typeof value === 'string'); + const stringLike = stringLikes.length + ? stringLikes.length === 1 + ? `string, allowing a string + ${stringLikes[0]}` + : `string, allowing a string + any of: ${stringLikes.join(', ')}` + : 'string'; + + function getTypeConstrained(node: TSESTree.Node): ts.Type { + return typeChecker.getBaseTypeOfLiteralType( + util.getConstrainedTypeAtLocation( + typeChecker, + service.esTreeNodeToTSNodeMap.get(node), + ), + ); + } - const stringType = typeChecker.typeToString(type); + function checkPlusOperands( + node: TSESTree.AssignmentExpression | TSESTree.BinaryExpression, + ): void { + const leftType = getTypeConstrained(node.left); + const rightType = getTypeConstrained(node.right); if ( - stringType === 'number' || - stringType === 'string' || - stringType === 'bigint' || - stringType === 'any' + leftType === rightType && + tsutils.isTypeFlagSet( + leftType, + ts.TypeFlags.BigIntLike | + ts.TypeFlags.NumberLike | + ts.TypeFlags.StringLike, + ) ) { - return stringType; + return; } - return 'invalid'; - } - - /** - * Helper function to get base type of node - * @param node the node to be evaluated. - */ - function getNodeType( - node: TSESTree.Expression | TSESTree.PrivateIdentifier, - ): BaseLiteral { - const tsNode = service.esTreeNodeToTSNodeMap.get(node); - const type = util.getConstrainedTypeAtLocation(typeChecker, tsNode); - - return getBaseTypeOfLiteralType(type); - } - function checkPlusOperands( - node: TSESTree.BinaryExpression | TSESTree.AssignmentExpression, - ): void { - const leftType = getNodeType(node.left); - const rightType = getNodeType(node.right); - - if (leftType === rightType) { - if (leftType === 'invalid') { + let hadIndividualComplaint = false; + + for (const [baseNode, baseType, otherType] of [ + [node.left, leftType, rightType], + [node.right, rightType, leftType], + ] as const) { + if ( + isTypeFlagSetInUnion( + baseType, + ts.TypeFlags.ESSymbolLike | + ts.TypeFlags.Never | + ts.TypeFlags.Unknown, + ) || + (!allowAny && isTypeFlagSetInUnion(baseType, ts.TypeFlags.Any)) || + (!allowBoolean && + isTypeFlagSetInUnion(baseType, ts.TypeFlags.BooleanLike)) || + (!allowNullish && + util.isTypeFlagSet( + baseType, + ts.TypeFlags.Null | ts.TypeFlags.Undefined, + )) + ) { context.report({ - node, - messageId: 'notValidTypes', + data: { + stringLike, + type: typeChecker.typeToString(baseType), + }, + messageId: 'invalid', + node: baseNode, }); + hadIndividualComplaint = true; + continue; } - if (!allowAny && leftType === 'any') { - context.report({ - node, - messageId: 'notValidAnys', - }); + // RegExps also contain ts.TypeFlags.Any & ts.TypeFlags.Object + for (const subBaseType of tsutils.unionTypeParts(baseType)) { + const typeName = util.getTypeName(typeChecker, subBaseType); + if ( + typeName === 'RegExp' + ? !allowRegExp || + tsutils.isTypeFlagSet(otherType, ts.TypeFlags.NumberLike) + : (!allowAny && util.isTypeAnyType(subBaseType)) || + isDeeplyObjectType(subBaseType) + ) { + context.report({ + data: { + stringLike, + type: typeChecker.typeToString(subBaseType), + }, + messageId: 'invalid', + node: baseNode, + }); + hadIndividualComplaint = true; + continue; + } } + } + if (hadIndividualComplaint) { return; } - if (leftType === 'any' || rightType === 'any') { - if (!allowAny || leftType === 'invalid' || rightType === 'invalid') { - context.report({ + for (const [baseType, otherType] of [ + [leftType, rightType], + [rightType, leftType], + ] as const) { + if ( + !allowNumberAndString && + isTypeFlagSetInUnion(baseType, ts.TypeFlags.StringLike) && + isTypeFlagSetInUnion(otherType, ts.TypeFlags.NumberLike) + ) { + return context.report({ + data: { + stringLike, + left: typeChecker.typeToString(leftType), + right: typeChecker.typeToString(rightType), + }, + messageId: 'mismatched', node, - messageId: 'notValidAnys', }); } - return; - } - - if (leftType === 'string' || rightType === 'string') { - return context.report({ - node, - messageId: 'notStrings', - }); - } - - if (leftType === 'bigint' || rightType === 'bigint') { - return context.report({ - node, - messageId: 'notBigInts', - }); - } - - if (leftType === 'number' || rightType === 'number') { - return context.report({ - node, - messageId: 'notNumbers', - }); + if ( + isTypeFlagSetInUnion(baseType, ts.TypeFlags.NumberLike) && + isTypeFlagSetInUnion(otherType, ts.TypeFlags.BigIntLike) + ) { + return context.report({ + data: { + left: typeChecker.typeToString(leftType), + right: typeChecker.typeToString(rightType), + }, + messageId: 'bigintAndNumber', + node, + }); + } } } @@ -200,3 +239,15 @@ export default util.createRule({ }; }, }); + +function isDeeplyObjectType(type: ts.Type): boolean { + return type.isIntersection() + ? tsutils.intersectionTypeParts(type).every(tsutils.isObjectType) + : tsutils.unionTypeParts(type).every(tsutils.isObjectType); +} + +function isTypeFlagSetInUnion(type: ts.Type, flag: ts.TypeFlags): boolean { + return tsutils + .unionTypeParts(type) + .some(subType => tsutils.isTypeFlagSet(subType, flag)); +} diff --git a/packages/eslint-plugin/src/rules/restrict-template-expressions.ts b/packages/eslint-plugin/src/rules/restrict-template-expressions.ts index 485ba42378bc..21e638e2f855 100644 --- a/packages/eslint-plugin/src/rules/restrict-template-expressions.ts +++ b/packages/eslint-plugin/src/rules/restrict-template-expressions.ts @@ -6,10 +6,10 @@ import * as util from '../util'; type Options = [ { - allowNumber?: boolean; - allowBoolean?: boolean; allowAny?: boolean; + allowBoolean?: boolean; allowNullish?: boolean; + allowNumber?: boolean; allowRegExp?: boolean; allowNever?: boolean; }, @@ -34,9 +34,9 @@ export default util.createRule({ { type: 'object', properties: { - allowNumber: { + allowAny: { description: - 'Whether to allow `number` typed values in template expressions.', + 'Whether to allow `any` typed values in template expressions.', type: 'boolean', }, allowBoolean: { @@ -44,14 +44,14 @@ export default util.createRule({ 'Whether to allow `boolean` typed values in template expressions.', type: 'boolean', }, - allowAny: { + allowNullish: { description: - 'Whether to allow `any` typed values in template expressions.', + 'Whether to allow `nullish` typed values in template expressions.', type: 'boolean', }, - allowNullish: { + allowNumber: { description: - 'Whether to allow `nullish` typed values in template expressions.', + 'Whether to allow `number` typed values in template expressions.', type: 'boolean', }, allowRegExp: { diff --git a/packages/eslint-plugin/tests/rules/restrict-plus-operands.test.ts b/packages/eslint-plugin/tests/rules/restrict-plus-operands.test.ts index 59215883758e..4d9aa64deaaf 100644 --- a/packages/eslint-plugin/tests/rules/restrict-plus-operands.test.ts +++ b/packages/eslint-plugin/tests/rules/restrict-plus-operands.test.ts @@ -13,53 +13,53 @@ const ruleTester = new RuleTester({ ruleTester.run('restrict-plus-operands', rule, { valid: [ - 'var x = 5;', - "var y = '10';", - 'var z = 8.2;', - "var w = '6.5';", - 'var foo = 5 + 10;', - "var foo = '5.5' + '10';", - "var foo = parseInt('5.5', 10) + 10;", - "var foo = parseFloat('5.5', 10) + 10;", - 'var foo = 1n + 1n;', - 'var foo = BigInt(1) + 1n;', + 'let x = 5;', + "let y = '10';", + 'let z = 8.2;', + "let w = '6.5';", + 'let foo = 5 + 10;', + "let foo = '5.5' + '10';", + "let foo = parseInt('5.5', 10) + 10;", + "let foo = parseFloat('5.5', 10) + 10;", + 'let foo = 1n + 1n;', + 'let foo = BigInt(1) + 1n;', ` - var foo = 1n; + let foo = 1n; foo + 2n; `, ` function test(s: string, n: number): number { return 2; } -var foo = test('5.5', 10) + 10; +let foo = test('5.5', 10) + 10; `, ` -var x = 5; -var z = 8.2; -var foo = x + z; +let x = 5; +let z = 8.2; +let foo = x + z; `, ` -var w = '6.5'; -var y = '10'; -var foo = y + w; +let w = '6.5'; +let y = '10'; +let foo = y + w; `, - 'var foo = 1 + 1;', - "var foo = '1' + '1';", + 'let foo = 1 + 1;', + "let foo = '1' + '1';", ` -var pair: { first: number; second: string } = { first: 5, second: '10' }; -var foo = pair.first + 10; +let pair: { first: number; second: string } = { first: 5, second: '10' }; +let foo = pair.first + 10; `, ` -var pair: { first: number; second: string } = { first: 5, second: '10' }; -var foo = pair.first + (10 as number); +let pair: { first: number; second: string } = { first: 5, second: '10' }; +let foo = pair.first + (10 as number); `, ` -var pair: { first: number; second: string } = { first: 5, second: '10' }; -var foo = '5.5' + pair.second; +let pair: { first: number; second: string } = { first: 5, second: '10' }; +let foo = '5.5' + pair.second; `, ` -var pair: { first: number; second: string } = { first: 5, second: '10' }; -var foo = ('5.5' as string) + pair.second; +let pair: { first: number; second: string } = { first: 5, second: '10' }; +let foo = ('5.5' as string) + pair.second; `, ` const foo = @@ -157,6 +157,84 @@ function A(s: string) { } const b = A('') + '!'; `, + ` +declare const a: \`template\${string}\`; +declare const b: ''; +const x = a + b; + `, + ` +const a: \`template\${0}\`; +declare const b: ''; +const x = a + b; + `, + { + code: ` + declare const a: RegExp; + declare const b: string; + const x = a + b; + `, + options: [ + { + allowRegExp: true, + }, + ], + }, + { + code: ` + const a = /regexp/; + declare const b: string; + const x = a + b; + `, + options: [ + { + allowRegExp: true, + }, + ], + }, + // TypeScript handles this case, so we don't have to + { + code: ` +const f = (a: RegExp, b: RegExp) => a + b; + `, + options: [ + { + allowRegExp: true, + }, + ], + }, + { + code: ` +let foo: string | undefined; +foo = foo + 'some data'; + `, + options: [ + { + allowNullish: true, + }, + ], + }, + { + code: ` +let foo: string | null; +foo = foo + 'some data'; + `, + options: [ + { + allowNullish: true, + }, + ], + }, + { + code: ` +let foo: string | null | undefined; +foo = foo + 'some data'; + `, + options: [ + { + allowNullish: true, + }, + ], + }, { code: ` let foo: number = 0; @@ -181,7 +259,7 @@ foo += 'string'; }, { code: ` -export const f = (a: any, b: any) => a + b; +const f = (a: any, b: any) => a + b; `, options: [ { @@ -191,7 +269,7 @@ export const f = (a: any, b: any) => a + b; }, { code: ` -export const f = (a: any, b: string) => a + b; +const f = (a: any, b: string) => a + b; `, options: [ { @@ -201,7 +279,7 @@ export const f = (a: any, b: string) => a + b; }, { code: ` -export const f = (a: any, b: bigint) => a + b; +const f = (a: any, b: bigint) => a + b; `, options: [ { @@ -211,7 +289,7 @@ export const f = (a: any, b: bigint) => a + b; }, { code: ` -export const f = (a: any, b: number) => a + b; +const f = (a: any, b: number) => a + b; `, options: [ { @@ -219,121 +297,230 @@ export const f = (a: any, b: number) => a + b; }, ], }, - ], - invalid: [ { - code: "var foo = '1' + 1;", - errors: [ + code: ` +const f = (a: any, b: boolean) => a + b; + `, + options: [ { - messageId: 'notStrings', - line: 1, - column: 11, + allowAny: true, + allowBoolean: true, }, ], }, { - code: 'var foo = [] + {};', + code: ` +const f = (a: string, b: string | number) => a + b; + `, + options: [ + { + allowAny: true, + allowBoolean: true, + allowNullish: true, + allowNumberAndString: true, + allowRegExp: true, + }, + ], + }, + { + code: ` +const f = (a: string | number, b: number) => a + b; + `, + options: [ + { + allowAny: true, + allowBoolean: true, + allowNullish: true, + allowNumberAndString: true, + allowRegExp: true, + }, + ], + }, + { + code: ` +const f = (a: string | number, b: string | number) => a + b; + `, + options: [ + { + allowAny: true, + allowBoolean: true, + allowNullish: true, + allowNumberAndString: true, + allowRegExp: true, + }, + ], + }, + ], + invalid: [ + { + code: "let foo = '1' + 1;", errors: [ { - messageId: 'notValidTypes', + data: { + left: 'string', + right: 'number', + stringLike: 'string', + }, + messageId: 'mismatched', line: 1, column: 11, }, ], }, { - code: "var foo = 5 + '10';", + code: 'let foo = [] + {};', errors: [ { - messageId: 'notStrings', - line: 1, + data: { + stringLike: 'string', + type: 'never[]', + }, column: 11, + endColumn: 13, + line: 1, + messageId: 'invalid', + }, + { + data: { + stringLike: 'string', + type: '{}', + }, + column: 16, + endColumn: 18, + line: 1, + messageId: 'invalid', }, ], }, { - code: 'var foo = [] + 5;', + code: "let foo = 5 + '10';", errors: [ { - messageId: 'notNumbers', + data: { + left: 'number', + right: 'string', + stringLike: 'string', + }, + messageId: 'mismatched', line: 1, column: 11, }, ], }, { - code: 'var foo = [] + [];', + code: 'let foo = [] + 5;', errors: [ { - messageId: 'notValidTypes', + data: { + stringLike: 'string', + type: 'never[]', + }, + messageId: 'invalid', line: 1, column: 11, + endColumn: 13, }, ], }, { - code: 'var foo = 5 + [];', + code: 'let foo = [] + [];', errors: [ { - messageId: 'notNumbers', + data: { + stringLike: 'string', + type: 'never[]', + }, + messageId: 'invalid', line: 1, + endColumn: 13, column: 11, }, + { + data: { + stringLike: 'string', + type: 'never[]', + }, + messageId: 'invalid', + line: 1, + endColumn: 18, + column: 16, + }, ], }, { - code: "var foo = '5' + {};", + code: 'let foo = 5 + [3];', errors: [ { - messageId: 'notStrings', + data: { + stringLike: 'string', + type: 'number[]', + }, + column: 15, + endColumn: 18, line: 1, - column: 11, + messageId: 'invalid', }, ], }, { - code: "var foo = 5.5 + '5';", + code: "let foo = '5' + {};", errors: [ { - messageId: 'notStrings', + data: { + stringLike: 'string', + type: '{}', + }, + messageId: 'invalid', line: 1, - column: 11, + endColumn: 19, + column: 17, }, ], }, { - code: "var foo = '5.5' + 5;", + code: "let foo = 5.5 + '5';", errors: [ { - messageId: 'notStrings', + data: { + left: 'number', + right: 'string', + stringLike: 'string', + }, + messageId: 'mismatched', line: 1, column: 11, }, ], }, { - code: ` -var x = 5; -var y = '10'; -var foo = x + y; - `, + code: "let foo = '5.5' + 5;", errors: [ { - messageId: 'notStrings', - line: 4, + data: { + left: 'string', + right: 'number', + stringLike: 'string', + }, + messageId: 'mismatched', + line: 1, column: 11, }, ], }, { code: ` -var x = 5; -var y = '10'; -var foo = y + x; +let x = 5; +let y = '10'; +let foo = x + y; `, errors: [ { - messageId: 'notStrings', + data: { + left: 'number', + right: 'string', + stringLike: 'string', + }, + messageId: 'mismatched', line: 4, column: 11, }, @@ -341,38 +528,52 @@ var foo = y + x; }, { code: ` -var x = 5; -var foo = x + {}; +let x = 5; +let y = '10'; +let foo = y + x; `, errors: [ { - messageId: 'notNumbers', - line: 3, + data: { + right: 'number', + left: 'string', + stringLike: 'string', + }, + messageId: 'mismatched', + line: 4, column: 11, }, ], }, { code: ` -var y = '10'; -var foo = [] + y; +let x = 5; +let foo = x + {}; `, errors: [ { - messageId: 'notStrings', + data: { + stringLike: 'string', + type: '{}', + }, + messageId: 'invalid', line: 3, - column: 11, + column: 15, }, ], }, { code: ` -var pair: { first: number; second: string } = { first: 5, second: '10' }; -var foo = pair.first + '10'; +let y = '10'; +let foo = [] + y; `, errors: [ { - messageId: 'notStrings', + data: { + stringLike: 'string', + type: 'never[]', + }, + messageId: 'invalid', line: 3, column: 11, }, @@ -380,55 +581,74 @@ var foo = pair.first + '10'; }, { code: ` -var pair: { first: number; second: string } = { first: 5, second: '10' }; -var foo = 5 + pair.second; +let pair = { first: 5, second: '10' }; +let foo = pair + pair; `, errors: [ { - messageId: 'notStrings', - line: 3, + data: { + stringLike: 'string', + type: '{ first: number; second: string; }', + }, column: 11, + endColumn: 15, + line: 3, + messageId: 'invalid', }, - ], - }, - { - code: "var foo = parseInt('5.5', 10) + '10';", - errors: [ { - messageId: 'notStrings', - line: 1, - column: 11, + data: { + stringLike: 'string', + type: '{ first: number; second: string; }', + }, + column: 18, + endColumn: 22, + line: 3, + messageId: 'invalid', }, ], }, { code: ` -var pair = { first: 5, second: '10' }; -var foo = pair + pair; +type Valued = { value: number }; +let value: Valued = { value: 0 }; +let combined = value + 0; `, errors: [ { - messageId: 'notValidTypes', - line: 3, - column: 11, + data: { + stringLike: 'string', + type: 'Valued', + }, + column: 16, + endColumn: 21, + line: 4, + messageId: 'invalid', }, ], }, { - code: 'var foo = 1n + 1;', + code: 'let foo = 1n + 1;', errors: [ { - messageId: 'notBigInts', + data: { + left: 'bigint', + right: 'number', + }, + messageId: 'bigintAndNumber', line: 1, column: 11, }, ], }, { - code: 'var foo = 1 + 1n;', + code: 'let foo = 1 + 1n;', errors: [ { - messageId: 'notBigInts', + data: { + left: 'number', + right: 'bigint', + }, + messageId: 'bigintAndNumber', line: 1, column: 11, }, @@ -436,12 +656,16 @@ var foo = pair + pair; }, { code: ` - var foo = 1n; + let foo = 1n; foo + 1; `, errors: [ { - messageId: 'notBigInts', + data: { + left: 'bigint', + right: 'number', + }, + messageId: 'bigintAndNumber', line: 3, column: 9, }, @@ -449,12 +673,16 @@ var foo = pair + pair; }, { code: ` - var foo = 1; + let foo = 1; foo + 1n; `, errors: [ { - messageId: 'notBigInts', + data: { + left: 'number', + right: 'bigint', + }, + messageId: 'bigintAndNumber', line: 3, column: 9, }, @@ -469,7 +697,12 @@ function foo(a: T) { `, errors: [ { - messageId: 'notStrings', + data: { + left: 'string', + right: 'number', + stringLike: 'string', + }, + messageId: 'mismatched', line: 3, column: 10, }, @@ -483,7 +716,12 @@ function foo(a: T) { `, errors: [ { - messageId: 'notStrings', + data: { + left: 'string', + right: 'number', + stringLike: 'string', + }, + messageId: 'mismatched', line: 3, column: 10, }, @@ -497,7 +735,12 @@ function foo(a: T) { `, errors: [ { - messageId: 'notStrings', + data: { + left: 'number', + right: 'string', + stringLike: 'string', + }, + messageId: 'mismatched', line: 3, column: 10, }, @@ -511,7 +754,12 @@ function foo(a: T) { `, errors: [ { - messageId: 'notStrings', + data: { + left: 'number', + right: 'string', + stringLike: 'string', + }, + messageId: 'mismatched', line: 3, column: 10, }, @@ -519,13 +767,18 @@ function foo(a: T) { }, { code: ` - declare const a: boolean & string; - declare const b: string; + declare const a: \`template\${number}\`; + declare const b: number; const x = a + b; `, errors: [ { - messageId: 'notStrings', + data: { + left: 'string', + right: 'number', + stringLike: 'string', + }, + messageId: 'mismatched', line: 4, column: 19, }, @@ -533,13 +786,17 @@ function foo(a: T) { }, { code: ` - declare const a: number & string; + declare const a: never; declare const b: string; const x = a + b; `, errors: [ { - messageId: 'notStrings', + data: { + stringLike: 'string', + type: 'never', + }, + messageId: 'invalid', line: 4, column: 19, }, @@ -547,13 +804,17 @@ function foo(a: T) { }, { code: ` - declare const a: symbol & string; + declare const a: never & string; declare const b: string; const x = a + b; `, errors: [ { - messageId: 'notStrings', + data: { + stringLike: 'string', + type: 'never', + }, + messageId: 'invalid', line: 4, column: 19, }, @@ -561,13 +822,17 @@ function foo(a: T) { }, { code: ` - declare const a: object & string; + declare const a: boolean & string; declare const b: string; const x = a + b; `, errors: [ { - messageId: 'notStrings', + data: { + stringLike: 'string', + type: 'never', + }, + messageId: 'invalid', line: 4, column: 19, }, @@ -575,13 +840,17 @@ function foo(a: T) { }, { code: ` - declare const a: never & string; + declare const a: any & string; declare const b: string; const x = a + b; `, errors: [ { - messageId: 'notStrings', + data: { + stringLike: 'string', + type: 'any', + }, + messageId: 'invalid', line: 4, column: 19, }, @@ -589,13 +858,17 @@ function foo(a: T) { }, { code: ` - declare const a: any & string; + declare const a: { a: 1 } & { b: 2 }; declare const b: string; const x = a + b; `, errors: [ { - messageId: 'notValidAnys', + data: { + stringLike: 'string', + type: '{ a: 1; } & { b: 2; }', + }, + messageId: 'invalid', line: 4, column: 19, }, @@ -603,55 +876,81 @@ function foo(a: T) { }, { code: ` - declare const a: { a: 1 } & { b: 2 }; + interface A { + a: 1; + } + declare const a: A; declare const b: string; const x = a + b; `, errors: [ { - messageId: 'notStrings', - line: 4, + data: { + stringLike: 'string', + type: 'A', + }, + messageId: 'invalid', + line: 7, column: 19, }, ], }, { code: ` - declare const a: boolean & number; - declare const b: number; + interface A { + a: 1; + } + interface A2 extends A { + b: 2; + } + declare const a: A2; + declare const b: string; const x = a + b; `, errors: [ { - messageId: 'notNumbers', - line: 4, + data: { + stringLike: 'string', + type: 'A2', + }, + messageId: 'invalid', + line: 10, column: 19, }, ], }, { code: ` - declare const a: symbol & number; - declare const b: number; + type A = { a: 1 } & { b: 2 }; + declare const a: A; + declare const b: string; const x = a + b; `, errors: [ { - messageId: 'notNumbers', - line: 4, + data: { + stringLike: 'string', + type: 'A', + }, + messageId: 'invalid', + line: 5, column: 19, }, ], }, { code: ` - declare const a: object & number; + declare const a: { a: 1 } & { b: 2 }; declare const b: number; const x = a + b; `, errors: [ { - messageId: 'notNumbers', + data: { + stringLike: 'string', + type: '{ a: 1; } & { b: 2; }', + }, + messageId: 'invalid', line: 4, column: 19, }, @@ -659,13 +958,17 @@ function foo(a: T) { }, { code: ` - declare const a: never & number; - declare const b: number; + declare const a: never; + declare const b: bigint; const x = a + b; `, errors: [ { - messageId: 'notNumbers', + data: { + stringLike: 'string', + type: 'never', + }, + messageId: 'invalid', line: 4, column: 19, }, @@ -673,13 +976,17 @@ function foo(a: T) { }, { code: ` - declare const a: any & number; - declare const b: number; + declare const a: any; + declare const b: bigint; const x = a + b; `, errors: [ { - messageId: 'notValidAnys', + data: { + stringLike: 'string', + type: 'any', + }, + messageId: 'invalid', line: 4, column: 19, }, @@ -688,12 +995,16 @@ function foo(a: T) { { code: ` declare const a: { a: 1 } & { b: 2 }; - declare const b: number; + declare const b: bigint; const x = a + b; `, errors: [ { - messageId: 'notNumbers', + data: { + stringLike: 'string', + type: '{ a: 1; } & { b: 2; }', + }, + messageId: 'invalid', line: 4, column: 19, }, @@ -701,13 +1012,17 @@ function foo(a: T) { }, { code: ` - declare const a: boolean & bigint; - declare const b: bigint; + declare const a: RegExp; + declare const b: string; const x = a + b; `, errors: [ { - messageId: 'notBigInts', + data: { + stringLike: 'string', + type: 'RegExp', + }, + messageId: 'invalid', line: 4, column: 19, }, @@ -715,13 +1030,17 @@ function foo(a: T) { }, { code: ` - declare const a: number & bigint; - declare const b: bigint; + const a = /regexp/; + declare const b: string; const x = a + b; `, errors: [ { - messageId: 'notBigInts', + data: { + stringLike: 'string', + type: 'RegExp', + }, + messageId: 'invalid', line: 4, column: 19, }, @@ -729,13 +1048,17 @@ function foo(a: T) { }, { code: ` - declare const a: symbol & bigint; - declare const b: bigint; + declare const a: Symbol; + declare const b: string; const x = a + b; `, errors: [ { - messageId: 'notBigInts', + data: { + stringLike: 'string', + type: 'Symbol', + }, + messageId: 'invalid', line: 4, column: 19, }, @@ -743,13 +1066,17 @@ function foo(a: T) { }, { code: ` - declare const a: object & bigint; - declare const b: bigint; + declare const a: symbol; + declare const b: string; const x = a + b; `, errors: [ { - messageId: 'notBigInts', + data: { + stringLike: 'string', + type: 'symbol', + }, + messageId: 'invalid', line: 4, column: 19, }, @@ -757,13 +1084,17 @@ function foo(a: T) { }, { code: ` - declare const a: never & bigint; - declare const b: bigint; + declare const a: unique symbol; + declare const b: string; const x = a + b; `, errors: [ { - messageId: 'notBigInts', + data: { + stringLike: 'string', + type: 'unique symbol', + }, + messageId: 'invalid', line: 4, column: 19, }, @@ -771,13 +1102,17 @@ function foo(a: T) { }, { code: ` - declare const a: any & bigint; - declare const b: bigint; + const a = Symbol(''); + declare const b: string; const x = a + b; `, errors: [ { - messageId: 'notValidAnys', + data: { + stringLike: 'string', + type: 'unique symbol', + }, + messageId: 'invalid', line: 4, column: 19, }, @@ -785,21 +1120,29 @@ function foo(a: T) { }, { code: ` - declare const a: { a: 1 } & { b: 2 }; - declare const b: bigint; - const x = a + b; +let foo: string | undefined; +foo += 'some data'; `, + options: [ + { + checkCompoundAssignments: true, + }, + ], errors: [ { - messageId: 'notBigInts', - line: 4, - column: 19, + data: { + stringLike: 'string', + type: 'string | undefined', + }, + messageId: 'invalid', + line: 3, + column: 1, }, ], }, { code: ` -let foo: string | undefined; +let foo: string | null; foo += 'some data'; `, options: [ @@ -809,7 +1152,11 @@ foo += 'some data'; ], errors: [ { - messageId: 'notStrings', + data: { + stringLike: 'string', + type: 'string | null', + }, + messageId: 'invalid', line: 3, column: 1, }, @@ -827,7 +1174,12 @@ foo += 0; ], errors: [ { - messageId: 'notStrings', + data: { + left: 'string', + right: 'number', + stringLike: 'string', + }, + messageId: 'mismatched', line: 3, column: 1, }, @@ -844,9 +1196,9 @@ const f = (a: any, b: boolean) => a + b; ], errors: [ { - messageId: 'notValidAnys', + messageId: 'invalid', line: 2, - column: 35, + column: 39, }, ], }, @@ -861,13 +1213,37 @@ const f = (a: any, b: []) => a + b; ], errors: [ { - messageId: 'notValidAnys', + data: { + stringLike: 'string, allowing a string + `any`', + type: '[]', + }, + messageId: 'invalid', line: 2, - column: 30, + column: 34, + }, + ], + }, + { + code: ` +const f = (a: any, b: boolean) => a + b; + `, + options: [ + { + allowBoolean: true, + }, + ], + errors: [ + { + data: { + stringLike: 'string, allowing a string + `boolean`', + type: 'any', + }, + messageId: 'invalid', + line: 2, + column: 35, }, ], }, - { code: ` const f = (a: any, b: any) => a + b; @@ -879,10 +1255,15 @@ const f = (a: any, b: any) => a + b; ], errors: [ { - messageId: 'notValidAnys', + messageId: 'invalid', line: 2, column: 31, }, + { + messageId: 'invalid', + line: 2, + column: 35, + }, ], }, { @@ -896,7 +1277,7 @@ const f = (a: any, b: string) => a + b; ], errors: [ { - messageId: 'notValidAnys', + messageId: 'invalid', line: 2, column: 34, }, @@ -913,7 +1294,7 @@ const f = (a: any, b: bigint) => a + b; ], errors: [ { - messageId: 'notValidAnys', + messageId: 'invalid', line: 2, column: 34, }, @@ -930,7 +1311,7 @@ const f = (a: any, b: number) => a + b; ], errors: [ { - messageId: 'notValidAnys', + messageId: 'invalid', line: 2, column: 34, }, @@ -940,16 +1321,109 @@ const f = (a: any, b: number) => a + b; code: ` const f = (a: any, b: boolean) => a + b; `, + errors: [ + { + messageId: 'invalid', + line: 2, + column: 35, + }, + { + messageId: 'invalid', + line: 2, + column: 39, + }, + ], options: [ { allowAny: false, }, ], + }, + { + code: ` +const f = (a: number, b: RegExp) => a + b; + `, errors: [ { - messageId: 'notValidAnys', + messageId: 'invalid', line: 2, - column: 35, + column: 41, + }, + ], + options: [ + { + allowRegExp: true, + }, + ], + }, + { + code: ` +let foo: string | boolean; +foo = foo + 'some data'; + `, + errors: [ + { + data: { + stringLike: + 'string, allowing a string + any of: `null`, `undefined`', + type: 'string | boolean', + }, + messageId: 'invalid', + line: 3, + column: 7, + }, + ], + options: [ + { + allowNullish: true, + }, + ], + }, + { + code: ` +let foo: boolean; +foo = foo + 'some data'; + `, + errors: [ + { + data: { + stringLike: + 'string, allowing a string + any of: `null`, `undefined`', + type: 'boolean', + }, + messageId: 'invalid', + line: 3, + column: 7, + }, + ], + options: [ + { + allowNullish: true, + }, + ], + }, + { + code: ` +const f = (a: any, b: unknown) => a + b; + `, + options: [ + { + allowAny: true, + allowBoolean: true, + allowNullish: true, + allowRegExp: true, + }, + ], + errors: [ + { + data: { + stringLike: + 'string, allowing a string + any of: `any`, `boolean`, `null`, `RegExp`, `undefined`', + type: 'unknown', + }, + messageId: 'invalid', + line: 2, + column: 39, }, ], }, diff --git a/packages/experimental-utils/CHANGELOG.md b/packages/experimental-utils/CHANGELOG.md index c1c89e9104bf..3ff2a1b22a14 100644 --- a/packages/experimental-utils/CHANGELOG.md +++ b/packages/experimental-utils/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.60.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.59.11...v5.60.0) (2023-06-19) + +**Note:** Version bump only for package @typescript-eslint/experimental-utils + + + + + ## [5.59.11](https://github.com/typescript-eslint/typescript-eslint/compare/v5.59.10...v5.59.11) (2023-06-12) **Note:** Version bump only for package @typescript-eslint/experimental-utils diff --git a/packages/experimental-utils/package.json b/packages/experimental-utils/package.json index 1772fd5eab42..a6e176ad7a0d 100644 --- a/packages/experimental-utils/package.json +++ b/packages/experimental-utils/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/experimental-utils", - "version": "5.59.11", + "version": "5.60.0", "description": "(Experimental) Utilities for working with TypeScript + ESLint together", "keywords": [ "eslint", @@ -38,7 +38,7 @@ "typecheck": "tsc -p tsconfig.json --noEmit" }, "dependencies": { - "@typescript-eslint/utils": "5.59.11" + "@typescript-eslint/utils": "5.60.0" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" diff --git a/packages/parser/CHANGELOG.md b/packages/parser/CHANGELOG.md index 40928c21778a..e2259b9efe4a 100644 --- a/packages/parser/CHANGELOG.md +++ b/packages/parser/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.60.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.59.11...v5.60.0) (2023-06-19) + +**Note:** Version bump only for package @typescript-eslint/parser + + + + + ## [5.59.11](https://github.com/typescript-eslint/typescript-eslint/compare/v5.59.10...v5.59.11) (2023-06-12) **Note:** Version bump only for package @typescript-eslint/parser diff --git a/packages/parser/package.json b/packages/parser/package.json index b7d1c2bfc674..6aacace216ae 100644 --- a/packages/parser/package.json +++ b/packages/parser/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/parser", - "version": "5.59.11", + "version": "5.60.0", "description": "An ESLint custom parser which leverages TypeScript ESTree", "main": "dist/index.js", "types": "dist/index.d.ts", @@ -45,9 +45,9 @@ "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" }, "dependencies": { - "@typescript-eslint/scope-manager": "5.59.11", - "@typescript-eslint/types": "5.59.11", - "@typescript-eslint/typescript-estree": "5.59.11", + "@typescript-eslint/scope-manager": "5.60.0", + "@typescript-eslint/types": "5.60.0", + "@typescript-eslint/typescript-estree": "5.60.0", "debug": "^4.3.4" }, "devDependencies": { diff --git a/packages/scope-manager/CHANGELOG.md b/packages/scope-manager/CHANGELOG.md index fd4c5c599b24..95e9495ebaeb 100644 --- a/packages/scope-manager/CHANGELOG.md +++ b/packages/scope-manager/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.60.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.59.11...v5.60.0) (2023-06-19) + +**Note:** Version bump only for package @typescript-eslint/scope-manager + + + + + ## [5.59.11](https://github.com/typescript-eslint/typescript-eslint/compare/v5.59.10...v5.59.11) (2023-06-12) **Note:** Version bump only for package @typescript-eslint/scope-manager diff --git a/packages/scope-manager/package.json b/packages/scope-manager/package.json index d2faa6b95f97..b7dcb8fb7c62 100644 --- a/packages/scope-manager/package.json +++ b/packages/scope-manager/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/scope-manager", - "version": "5.59.11", + "version": "5.60.0", "description": "TypeScript scope analyser for ESLint", "keywords": [ "eslint", @@ -38,12 +38,12 @@ "typecheck": "nx typecheck" }, "dependencies": { - "@typescript-eslint/types": "5.59.11", - "@typescript-eslint/visitor-keys": "5.59.11" + "@typescript-eslint/types": "5.60.0", + "@typescript-eslint/visitor-keys": "5.60.0" }, "devDependencies": { "@types/glob": "*", - "@typescript-eslint/typescript-estree": "5.59.11", + "@typescript-eslint/typescript-estree": "5.60.0", "glob": "*", "jest-specific-snapshot": "*", "make-dir": "*", diff --git a/packages/type-utils/CHANGELOG.md b/packages/type-utils/CHANGELOG.md index 5b8f864b60fd..0103b014dcc9 100644 --- a/packages/type-utils/CHANGELOG.md +++ b/packages/type-utils/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.60.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.59.11...v5.60.0) (2023-06-19) + +**Note:** Version bump only for package @typescript-eslint/type-utils + + + + + ## [5.59.11](https://github.com/typescript-eslint/typescript-eslint/compare/v5.59.10...v5.59.11) (2023-06-12) **Note:** Version bump only for package @typescript-eslint/type-utils diff --git a/packages/type-utils/package.json b/packages/type-utils/package.json index 0bdcb91914b2..19aaa3129278 100644 --- a/packages/type-utils/package.json +++ b/packages/type-utils/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/type-utils", - "version": "5.59.11", + "version": "5.60.0", "description": "Type utilities for working with TypeScript + ESLint together", "keywords": [ "eslint", @@ -39,13 +39,13 @@ "typecheck": "tsc -p tsconfig.json --noEmit" }, "dependencies": { - "@typescript-eslint/typescript-estree": "5.59.11", - "@typescript-eslint/utils": "5.59.11", + "@typescript-eslint/typescript-estree": "5.60.0", + "@typescript-eslint/utils": "5.60.0", "debug": "^4.3.4", "tsutils": "^3.21.0" }, "devDependencies": { - "@typescript-eslint/parser": "5.59.11", + "@typescript-eslint/parser": "5.60.0", "typescript": "*" }, "peerDependencies": { diff --git a/packages/types/CHANGELOG.md b/packages/types/CHANGELOG.md index 93542a0df77a..af82608147ec 100644 --- a/packages/types/CHANGELOG.md +++ b/packages/types/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.60.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.59.11...v5.60.0) (2023-06-19) + +**Note:** Version bump only for package @typescript-eslint/types + + + + + ## [5.59.11](https://github.com/typescript-eslint/typescript-eslint/compare/v5.59.10...v5.59.11) (2023-06-12) **Note:** Version bump only for package @typescript-eslint/types diff --git a/packages/types/package.json b/packages/types/package.json index 615ae3bf03a1..c1ab995888e9 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/types", - "version": "5.59.11", + "version": "5.60.0", "description": "Types for the TypeScript-ESTree AST spec", "keywords": [ "eslint", diff --git a/packages/typescript-estree/CHANGELOG.md b/packages/typescript-estree/CHANGELOG.md index 786d3f7f48fe..4272d156ee43 100644 --- a/packages/typescript-estree/CHANGELOG.md +++ b/packages/typescript-estree/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.60.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.59.11...v5.60.0) (2023-06-19) + +**Note:** Version bump only for package @typescript-eslint/typescript-estree + + + + + ## [5.59.11](https://github.com/typescript-eslint/typescript-eslint/compare/v5.59.10...v5.59.11) (2023-06-12) **Note:** Version bump only for package @typescript-eslint/typescript-estree diff --git a/packages/typescript-estree/package.json b/packages/typescript-estree/package.json index 13484bcb19e6..b9ceac7e4312 100644 --- a/packages/typescript-estree/package.json +++ b/packages/typescript-estree/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/typescript-estree", - "version": "5.59.11", + "version": "5.60.0", "description": "A parser that converts TypeScript source code into an ESTree compatible form", "main": "dist/index.js", "types": "dist/index.d.ts", @@ -42,8 +42,8 @@ "typecheck": "tsc -p tsconfig.json --noEmit" }, "dependencies": { - "@typescript-eslint/types": "5.59.11", - "@typescript-eslint/visitor-keys": "5.59.11", + "@typescript-eslint/types": "5.60.0", + "@typescript-eslint/visitor-keys": "5.60.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", diff --git a/packages/utils/CHANGELOG.md b/packages/utils/CHANGELOG.md index 96f2dd2e0f83..31b4f80488db 100644 --- a/packages/utils/CHANGELOG.md +++ b/packages/utils/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.60.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.59.11...v5.60.0) (2023-06-19) + +**Note:** Version bump only for package @typescript-eslint/utils + + + + + ## [5.59.11](https://github.com/typescript-eslint/typescript-eslint/compare/v5.59.10...v5.59.11) (2023-06-12) **Note:** Version bump only for package @typescript-eslint/utils diff --git a/packages/utils/package.json b/packages/utils/package.json index b625f9f75205..2f211a43a2f6 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/utils", - "version": "5.59.11", + "version": "5.60.0", "description": "Utilities for working with TypeScript + ESLint together", "keywords": [ "eslint", @@ -42,9 +42,9 @@ "@eslint-community/eslint-utils": "^4.2.0", "@types/json-schema": "^7.0.9", "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.59.11", - "@typescript-eslint/types": "5.59.11", - "@typescript-eslint/typescript-estree": "5.59.11", + "@typescript-eslint/scope-manager": "5.60.0", + "@typescript-eslint/types": "5.60.0", + "@typescript-eslint/typescript-estree": "5.60.0", "eslint-scope": "^5.1.1", "semver": "^7.3.7" }, @@ -52,7 +52,7 @@ "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" }, "devDependencies": { - "@typescript-eslint/parser": "5.59.11", + "@typescript-eslint/parser": "5.60.0", "typescript": "*" }, "funding": { diff --git a/packages/visitor-keys/CHANGELOG.md b/packages/visitor-keys/CHANGELOG.md index 0e138d273269..6b0cfe90b2ed 100644 --- a/packages/visitor-keys/CHANGELOG.md +++ b/packages/visitor-keys/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.60.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.59.11...v5.60.0) (2023-06-19) + +**Note:** Version bump only for package @typescript-eslint/visitor-keys + + + + + ## [5.59.11](https://github.com/typescript-eslint/typescript-eslint/compare/v5.59.10...v5.59.11) (2023-06-12) **Note:** Version bump only for package @typescript-eslint/visitor-keys diff --git a/packages/visitor-keys/package.json b/packages/visitor-keys/package.json index e44ee083c208..37e81c5630d5 100644 --- a/packages/visitor-keys/package.json +++ b/packages/visitor-keys/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/visitor-keys", - "version": "5.59.11", + "version": "5.60.0", "description": "Visitor keys used to help traverse the TypeScript-ESTree AST", "keywords": [ "eslint", @@ -39,7 +39,7 @@ "typecheck": "tsc -p tsconfig.json --noEmit" }, "dependencies": { - "@typescript-eslint/types": "5.59.11", + "@typescript-eslint/types": "5.60.0", "eslint-visitor-keys": "^3.3.0" }, "devDependencies": { diff --git a/packages/website-eslint/CHANGELOG.md b/packages/website-eslint/CHANGELOG.md index 53fa4da54a75..7df930eb1342 100644 --- a/packages/website-eslint/CHANGELOG.md +++ b/packages/website-eslint/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.60.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.59.11...v5.60.0) (2023-06-19) + +**Note:** Version bump only for package @typescript-eslint/website-eslint + + + + + ## [5.59.11](https://github.com/typescript-eslint/typescript-eslint/compare/v5.59.10...v5.59.11) (2023-06-12) **Note:** Version bump only for package @typescript-eslint/website-eslint diff --git a/packages/website-eslint/package.json b/packages/website-eslint/package.json index 60755a3ad2aa..bbe102b75986 100644 --- a/packages/website-eslint/package.json +++ b/packages/website-eslint/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/website-eslint", - "version": "5.59.11", + "version": "5.60.0", "private": true, "description": "ESLint which works in browsers.", "engines": { @@ -16,8 +16,8 @@ "format": "prettier --write \"./**/*.{ts,mts,cts,tsx,js,mjs,cjs,jsx,json,md,css}\" --ignore-path ../../.prettierignore" }, "dependencies": { - "@typescript-eslint/types": "5.59.11", - "@typescript-eslint/utils": "5.59.11" + "@typescript-eslint/types": "5.60.0", + "@typescript-eslint/utils": "5.60.0" }, "devDependencies": { "@rollup/plugin-commonjs": "^23.0.0", @@ -25,11 +25,11 @@ "@rollup/plugin-node-resolve": "^15.0.0", "@rollup/plugin-terser": "^0.4.0", "@rollup/pluginutils": "^5.0.0", - "@typescript-eslint/eslint-plugin": "5.59.11", - "@typescript-eslint/parser": "5.59.11", - "@typescript-eslint/scope-manager": "5.59.11", - "@typescript-eslint/typescript-estree": "5.59.11", - "@typescript-eslint/visitor-keys": "5.59.11", + "@typescript-eslint/eslint-plugin": "5.60.0", + "@typescript-eslint/parser": "5.60.0", + "@typescript-eslint/scope-manager": "5.60.0", + "@typescript-eslint/typescript-estree": "5.60.0", + "@typescript-eslint/visitor-keys": "5.60.0", "eslint": "*", "esquery": "*", "rollup": "^2.75.4", diff --git a/packages/website/CHANGELOG.md b/packages/website/CHANGELOG.md index c7ded7f3d27b..7c96f9dd6466 100644 --- a/packages/website/CHANGELOG.md +++ b/packages/website/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.60.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.59.11...v5.60.0) (2023-06-19) + +**Note:** Version bump only for package website + + + + + ## [5.59.11](https://github.com/typescript-eslint/typescript-eslint/compare/v5.59.10...v5.59.11) (2023-06-12) **Note:** Version bump only for package website diff --git a/packages/website/data/sponsors.json b/packages/website/data/sponsors.json index 93cf457ce828..c4a4515bcc2e 100644 --- a/packages/website/data/sponsors.json +++ b/packages/website/data/sponsors.json @@ -24,7 +24,7 @@ "id": "Hugging Face", "image": "https://images.opencollective.com/huggingface/5c934ee/logo.png", "name": "Hugging Face", - "totalDonations": 260000, + "totalDonations": 280000, "website": "https://huggingface.co" }, { diff --git a/packages/website/package.json b/packages/website/package.json index 4c5bafb7a3a7..d1ca025502bd 100644 --- a/packages/website/package.json +++ b/packages/website/package.json @@ -1,6 +1,6 @@ { "name": "website", - "version": "5.59.11", + "version": "5.60.0", "private": true, "scripts": { "build": "docusaurus build", @@ -21,8 +21,8 @@ "@docusaurus/remark-plugin-npm2yarn": "~2.4.0", "@docusaurus/theme-common": "~2.4.0", "@mdx-js/react": "1.6.22", - "@typescript-eslint/parser": "5.59.11", - "@typescript-eslint/website-eslint": "5.59.11", + "@typescript-eslint/parser": "5.60.0", + "@typescript-eslint/website-eslint": "5.60.0", "clsx": "^1.1.1", "eslint": "*", "json-schema": "^0.4.0", @@ -49,7 +49,7 @@ "@types/react": "^18.0.9", "@types/react-helmet": "^6.1.5", "@types/react-router-dom": "^5.3.3", - "@typescript-eslint/eslint-plugin": "5.59.11", + "@typescript-eslint/eslint-plugin": "5.60.0", "copy-webpack-plugin": "^11.0.0", "eslint-plugin-jsx-a11y": "^6.5.1", "eslint-plugin-react": "^7.29.4",