mirror of
https://github.com/oxc-project/oxc.git
synced 2026-11-04 10:29:58 +00:00
feat(linter/typescript): implement no-unsafe-enum-assignment rule (#28117)
Register `typescript/no-unsafe-enum-assignment` as a type-aware rule backed by oxlint-tsgolint 7.0.2005, following https://github.com/oxc-project/tsgolint/pull/1316. Add rule documentation and regenerate the rule registry, JSON schema, and TypeScript config types. Extend the existing type-aware CLI fixture with unsafe assignments, arguments, returns, assertions, mutations, and enum-key access, plus valid enum-member and bitwise-combination cases. Reuse the existing tests and update their diagnostic and count snapshots.
This commit is contained in:
1 parent
165c91f9c1
commit
d1b00f45ec
13 files changed
+762
-593
No files matched your search
@@ -32,6 +32,7 @@
|
||||
"typescript/no-unsafe-argument": "error",
|
||||
"typescript/no-unsafe-assignment": "error",
|
||||
"typescript/no-unsafe-call": "error",
|
||||
"typescript/no-unsafe-enum-assignment": "error",
|
||||
"typescript/no-unsafe-enum-comparison": "error",
|
||||
"typescript/no-unsafe-member-access": "error",
|
||||
"typescript/no-unsafe-return": "error",
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
enum Fruit {
|
||||
Apple,
|
||||
Banana,
|
||||
}
|
||||
|
||||
const fruit: Fruit = 1;
|
||||
function takesFruit(value: Fruit): void {}
|
||||
takesFruit(1);
|
||||
function getFruit(): Fruit {
|
||||
return 0;
|
||||
}
|
||||
const asserted = 1 as Fruit;
|
||||
let mutable = Fruit.Apple;
|
||||
mutable++;
|
||||
declare const names: { [key in Fruit]: string };
|
||||
names[0];
|
||||
|
||||
// Enum members and bitwise combinations are allowed.
|
||||
const safeFruit: Fruit = Fruit.Apple;
|
||||
takesFruit(Fruit.Banana);
|
||||
const combined: Fruit = Fruit.Apple | Fruit.Banana;
|
||||
names[Fruit.Apple];
|
||||
|
||||
export {};
|
||||
@@ -1490,6 +1490,7 @@ export interface DummyRuleMap {
|
||||
"typescript/no-unsafe-assignment"?: RuleNoConfig;
|
||||
"typescript/no-unsafe-call"?: RuleNoConfig;
|
||||
"typescript/no-unsafe-declaration-merging"?: RuleNoConfig;
|
||||
"typescript/no-unsafe-enum-assignment"?: RuleNoConfig;
|
||||
"typescript/no-unsafe-enum-comparison"?: RuleNoConfig;
|
||||
"typescript/no-unsafe-function-type"?: RuleNoConfig;
|
||||
"typescript/no-unsafe-member-access"?: RuleNoConfig | [AllowWarnDeny, NoUnsafeMemberAccessConfig];
|
||||
|
||||
@@ -6,8 +6,8 @@ arguments: --type-aware --silent
|
||||
working directory: fixtures/cli/tsgolint
|
||||
----------
|
||||
|
||||
Found 0 warnings and 86 errors.
|
||||
Finished in <variable>ms on 61 files with 60 rules using 1 threads.
|
||||
Found 0 warnings and 92 errors.
|
||||
Finished in <variable>ms on 62 files with 61 rules using 1 threads.
|
||||
----------
|
||||
CLI result: LintFoundErrors
|
||||
----------
|
||||
+1
-1
@@ -42,7 +42,7 @@ working directory: fixtures/cli/tsgolint
|
||||
help: Remove the debugger statement
|
||||
|
||||
Found 2 warnings and 2 errors.
|
||||
Finished in <variable>ms on 61 files with 2 rules using 1 threads.
|
||||
Finished in <variable>ms on 62 files with 2 rules using 1 threads.
|
||||
----------
|
||||
CLI result: LintFoundErrors
|
||||
----------
|
||||
+1
-1
@@ -16,7 +16,7 @@ working directory: fixtures/cli/tsgolint
|
||||
help: Remove the debugger statement
|
||||
|
||||
Found 0 warnings and 1 error.
|
||||
Finished in <variable>ms on 1 file with 60 rules using 1 threads.
|
||||
Finished in <variable>ms on 1 file with 61 rules using 1 threads.
|
||||
----------
|
||||
CLI result: LintFoundErrors
|
||||
----------
|
||||
@@ -352,6 +352,54 @@ working directory: fixtures/cli/tsgolint
|
||||
3 |
|
||||
`----
|
||||
|
||||
x typescript(no-unsafe-enum-assignment): The value assigned here does not have a shared enum type with the expected enum 'Fruit'.
|
||||
,-[no-unsafe-enum-assignment.ts:6:7]
|
||||
5 |
|
||||
6 | const fruit: Fruit = 1;
|
||||
: ^^^^^^^^^^^^^^^^
|
||||
7 | function takesFruit(value: Fruit): void {}
|
||||
`----
|
||||
|
||||
x typescript(no-unsafe-enum-assignment): The argument passed here does not have a shared enum type with the expected enum 'Fruit'.
|
||||
,-[no-unsafe-enum-assignment.ts:8:12]
|
||||
7 | function takesFruit(value: Fruit): void {}
|
||||
8 | takesFruit(1);
|
||||
: ^
|
||||
9 | function getFruit(): Fruit {
|
||||
`----
|
||||
|
||||
x typescript(no-unsafe-enum-assignment): The value returned here does not have a shared enum type with the expected enum 'Fruit'.
|
||||
,-[no-unsafe-enum-assignment.ts:10:3]
|
||||
9 | function getFruit(): Fruit {
|
||||
10 | return 0;
|
||||
: ^^^^^^^^^
|
||||
11 | }
|
||||
`----
|
||||
|
||||
x typescript(no-unsafe-enum-assignment): The value asserted here does not have a shared enum type with the expected enum 'Fruit'.
|
||||
,-[no-unsafe-enum-assignment.ts:12:18]
|
||||
11 | }
|
||||
12 | const asserted = 1 as Fruit;
|
||||
: ^^^^^^^^^^
|
||||
13 | let mutable = Fruit.Apple;
|
||||
`----
|
||||
|
||||
x typescript(no-unsafe-enum-assignment): This mutation can produce a value outside of the expected enum 'Fruit'.
|
||||
,-[no-unsafe-enum-assignment.ts:14:1]
|
||||
13 | let mutable = Fruit.Apple;
|
||||
14 | mutable++;
|
||||
: ^^^^^^^^^
|
||||
15 | declare const names: { [key in Fruit]: string };
|
||||
`----
|
||||
|
||||
x typescript(no-unsafe-enum-assignment): The computed key used here does not have a shared enum type with the expected enum 'Fruit'.
|
||||
,-[no-unsafe-enum-assignment.ts:16:7]
|
||||
15 | declare const names: { [key in Fruit]: string };
|
||||
16 | names[0];
|
||||
: ^
|
||||
17 |
|
||||
`----
|
||||
|
||||
x typescript(no-unsafe-enum-comparison): The two values in this comparison do not have a shared enum type.
|
||||
,-[no-unsafe-enum-comparison.ts:9:20]
|
||||
8 | }
|
||||
@@ -720,8 +768,8 @@ working directory: fixtures/cli/tsgolint
|
||||
`----
|
||||
help: If your function does not access `this`, you can annotate it with `this: void`, or consider using an arrow function instead.
|
||||
|
||||
Found 0 warnings and 86 errors.
|
||||
Finished in <variable>ms on 61 files with 60 rules using 1 threads.
|
||||
Found 0 warnings and 92 errors.
|
||||
Finished in <variable>ms on 62 files with 61 rules using 1 threads.
|
||||
----------
|
||||
CLI result: LintFoundErrors
|
||||
----------
|
||||
+1
-1
@@ -42,7 +42,7 @@ working directory: fixtures/cli/tsgolint
|
||||
help: Remove the debugger statement
|
||||
|
||||
Found 2 warnings and 2 errors.
|
||||
Finished in <variable>ms on 61 files with 2 rules using 1 threads.
|
||||
Finished in <variable>ms on 62 files with 2 rules using 1 threads.
|
||||
----------
|
||||
CLI result: LintFoundErrors
|
||||
----------
|
||||
@@ -1972,6 +1972,11 @@ impl RuleRunner
|
||||
const RUN_FUNCTIONS: RuleRunFunctionsImplemented = RuleRunFunctionsImplemented::Run;
|
||||
}
|
||||
|
||||
impl RuleRunner for crate::rules::typescript::no_unsafe_enum_assignment::NoUnsafeEnumAssignment {
|
||||
const NODE_TYPES: Option<&AstTypesBitset> = None;
|
||||
const RUN_FUNCTIONS: RuleRunFunctionsImplemented = RuleRunFunctionsImplemented::Unknown;
|
||||
}
|
||||
|
||||
impl RuleRunner for crate::rules::typescript::no_unsafe_enum_comparison::NoUnsafeEnumComparison {
|
||||
const NODE_TYPES: Option<&AstTypesBitset> = None;
|
||||
const RUN_FUNCTIONS: RuleRunFunctionsImplemented = RuleRunFunctionsImplemented::Unknown;
|
||||
|
||||
+611
-586
File diff suppressed because it is too large.
Load diff
@@ -299,6 +299,7 @@ pub(crate) mod typescript {
|
||||
pub mod no_unsafe_assignment;
|
||||
pub mod no_unsafe_call;
|
||||
pub mod no_unsafe_declaration_merging;
|
||||
pub mod no_unsafe_enum_assignment;
|
||||
pub mod no_unsafe_enum_comparison;
|
||||
pub mod no_unsafe_function_type;
|
||||
pub mod no_unsafe_member_access;
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
use oxc_macros::declare_oxc_lint;
|
||||
|
||||
use crate::rule::Rule;
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct NoUnsafeEnumAssignment;
|
||||
|
||||
declare_oxc_lint!(
|
||||
/// ### What it does
|
||||
///
|
||||
/// Disallows using values that do not share an enum type where an enum value is expected.
|
||||
/// This includes assignments, arguments, return values, type assertions, mutations,
|
||||
/// and computed keys in objects keyed by enum members.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
///
|
||||
/// Using the underlying number or string instead of an enum member bypasses the
|
||||
/// enum's type safety. Numeric mutations can also produce values outside the enum.
|
||||
/// Referencing enum members keeps values tied to the enum when its members change.
|
||||
///
|
||||
/// ### Examples
|
||||
///
|
||||
/// Examples of **incorrect** code for this rule:
|
||||
/// ```ts
|
||||
/// enum Fruit {
|
||||
/// Apple,
|
||||
/// Banana,
|
||||
/// }
|
||||
///
|
||||
/// const fruit: Fruit = 0;
|
||||
/// function eat(fruit: Fruit) {}
|
||||
/// eat(1);
|
||||
///
|
||||
/// function getFruit(): Fruit {
|
||||
/// return 0;
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Examples of **correct** code for this rule:
|
||||
/// ```ts
|
||||
/// enum Fruit {
|
||||
/// Apple,
|
||||
/// Banana,
|
||||
/// }
|
||||
///
|
||||
/// const fruit: Fruit = Fruit.Apple;
|
||||
/// function eat(fruit: Fruit) {}
|
||||
/// eat(Fruit.Banana);
|
||||
///
|
||||
/// function getFruit(): Fruit {
|
||||
/// return Fruit.Apple;
|
||||
/// }
|
||||
/// ```
|
||||
NoUnsafeEnumAssignment(tsgolint),
|
||||
typescript,
|
||||
suspicious,
|
||||
version = "next",
|
||||
short_description = "Disallow unsafe enum assignments.",
|
||||
);
|
||||
|
||||
impl Rule for NoUnsafeEnumAssignment {}
|
||||
@@ -8371,6 +8371,9 @@
|
||||
"typescript/no-unsafe-declaration-merging": {
|
||||
"$ref": "#/definitions/RuleNoConfig"
|
||||
},
|
||||
"typescript/no-unsafe-enum-assignment": {
|
||||
"$ref": "#/definitions/RuleNoConfig"
|
||||
},
|
||||
"typescript/no-unsafe-enum-comparison": {
|
||||
"$ref": "#/definitions/RuleNoConfig"
|
||||
},
|
||||
|
||||
Reference in new issue
Block a user