Skip to content

Commit 42e9dcc

Browse files
committed
fix(linter): Fix docs for consistent-type-specifier-style and consistent-type-definitions rules. (#16253)
Both of these take a string config, and the docs were set up as a configuration object. Also refactor a few more rules to use the DefaultRuleConfig pattern.
1 parent 2beb500 commit 42e9dcc

File tree

5 files changed

+67
-91
lines changed

5 files changed

+67
-91
lines changed

crates/oxc_linter/src/rules/eslint/getter_return.rs

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,13 @@ use oxc_diagnostics::OxcDiagnostic;
1616
use oxc_macros::declare_oxc_lint;
1717
use oxc_span::Span;
1818
use schemars::JsonSchema;
19+
use serde::Deserialize;
20+
use serde_json::Value;
1921

2022
use crate::{
2123
AstNode,
2224
context::{ContextHost, LintContext},
23-
rule::Rule,
25+
rule::{DefaultRuleConfig, Rule},
2426
};
2527

2628
fn getter_return_diagnostic(span: Span) -> OxcDiagnostic {
@@ -29,7 +31,7 @@ fn getter_return_diagnostic(span: Span) -> OxcDiagnostic {
2931
.with_label(span)
3032
}
3133

32-
#[derive(Debug, Default, Clone, JsonSchema)]
34+
#[derive(Debug, Default, Clone, JsonSchema, Deserialize)]
3335
#[serde(rename_all = "camelCase", default)]
3436
pub struct GetterReturn {
3537
/// When set to `true`, allows getters to implicitly return `undefined` with a `return` statement containing no expression.
@@ -87,6 +89,12 @@ declare_oxc_lint!(
8789
);
8890

8991
impl Rule for GetterReturn {
92+
fn from_configuration(value: Value) -> Self {
93+
serde_json::from_value::<DefaultRuleConfig<GetterReturn>>(value)
94+
.unwrap_or_default()
95+
.into_inner()
96+
}
97+
9098
fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) {
9199
match node.kind() {
92100
AstKind::Function(func) if !func.is_typescript_syntax() => {
@@ -99,16 +107,6 @@ impl Rule for GetterReturn {
99107
}
100108
}
101109

102-
fn from_configuration(value: serde_json::Value) -> Self {
103-
let allow_implicit = value
104-
.get(0)
105-
.and_then(|config| config.get("allowImplicit"))
106-
.and_then(serde_json::Value::as_bool)
107-
.unwrap_or(false);
108-
109-
Self { allow_implicit }
110-
}
111-
112110
fn should_run(&self, ctx: &ContextHost) -> bool {
113111
// https://eslint.org/docs/latest/rules/getter-return#handled_by_typescript
114112
!ctx.source_type().is_typescript()

crates/oxc_linter/src/rules/eslint/use_isnan.rs

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,13 @@ use oxc_macros::declare_oxc_lint;
77
use oxc_span::{GetSpan, Span};
88
use oxc_syntax::operator::BinaryOperator;
99
use schemars::JsonSchema;
10+
use serde::Deserialize;
1011

11-
use crate::{AstNode, context::LintContext, rule::Rule};
12+
use crate::{
13+
AstNode,
14+
context::LintContext,
15+
rule::{DefaultRuleConfig, Rule},
16+
};
1217

1318
fn comparison_with_na_n(span: Span) -> OxcDiagnostic {
1419
OxcDiagnostic::warn("Requires calls to `isNaN()` when checking for NaN")
@@ -36,7 +41,7 @@ fn index_of_na_n(method_name: &str, span: Span) -> OxcDiagnostic {
3641
.with_label(span)
3742
}
3843

39-
#[derive(Debug, Clone, JsonSchema)]
44+
#[derive(Debug, Clone, JsonSchema, Deserialize)]
4045
#[serde(rename_all = "camelCase", default)]
4146
pub struct UseIsnan {
4247
/// Whether to disallow NaN in switch cases and discriminants
@@ -139,21 +144,9 @@ impl Rule for UseIsnan {
139144
}
140145

141146
fn from_configuration(value: serde_json::Value) -> Self {
142-
let (enforce_for_switch_case, enforce_for_index_of) =
143-
value.get(0).map_or((true, false), |config| {
144-
(
145-
config
146-
.get("enforceForSwitchCase")
147-
.and_then(serde_json::Value::as_bool)
148-
.unwrap_or(true),
149-
config
150-
.get("enforceForIndexOf")
151-
.and_then(serde_json::Value::as_bool)
152-
.unwrap_or_default(),
153-
)
154-
});
155-
156-
Self { enforce_for_switch_case, enforce_for_index_of }
147+
serde_json::from_value::<DefaultRuleConfig<UseIsnan>>(value)
148+
.unwrap_or_default()
149+
.into_inner()
157150
}
158151
}
159152

crates/oxc_linter/src/rules/eslint/valid_typeof.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,13 @@ use oxc_macros::declare_oxc_lint;
44
use oxc_span::{GetSpan, Span};
55
use oxc_syntax::operator::UnaryOperator;
66
use schemars::JsonSchema;
7+
use serde::Deserialize;
78

8-
use crate::{AstNode, context::LintContext, rule::Rule};
9+
use crate::{
10+
AstNode,
11+
context::LintContext,
12+
rule::{DefaultRuleConfig, Rule},
13+
};
914

1015
fn not_string(help: Option<&'static str>, span: Span) -> OxcDiagnostic {
1116
let mut d =
@@ -24,7 +29,7 @@ fn invalid_value(help: Option<&'static str>, span: Span) -> OxcDiagnostic {
2429
d
2530
}
2631

27-
#[derive(Debug, Clone, Default, JsonSchema)]
32+
#[derive(Debug, Clone, Default, JsonSchema, Deserialize)]
2833
#[serde(rename_all = "camelCase", default)]
2934
pub struct ValidTypeof {
3035
/// The `requireStringLiterals` option when set to `true`, allows the comparison of `typeof`
@@ -154,14 +159,9 @@ impl Rule for ValidTypeof {
154159
}
155160

156161
fn from_configuration(value: serde_json::Value) -> Self {
157-
let require_string_literals = value.get(0).is_some_and(|config| {
158-
config
159-
.get("requireStringLiterals")
160-
.and_then(serde_json::Value::as_bool)
161-
.unwrap_or(false)
162-
});
163-
164-
Self { require_string_literals }
162+
serde_json::from_value::<DefaultRuleConfig<ValidTypeof>>(value)
163+
.unwrap_or_default()
164+
.into_inner()
165165
}
166166
}
167167

crates/oxc_linter/src/rules/import/consistent_type_specifier_style.rs

Lines changed: 18 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,12 @@ use schemars::JsonSchema;
1111
use serde::{Deserialize, Serialize};
1212
use serde_json::Value;
1313

14-
use crate::{AstNode, context::LintContext, fixer::RuleFixer, rule::Rule};
14+
use crate::{
15+
AstNode,
16+
context::LintContext,
17+
fixer::RuleFixer,
18+
rule::{DefaultRuleConfig, Rule},
19+
};
1520

1621
fn consistent_type_specifier_style_diagnostic(span: Span, mode: &Mode) -> OxcDiagnostic {
1722
let (warn_msg, help_msg) = if *mode == Mode::PreferInline {
@@ -31,25 +36,15 @@ fn consistent_type_specifier_style_diagnostic(span: Span, mode: &Mode) -> OxcDia
3136
#[derive(Debug, Default, PartialEq, Clone, Serialize, Deserialize, JsonSchema)]
3237
#[serde(rename_all = "kebab-case")]
3338
enum Mode {
39+
/// Prefer `import type { Foo } from 'foo'` for type imports.
3440
#[default]
3541
PreferTopLevel,
42+
/// Prefer `import { type Foo } from 'foo'` for type imports.
3643
PreferInline,
3744
}
3845

39-
impl Mode {
40-
pub fn from(raw: &str) -> Self {
41-
if raw == "prefer-inline" { Self::PreferInline } else { Self::PreferTopLevel }
42-
}
43-
}
44-
45-
#[derive(Debug, Default, Clone, Serialize, Deserialize, JsonSchema)]
46-
#[serde(rename_all = "camelCase", default)]
47-
pub struct ConsistentTypeSpecifierStyle {
48-
/// Specify whether to prefer top-level type-only imports or inline type specifiers.
49-
/// - `"prefer-top-level"`: `import type { Foo } from 'foo'`
50-
/// - `"prefer-inline"`: `import { type Foo } from 'foo'`
51-
mode: Mode,
52-
}
46+
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
47+
pub struct ConsistentTypeSpecifierStyle(Mode);
5348

5449
declare_oxc_lint!(
5550
/// ### What it does
@@ -91,12 +86,14 @@ declare_oxc_lint!(
9186
import,
9287
style,
9388
conditional_fix,
94-
config = ConsistentTypeSpecifierStyle,
89+
config = Mode,
9590
);
9691

9792
impl Rule for ConsistentTypeSpecifierStyle {
9893
fn from_configuration(value: Value) -> Self {
99-
Self { mode: value.get(0).and_then(Value::as_str).map(Mode::from).unwrap_or_default() }
94+
serde_json::from_value::<DefaultRuleConfig<ConsistentTypeSpecifierStyle>>(value)
95+
.unwrap_or_default()
96+
.into_inner()
10097
}
10198
fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) {
10299
let AstKind::ImportDeclaration(import_decl) = node.kind() else {
@@ -112,15 +109,15 @@ impl Rule for ConsistentTypeSpecifierStyle {
112109
{
113110
return;
114111
}
115-
if self.mode == Mode::PreferTopLevel && import_decl.import_kind.is_value() {
112+
if self.0 == Mode::PreferTopLevel && import_decl.import_kind.is_value() {
116113
let (value_specifiers, type_specifiers) = split_import_specifiers_by_kind(specifiers);
117114
if type_specifiers.is_empty() {
118115
return;
119116
}
120117

121118
for item in &type_specifiers {
122119
ctx.diagnostic_with_fix(
123-
consistent_type_specifier_style_diagnostic(item.span(), &self.mode),
120+
consistent_type_specifier_style_diagnostic(item.span(), &self.0),
124121
|fixer| {
125122
let mut import_source = String::new();
126123

@@ -141,9 +138,9 @@ impl Rule for ConsistentTypeSpecifierStyle {
141138
);
142139
}
143140
}
144-
if self.mode == Mode::PreferInline && import_decl.import_kind.is_type() {
141+
if self.0 == Mode::PreferInline && import_decl.import_kind.is_type() {
145142
ctx.diagnostic_with_fix(
146-
consistent_type_specifier_style_diagnostic(import_decl.span, &self.mode),
143+
consistent_type_specifier_style_diagnostic(import_decl.span, &self.0),
147144
|fixer| {
148145
let fixer = fixer.for_multifix();
149146
let mut rule_fixes = fixer.new_fix_with_capacity(len);

crates/oxc_linter/src/rules/typescript/consistent_type_definitions.rs

Lines changed: 19 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use serde::{Deserialize, Serialize};
1313
use crate::{
1414
AstNode,
1515
context::{ContextHost, LintContext},
16-
rule::Rule,
16+
rule::{DefaultRuleConfig, Rule},
1717
};
1818

1919
fn consistent_type_definitions_diagnostic(
@@ -28,33 +28,26 @@ fn consistent_type_definitions_diagnostic(
2828
OxcDiagnostic::warn(message).with_label(span)
2929
}
3030

31-
#[derive(Debug, Default, Clone, JsonSchema, Deserialize, Serialize)]
32-
#[serde(rename_all = "camelCase", default)]
33-
pub struct ConsistentTypeDefinitions {
34-
/// Configuration option to enforce either `interface` or `type` for object type definitions.
35-
///
36-
/// Setting to `type` enforces the use of types for object type definitions.
37-
///
38-
/// Examples of **incorrect** code for this option:
31+
#[derive(Debug, Default, Clone, Deserialize, Serialize)]
32+
pub struct ConsistentTypeDefinitions(ConsistentTypeDefinitionsConfig);
33+
34+
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, JsonSchema, Deserialize, Serialize)]
35+
#[serde(rename_all = "kebab-case")]
36+
enum ConsistentTypeDefinitionsConfig {
37+
/// Prefer `interface` over `type` for object type definitions:
3938
///
4039
/// ```typescript
4140
/// interface T {
4241
/// x: number;
4342
/// }
4443
/// ```
44+
#[default]
45+
Interface,
46+
/// Prefer `type` over `interface` for object type definitions:
4547
///
46-
/// Examples of **correct** code for this option:
4748
/// ```typescript
4849
/// type T = { x: number };
4950
/// ```
50-
config: ConsistentTypeDefinitionsConfig,
51-
}
52-
53-
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, JsonSchema, Deserialize, Serialize)]
54-
#[serde(rename_all = "kebab-case")]
55-
enum ConsistentTypeDefinitionsConfig {
56-
#[default]
57-
Interface,
5851
Type,
5952
}
6053

@@ -71,7 +64,7 @@ declare_oxc_lint!(
7164
///
7265
/// ### Examples
7366
///
74-
/// By default this rule enforces the use of interfaces for object types.
67+
/// By default this rule enforces the use of `interface` for defining object types.
7568
///
7669
/// Examples of **incorrect** code for this rule:
7770
/// ```typescript
@@ -91,26 +84,21 @@ declare_oxc_lint!(
9184
typescript,
9285
style,
9386
fix,
94-
config = ConsistentTypeDefinitions,
87+
config = ConsistentTypeDefinitionsConfig,
9588
);
9689

9790
impl Rule for ConsistentTypeDefinitions {
9891
fn from_configuration(value: serde_json::Value) -> Self {
99-
let config = value.get(0).and_then(serde_json::Value::as_str).map_or_else(
100-
ConsistentTypeDefinitionsConfig::default,
101-
|value| match value {
102-
"type" => ConsistentTypeDefinitionsConfig::Type,
103-
_ => ConsistentTypeDefinitionsConfig::Interface,
104-
},
105-
);
106-
Self { config }
92+
serde_json::from_value::<DefaultRuleConfig<ConsistentTypeDefinitions>>(value)
93+
.unwrap_or_default()
94+
.into_inner()
10795
}
10896

10997
fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) {
11098
match node.kind() {
11199
AstKind::TSTypeAliasDeclaration(decl) => match &decl.type_annotation {
112100
TSType::TSTypeLiteral(_)
113-
if self.config == ConsistentTypeDefinitionsConfig::Interface =>
101+
if self.0 == ConsistentTypeDefinitionsConfig::Interface =>
114102
{
115103
let start = if decl.declare {
116104
let base_start = decl.span.start + 7;
@@ -155,7 +143,7 @@ impl Rule for ConsistentTypeDefinitions {
155143

156144
AstKind::ExportDefaultDeclaration(exp) => match &exp.declaration {
157145
ExportDefaultDeclarationKind::TSInterfaceDeclaration(decl)
158-
if self.config == ConsistentTypeDefinitionsConfig::Type =>
146+
if self.0 == ConsistentTypeDefinitionsConfig::Type =>
159147
{
160148
let name_span_start = &decl.id.span.start;
161149
let mut name_span_end = &decl.id.span.end;
@@ -192,7 +180,7 @@ impl Rule for ConsistentTypeDefinitions {
192180
},
193181

194182
AstKind::TSInterfaceDeclaration(decl)
195-
if self.config == ConsistentTypeDefinitionsConfig::Type =>
183+
if self.0 == ConsistentTypeDefinitionsConfig::Type =>
196184
{
197185
let start = if decl.declare {
198186
let base_start = decl.span.start + 7;

0 commit comments

Comments
 (0)