From d4bdc747a0fdf17f66fadae804ab488803e11428 Mon Sep 17 00:00:00 2001 From: YeonJuan Date: Mon, 28 Oct 2024 23:35:09 +0900 Subject: [PATCH 1/5] feat(eslint-plugin): [only-throw-error] add allowThrowing option --- .../docs/rules/only-throw-error.mdx | 22 ++++++ .../src/rules/only-throw-error.ts | 17 ++++- .../eslint-plugin/tests/fixtures/errors.ts | 5 ++ .../tests/fixtures/tsconfig.json | 3 +- .../tests/rules/only-throw-error.test.ts | 70 +++++++++++++++++++ 5 files changed, 115 insertions(+), 2 deletions(-) create mode 100644 packages/eslint-plugin/tests/fixtures/errors.ts diff --git a/packages/eslint-plugin/docs/rules/only-throw-error.mdx b/packages/eslint-plugin/docs/rules/only-throw-error.mdx index 8fffde428fee..199544435c32 100644 --- a/packages/eslint-plugin/docs/rules/only-throw-error.mdx +++ b/packages/eslint-plugin/docs/rules/only-throw-error.mdx @@ -102,6 +102,27 @@ This rule adds the following options: ```ts interface Options { + /** + * Type specifiers that can be thrown. + */ + allowThrowing?: ( + | { + from: 'file'; + name: [string, ...string[]] | string; + path?: string; + } + | { + from: 'lib'; + name: [string, ...string[]] | string; + } + | { + from: 'package'; + name: [string, ...string[]] | string; + package: string; + } + | string + )[]; + /** * Whether to always allow throwing values typed as `any`. */ @@ -114,6 +135,7 @@ interface Options { } const defaultOptions: Options = { + allowThrowing: [], allowThrowingAny: false, allowThrowingUnknown: false, }; diff --git a/packages/eslint-plugin/src/rules/only-throw-error.ts b/packages/eslint-plugin/src/rules/only-throw-error.ts index 0ebd6048bee3..c1bc46864c6b 100644 --- a/packages/eslint-plugin/src/rules/only-throw-error.ts +++ b/packages/eslint-plugin/src/rules/only-throw-error.ts @@ -3,18 +3,24 @@ import type { TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; import * as ts from 'typescript'; +import type { TypeOrValueSpecifier } from '../util'; + import { createRule, getParserServices, isErrorLike, isTypeAnyType, isTypeUnknownType, + readonlynessOptionsDefaults, + readonlynessOptionsSchema, + typeMatchesSomeSpecifier, } from '../util'; type MessageIds = 'object' | 'undef'; type Options = [ { + allowThrowing?: TypeOrValueSpecifier[]; allowThrowingAny?: boolean; allowThrowingUnknown?: boolean; }, @@ -39,6 +45,10 @@ export default createRule({ type: 'object', additionalProperties: false, properties: { + allowThrowing: { + ...readonlynessOptionsSchema.properties.allow, + description: 'Type specifiers that can be thrown.', + }, allowThrowingAny: { type: 'boolean', description: @@ -55,13 +65,14 @@ export default createRule({ }, defaultOptions: [ { + allowThrowing: readonlynessOptionsDefaults.allow, allowThrowingAny: true, allowThrowingUnknown: true, }, ], create(context, [options]) { const services = getParserServices(context); - + const allowThrowing = options.allowThrowing; function checkThrowArgument(node: TSESTree.Node): void { if ( node.type === AST_NODE_TYPES.AwaitExpression || @@ -72,6 +83,10 @@ export default createRule({ const type = services.getTypeAtLocation(node); + if (typeMatchesSomeSpecifier(type, allowThrowing, services.program)) { + return; + } + if (type.flags & ts.TypeFlags.Undefined) { context.report({ node, messageId: 'undef' }); return; diff --git a/packages/eslint-plugin/tests/fixtures/errors.ts b/packages/eslint-plugin/tests/fixtures/errors.ts new file mode 100644 index 000000000000..63addd9d7df8 --- /dev/null +++ b/packages/eslint-plugin/tests/fixtures/errors.ts @@ -0,0 +1,5 @@ +declare module 'errors' { + class ErrorLike {} + + export function createError(): ErrorLike; +} diff --git a/packages/eslint-plugin/tests/fixtures/tsconfig.json b/packages/eslint-plugin/tests/fixtures/tsconfig.json index a0fc993b1f48..d8141e1ddfa4 100644 --- a/packages/eslint-plugin/tests/fixtures/tsconfig.json +++ b/packages/eslint-plugin/tests/fixtures/tsconfig.json @@ -14,6 +14,7 @@ "deprecated.ts", "mixed-enums-decl.ts", "react.tsx", - "var-declaration.ts" + "var-declaration.ts", + "errors.ts" ] } diff --git a/packages/eslint-plugin/tests/rules/only-throw-error.test.ts b/packages/eslint-plugin/tests/rules/only-throw-error.test.ts index b20673db84ea..533d2a1140cd 100644 --- a/packages/eslint-plugin/tests/rules/only-throw-error.test.ts +++ b/packages/eslint-plugin/tests/rules/only-throw-error.test.ts @@ -139,6 +139,58 @@ function fun(t: T): void { throw t; } `, + { + code: ` +throw undefined; + `, + options: [ + { + allowThrowing: [{ from: 'lib', name: 'undefined' }], + allowThrowingAny: false, + allowThrowingUnknown: false, + }, + ], + }, + { + code: ` +class CustomError implements Error {} +throw new CustomError(); + `, + options: [ + { + allowThrowing: [{ from: 'file', name: 'CustomError' }], + allowThrowingAny: false, + allowThrowingUnknown: false, + }, + ], + }, + { + code: ` +throw new Map(); + `, + options: [ + { + allowThrowing: [{ from: 'lib', name: 'Map' }], + allowThrowingAny: false, + allowThrowingUnknown: false, + }, + ], + }, + { + code: ` + import { createError } from 'errors'; + throw createError(); + `, + options: [ + { + allowThrowing: [ + { from: 'package', name: 'ErrorLike', package: 'errors' }, + ], + allowThrowingAny: false, + allowThrowingUnknown: false, + }, + ], + }, ], invalid: [ { @@ -485,5 +537,23 @@ function fun(t: T): void { }, ], }, + { + code: ` +class UnknownError implements Error {} +throw new UnknownError(); + `, + errors: [ + { + messageId: 'object', + }, + ], + options: [ + { + allowThrowing: [{ from: 'file', name: 'CustomError' }], + allowThrowingAny: false, + allowThrowingUnknown: false, + }, + ], + }, ], }); From 124faa97d974bf77fba2af73511539d39d77891e Mon Sep 17 00:00:00 2001 From: YeonJuan Date: Mon, 28 Oct 2024 23:46:08 +0900 Subject: [PATCH 2/5] ts ignore --- packages/eslint-plugin/tests/fixtures/errors.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/eslint-plugin/tests/fixtures/errors.ts b/packages/eslint-plugin/tests/fixtures/errors.ts index 63addd9d7df8..b38f6885bf80 100644 --- a/packages/eslint-plugin/tests/fixtures/errors.ts +++ b/packages/eslint-plugin/tests/fixtures/errors.ts @@ -1,3 +1,4 @@ +// @ts-ignore declare module 'errors' { class ErrorLike {} From 7889124c11147f90fe1e8063a640dcc5b3d2dc72 Mon Sep 17 00:00:00 2001 From: YeonJuan Date: Tue, 29 Oct 2024 00:02:53 +0900 Subject: [PATCH 3/5] Update only-throw-error.shot --- .../schema-snapshots/only-throw-error.shot | 113 ++++++++++++++++++ 1 file changed, 113 insertions(+) diff --git a/packages/eslint-plugin/tests/schema-snapshots/only-throw-error.shot b/packages/eslint-plugin/tests/schema-snapshots/only-throw-error.shot index 05b6ae4af6b0..aa00408329a9 100644 --- a/packages/eslint-plugin/tests/schema-snapshots/only-throw-error.shot +++ b/packages/eslint-plugin/tests/schema-snapshots/only-throw-error.shot @@ -8,6 +8,101 @@ exports[`Rule schemas should be convertible to TS types for documentation purpos { "additionalProperties": false, "properties": { + "allowThrowing": { + "description": "Type specifiers that can be thrown.", + "items": { + "oneOf": [ + { + "type": "string" + }, + { + "additionalProperties": false, + "properties": { + "from": { + "enum": ["file"], + "type": "string" + }, + "name": { + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "minItems": 1, + "type": "array", + "uniqueItems": true + } + ] + }, + "path": { + "type": "string" + } + }, + "required": ["from", "name"], + "type": "object" + }, + { + "additionalProperties": false, + "properties": { + "from": { + "enum": ["lib"], + "type": "string" + }, + "name": { + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "minItems": 1, + "type": "array", + "uniqueItems": true + } + ] + } + }, + "required": ["from", "name"], + "type": "object" + }, + { + "additionalProperties": false, + "properties": { + "from": { + "enum": ["package"], + "type": "string" + }, + "name": { + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "minItems": 1, + "type": "array", + "uniqueItems": true + } + ] + }, + "package": { + "type": "string" + } + }, + "required": ["from", "name", "package"], + "type": "object" + } + ] + }, + "type": "array" + }, "allowThrowingAny": { "description": "Whether to always allow throwing values typed as \`any\`.", "type": "boolean" @@ -26,6 +121,24 @@ exports[`Rule schemas should be convertible to TS types for documentation purpos type Options = [ { + /** Type specifiers that can be thrown. */ + allowThrowing?: ( + | { + from: 'file'; + name: [string, ...string[]] | string; + path?: string; + } + | { + from: 'lib'; + name: [string, ...string[]] | string; + } + | { + from: 'package'; + name: [string, ...string[]] | string; + package: string; + } + | string + )[]; /** Whether to always allow throwing values typed as \`any\`. */ allowThrowingAny?: boolean; /** Whether to always allow throwing values typed as \`unknown\`. */ From aff345c1150996386ea2c3a88c7a7b1e272eec90 Mon Sep 17 00:00:00 2001 From: YeonJuan Date: Wed, 30 Oct 2024 12:35:53 +0900 Subject: [PATCH 4/5] review --- .../eslint-plugin/docs/rules/only-throw-error.mdx | 8 ++++---- .../eslint-plugin/src/rules/only-throw-error.ts | 15 +++++++-------- .../tests/rules/only-throw-error.test.ts | 12 +++++------- .../tests/schema-snapshots/only-throw-error.shot | 4 ++-- 4 files changed, 18 insertions(+), 21 deletions(-) diff --git a/packages/eslint-plugin/docs/rules/only-throw-error.mdx b/packages/eslint-plugin/docs/rules/only-throw-error.mdx index 199544435c32..109b1763ebf1 100644 --- a/packages/eslint-plugin/docs/rules/only-throw-error.mdx +++ b/packages/eslint-plugin/docs/rules/only-throw-error.mdx @@ -105,7 +105,7 @@ interface Options { /** * Type specifiers that can be thrown. */ - allowThrowing?: ( + allow?: ( | { from: 'file'; name: [string, ...string[]] | string; @@ -135,9 +135,9 @@ interface Options { } const defaultOptions: Options = { - allowThrowing: [], - allowThrowingAny: false, - allowThrowingUnknown: false, + allow: [], + allowThrowingAny: true, + allowThrowingUnknown: true, }; ``` diff --git a/packages/eslint-plugin/src/rules/only-throw-error.ts b/packages/eslint-plugin/src/rules/only-throw-error.ts index c1bc46864c6b..87f6a1e34152 100644 --- a/packages/eslint-plugin/src/rules/only-throw-error.ts +++ b/packages/eslint-plugin/src/rules/only-throw-error.ts @@ -11,16 +11,15 @@ import { isErrorLike, isTypeAnyType, isTypeUnknownType, - readonlynessOptionsDefaults, - readonlynessOptionsSchema, typeMatchesSomeSpecifier, + typeOrValueSpecifiersSchema, } from '../util'; type MessageIds = 'object' | 'undef'; type Options = [ { - allowThrowing?: TypeOrValueSpecifier[]; + allow?: TypeOrValueSpecifier[]; allowThrowingAny?: boolean; allowThrowingUnknown?: boolean; }, @@ -45,8 +44,8 @@ export default createRule({ type: 'object', additionalProperties: false, properties: { - allowThrowing: { - ...readonlynessOptionsSchema.properties.allow, + allow: { + ...typeOrValueSpecifiersSchema, description: 'Type specifiers that can be thrown.', }, allowThrowingAny: { @@ -65,14 +64,14 @@ export default createRule({ }, defaultOptions: [ { - allowThrowing: readonlynessOptionsDefaults.allow, + allow: [], allowThrowingAny: true, allowThrowingUnknown: true, }, ], create(context, [options]) { const services = getParserServices(context); - const allowThrowing = options.allowThrowing; + const allow = options.allow; function checkThrowArgument(node: TSESTree.Node): void { if ( node.type === AST_NODE_TYPES.AwaitExpression || @@ -83,7 +82,7 @@ export default createRule({ const type = services.getTypeAtLocation(node); - if (typeMatchesSomeSpecifier(type, allowThrowing, services.program)) { + if (typeMatchesSomeSpecifier(type, allow, services.program)) { return; } diff --git a/packages/eslint-plugin/tests/rules/only-throw-error.test.ts b/packages/eslint-plugin/tests/rules/only-throw-error.test.ts index 533d2a1140cd..c7d52c6a1e1c 100644 --- a/packages/eslint-plugin/tests/rules/only-throw-error.test.ts +++ b/packages/eslint-plugin/tests/rules/only-throw-error.test.ts @@ -145,7 +145,7 @@ throw undefined; `, options: [ { - allowThrowing: [{ from: 'lib', name: 'undefined' }], + allow: [{ from: 'lib', name: 'undefined' }], allowThrowingAny: false, allowThrowingUnknown: false, }, @@ -158,7 +158,7 @@ throw new CustomError(); `, options: [ { - allowThrowing: [{ from: 'file', name: 'CustomError' }], + allow: [{ from: 'file', name: 'CustomError' }], allowThrowingAny: false, allowThrowingUnknown: false, }, @@ -170,7 +170,7 @@ throw new Map(); `, options: [ { - allowThrowing: [{ from: 'lib', name: 'Map' }], + allow: [{ from: 'lib', name: 'Map' }], allowThrowingAny: false, allowThrowingUnknown: false, }, @@ -183,9 +183,7 @@ throw new Map(); `, options: [ { - allowThrowing: [ - { from: 'package', name: 'ErrorLike', package: 'errors' }, - ], + allow: [{ from: 'package', name: 'ErrorLike', package: 'errors' }], allowThrowingAny: false, allowThrowingUnknown: false, }, @@ -549,7 +547,7 @@ throw new UnknownError(); ], options: [ { - allowThrowing: [{ from: 'file', name: 'CustomError' }], + allow: [{ from: 'file', name: 'CustomError' }], allowThrowingAny: false, allowThrowingUnknown: false, }, diff --git a/packages/eslint-plugin/tests/schema-snapshots/only-throw-error.shot b/packages/eslint-plugin/tests/schema-snapshots/only-throw-error.shot index aa00408329a9..c2ddc66bcc81 100644 --- a/packages/eslint-plugin/tests/schema-snapshots/only-throw-error.shot +++ b/packages/eslint-plugin/tests/schema-snapshots/only-throw-error.shot @@ -8,7 +8,7 @@ exports[`Rule schemas should be convertible to TS types for documentation purpos { "additionalProperties": false, "properties": { - "allowThrowing": { + "allow": { "description": "Type specifiers that can be thrown.", "items": { "oneOf": [ @@ -122,7 +122,7 @@ exports[`Rule schemas should be convertible to TS types for documentation purpos type Options = [ { /** Type specifiers that can be thrown. */ - allowThrowing?: ( + allow?: ( | { from: 'file'; name: [string, ...string[]] | string; From fcf19d87aafda6258e38ecaa5695d23a1f61b06d Mon Sep 17 00:00:00 2001 From: Josh Goldberg Date: Mon, 4 Nov 2024 08:53:38 -0500 Subject: [PATCH 5/5] Add to TypeOrValueSpecifier.mdx options --- docs/packages/type-utils/TypeOrValueSpecifier.mdx | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/packages/type-utils/TypeOrValueSpecifier.mdx b/docs/packages/type-utils/TypeOrValueSpecifier.mdx index b9d76442406a..7a21d16cf26d 100644 --- a/docs/packages/type-utils/TypeOrValueSpecifier.mdx +++ b/docs/packages/type-utils/TypeOrValueSpecifier.mdx @@ -132,4 +132,5 @@ Universal string specifiers will be removed in a future major version of typescr - [`@typescript-eslint/no-floating-promises` > `allowForKnownSafeCalls`](/rules/no-floating-promises#allowforknownsafecalls) - [`@typescript-eslint/no-floating-promises` > `allowForKnownSafePromises`](/rules/no-floating-promises#allowforknownsafepromises) +- [`@typescript-eslint/only-throw-error` > `allow`](/rules/only-throw-error/#allow) - [`@typescript-eslint/prefer-readonly-parameter-types` > `allow`](/rules/prefer-readonly-parameter-types/#allow) pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy