From 9544b7fc696b4fb8a8ead89cf1a957963e8c80d1 Mon Sep 17 00:00:00 2001 From: Rebecca Stevens Date: Mon, 15 Apr 2024 02:02:38 +1200 Subject: [PATCH] feat(prefer-immutable-types): allows for applying overrides to the options based on the type fix #800 --- docs/rules/prefer-immutable-types.md | 57 ++++ eslint.config.js | 1 - src/rules/prefer-immutable-types.ts | 467 ++++++++++++++++----------- 3 files changed, 332 insertions(+), 193 deletions(-) diff --git a/docs/rules/prefer-immutable-types.md b/docs/rules/prefer-immutable-types.md index e61dc9dff..df3ee7ca6 100644 --- a/docs/rules/prefer-immutable-types.md +++ b/docs/rules/prefer-immutable-types.md @@ -255,6 +255,37 @@ type Options = { Array<{ pattern: string; replace: string; message?: string }> >; }; + + overrides?: Array<{ + match: Array< + | { + from: "file"; + path?: string; + name?: string | string[]; + pattern?: RegExp | RegExp[]; + ignoreName?: string | string[]; + ignorePattern?: RegExp | RegExp[]; + } + | { + from: "lib"; + name?: string | string[]; + pattern?: RegExp | RegExp[]; + ignoreName?: string | string[]; + ignorePattern?: RegExp | RegExp[]; + } + | { + from: "package"; + package?: string; + name?: string | string[]; + pattern?: RegExp | RegExp[]; + ignoreName?: string | string[]; + ignorePattern?: RegExp | RegExp[]; + } + >; + options: Omit; + inherit?: boolean; + disable: boolean; + }>; }; ``` @@ -488,3 +519,29 @@ It allows for the ability to ignore violations based on the identifier (name) of This option takes a `RegExp` string or an array of `RegExp` strings. It allows for the ability to ignore violations based on the type (as written, with whitespace removed) of the node in question. + +### `overrides` + +Allows for applying overrides to the options based on the type's declaration. +This can be used to override the settings for types coming from 3rd party libraries. + +Note: Only the first matching override will be used. + +#### `overrides[n].specifiers` + +A specifier, or an array of specifiers to match the function type against. + +In the case of reference types, both the type and its generics will be recursively checked. +If any of them match, the specifier will be considered a match. + +#### `overrides[n].options` + +The options to use when a specifiers matches. + +#### `overrides[n].inherit` + +Inherit the root options? Default is `true`. + +#### `overrides[n].disable` + +If true, when a specifier matches, this rule will not be applied to the matching node. diff --git a/eslint.config.js b/eslint.config.js index 441606d81..75b58f631 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -55,7 +55,6 @@ export default rsEslint( "ts/no-unnecessary-condition": "off", // Temp - "functional/prefer-immutable-types": "off", "functional/no-throw-statements": "off", }, }, diff --git a/src/rules/prefer-immutable-types.ts b/src/rules/prefer-immutable-types.ts index 547ec6a49..0939d41f5 100644 --- a/src/rules/prefer-immutable-types.ts +++ b/src/rules/prefer-immutable-types.ts @@ -9,13 +9,19 @@ import { } from "@typescript-eslint/utils/ts-eslint"; import { deepmerge } from "deepmerge-ts"; import { Immutability } from "is-immutable-type"; +import { type Type, type TypeNode } from "typescript"; import { type IgnoreClassesOption, + type OverridableOptions, + type RawOverridableOptions, + getCoreOptions, + getCoreOptionsForType, ignoreClassesOptionSchema, shouldIgnoreClasses, shouldIgnoreInFunction, shouldIgnorePattern, + upgradeRawOverridableOptions, } from "#/options"; import { ruleNameScope } from "#/utils/misc"; import { type ESFunctionType } from "#/utils/node-types"; @@ -25,6 +31,7 @@ import { type RuleResult, createRule, getReturnTypesOfFunction, + getTypeDataOfNode, getTypeImmutabilityOfNode, getTypeImmutabilityOfType, isImplementationOfOverload, @@ -43,6 +50,8 @@ import { isTSTypePredicate, } from "#/utils/type-guards"; +import { overridableOptionsSchema } from "../utils/schemas"; + /** * The name of this rule. */ @@ -56,7 +65,8 @@ export const fullName: `${typeof ruleNameScope}/${typeof name}` = `${ruleNameSco type RawEnforcement = | Exclude | "None" - | false; + | false + | undefined; type Option = IgnoreClassesOption & { enforcement: RawEnforcement; @@ -65,6 +75,20 @@ type Option = IgnoreClassesOption & { ignoreTypePattern?: string[] | string; }; +type CoreOptions = Option & { + parameters?: Partial