diff --git a/crates/oxc_linter/src/rules/import/no_duplicates.rs b/crates/oxc_linter/src/rules/import/no_duplicates.rs index fd5b9a5b65024..68d44638d032c 100644 --- a/crates/oxc_linter/src/rules/import/no_duplicates.rs +++ b/crates/oxc_linter/src/rules/import/no_duplicates.rs @@ -6,11 +6,12 @@ use oxc_macros::declare_oxc_lint; use oxc_span::Span; use rustc_hash::FxHashMap; use schemars::JsonSchema; +use serde::Deserialize; use crate::{ context::LintContext, module_record::{ImportImportName, RequestedModule}, - rule::Rule, + rule::{DefaultRuleConfig, Rule}, }; fn no_duplicates_diagnostic( @@ -37,7 +38,7 @@ where } /// -#[derive(Debug, Default, Clone, JsonSchema)] +#[derive(Debug, Default, Clone, JsonSchema, Deserialize)] #[serde(rename_all = "camelCase", default)] pub struct NoDuplicates { /// When set to `true`, prefer inline type imports instead of separate type import @@ -47,6 +48,7 @@ pub struct NoDuplicates { /// ```typescript /// import { Foo, type Bar } from './module'; /// ``` + #[serde(alias = "prefer-inline")] prefer_inline: bool, } @@ -81,7 +83,7 @@ declare_oxc_lint!( /// import { b } from 'foo'; /// /// import { c } from 'foo'; // separate type imports, unless - /// import type { d } from 'foo'; // `preferInline` is true + /// import type { d } from 'foo'; // `prefer-inline` is true /// ``` NoDuplicates, import, @@ -91,12 +93,9 @@ declare_oxc_lint!( impl Rule for NoDuplicates { fn from_configuration(value: serde_json::Value) -> Self { - Self { - prefer_inline: value - .get("preferInline") - .and_then(serde_json::Value::as_bool) - .unwrap_or(false), - } + serde_json::from_value::>(value) + .unwrap_or_default() + .into_inner() } fn run_once(&self, ctx: &LintContext<'_>) { @@ -413,9 +412,15 @@ fn test() { (r"import {type x} from './foo'; import {type y} from './foo'", None), (r"import {type x} from './foo'; import {type y} from './foo'", None), (r"import {AValue, type x, BValue} from './foo'; import {type y} from './foo'", None), + // Test prefer-inline with camelCase (legacy) + ( + r"import {AValue} from './foo'; import type {AType} from './foo'", + Some(json!([{ "preferInline": true }])), + ), + // Test prefer-inline with kebab-case (primary, matches ESLint) ( r"import {AValue} from './foo'; import type {AType} from './foo'", - Some(json!({ "preferInline": true })), + Some(json!([{ "prefer-inline": true }])), ), ]; diff --git a/crates/oxc_linter/src/snapshots/import_no_duplicates.snap b/crates/oxc_linter/src/snapshots/import_no_duplicates.snap index 5213ba842a7e1..8ed9777da6770 100644 --- a/crates/oxc_linter/src/snapshots/import_no_duplicates.snap +++ b/crates/oxc_linter/src/snapshots/import_no_duplicates.snap @@ -555,3 +555,11 @@ source: crates/oxc_linter/src/tester.rs · ╰── It is first imported here ╰──── help: Merge these imports into a single import statement + + ⚠ eslint-plugin-import(no-duplicates): Module './foo' is imported more than once in this file + ╭─[index.ts:1:22] + 1 │ import {AValue} from './foo'; import type {AType} from './foo' + · ───┬─── ─────── + · ╰── It is first imported here + ╰──── + help: Merge these imports into a single import statement