diff --git a/apps/oxlint/fixtures/tsgolint/.oxlintrc.json b/apps/oxlint/fixtures/tsgolint/.oxlintrc.json index 5deeaf4964ef2..c705dccd7d9b8 100644 --- a/apps/oxlint/fixtures/tsgolint/.oxlintrc.json +++ b/apps/oxlint/fixtures/tsgolint/.oxlintrc.json @@ -4,6 +4,7 @@ }, "rules": { "typescript/await-thenable": "error", + "typescript/consistent-type-exports": "error", "typescript/no-array-delete": "error", "typescript/no-base-to-string": "error", "typescript/no-confusing-void-expression": "error", diff --git a/apps/oxlint/fixtures/tsgolint/consistent-type-exports.ts b/apps/oxlint/fixtures/tsgolint/consistent-type-exports.ts new file mode 100644 index 0000000000000..7ef68b84b3a99 --- /dev/null +++ b/apps/oxlint/fixtures/tsgolint/consistent-type-exports.ts @@ -0,0 +1,7 @@ +type LocalType = { + value: string; +}; + +const localValue = 1; + +export { LocalType, localValue }; diff --git a/apps/oxlint/fixtures/tsgolint_rule_options/.oxlintrc.json b/apps/oxlint/fixtures/tsgolint_rule_options/.oxlintrc.json index 0da3e6afe6a67..74e8d85bf0e5e 100644 --- a/apps/oxlint/fixtures/tsgolint_rule_options/.oxlintrc.json +++ b/apps/oxlint/fixtures/tsgolint_rule_options/.oxlintrc.json @@ -51,6 +51,12 @@ "checkTypePredicates": false, } ], + "typescript/consistent-type-exports": [ + "error", + { + "fixMixedExportsWithInlineTypeSpecifier": true + } + ], "typescript/only-throw-error": [ "error", { diff --git a/apps/oxlint/fixtures/tsgolint_rule_options/test.ts b/apps/oxlint/fixtures/tsgolint_rule_options/test.ts index 0c5ad984174b9..c7e187f12f2ee 100644 --- a/apps/oxlint/fixtures/tsgolint_rule_options/test.ts +++ b/apps/oxlint/fixtures/tsgolint_rule_options/test.ts @@ -74,6 +74,12 @@ while (true) { break; } +// Test consistent-type-exports with fixMixedExportsWithInlineTypeSpecifier option +type ExportOnlyType = { value: number }; +const exportOnlyValue = 1; +// This SHOULD error because ExportOnlyType is only used as a type. +export { ExportOnlyType, exportOnlyValue }; + // Test only-throw-error with allowRethrowing option // When allowRethrowing is false, rethrowing a caught error SHOULD error try { diff --git a/apps/oxlint/src/snapshots/fixtures__tsgolint_--type-aware --silent@oxlint.snap b/apps/oxlint/src/snapshots/fixtures__tsgolint_--type-aware --silent@oxlint.snap index 8382d15c16563..0f635ab81fc53 100644 --- a/apps/oxlint/src/snapshots/fixtures__tsgolint_--type-aware --silent@oxlint.snap +++ b/apps/oxlint/src/snapshots/fixtures__tsgolint_--type-aware --silent@oxlint.snap @@ -6,8 +6,8 @@ arguments: --type-aware --silent working directory: fixtures/tsgolint ---------- -Found 0 warnings and 57 errors. -Finished in ms on 47 files with 46 rules using 1 threads. +Found 0 warnings and 58 errors. +Finished in ms on 48 files with 47 rules using 1 threads. ---------- CLI result: LintFoundErrors ---------- diff --git a/apps/oxlint/src/snapshots/fixtures__tsgolint_--type-aware -c config-test.json@oxlint.snap b/apps/oxlint/src/snapshots/fixtures__tsgolint_--type-aware -c config-test.json@oxlint.snap index 046f6457dc2c9..51206f940d71a 100644 --- a/apps/oxlint/src/snapshots/fixtures__tsgolint_--type-aware -c config-test.json@oxlint.snap +++ b/apps/oxlint/src/snapshots/fixtures__tsgolint_--type-aware -c config-test.json@oxlint.snap @@ -40,7 +40,7 @@ working directory: fixtures/tsgolint help: Remove the debugger statement Found 2 warnings and 2 errors. -Finished in ms on 47 files with 1 rules using 1 threads. +Finished in ms on 48 files with 1 rules using 1 threads. ---------- CLI result: LintFoundErrors ---------- diff --git a/apps/oxlint/src/snapshots/fixtures__tsgolint_--type-aware test.svelte@oxlint.snap b/apps/oxlint/src/snapshots/fixtures__tsgolint_--type-aware test.svelte@oxlint.snap index 083c9b71e8cee..3224fef6af439 100644 --- a/apps/oxlint/src/snapshots/fixtures__tsgolint_--type-aware test.svelte@oxlint.snap +++ b/apps/oxlint/src/snapshots/fixtures__tsgolint_--type-aware test.svelte@oxlint.snap @@ -16,7 +16,7 @@ working directory: fixtures/tsgolint help: Remove the debugger statement Found 0 warnings and 1 error. -Finished in ms on 1 file with 46 rules using 1 threads. +Finished in ms on 1 file with 47 rules using 1 threads. ---------- CLI result: LintFoundErrors ---------- diff --git a/apps/oxlint/src/snapshots/fixtures__tsgolint_--type-aware@oxlint.snap b/apps/oxlint/src/snapshots/fixtures__tsgolint_--type-aware@oxlint.snap index ed5c7f8997506..2370cd80daf04 100644 --- a/apps/oxlint/src/snapshots/fixtures__tsgolint_--type-aware@oxlint.snap +++ b/apps/oxlint/src/snapshots/fixtures__tsgolint_--type-aware@oxlint.snap @@ -13,6 +13,13 @@ working directory: fixtures/tsgolint 2 | `---- + x typescript-eslint(consistent-type-exports): Type export LocalType is not a value and should be exported using `export type`. + ,-[consistent-type-exports.ts:7:1] + 6 | + 7 | export { LocalType, localValue }; + : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + `---- + x typescript-eslint(no-array-delete): Using the `delete` operator with an array expression is unsafe. ,-[no-array-delete.ts:2:1] 1 | declare const arr: number[]; @@ -448,8 +455,8 @@ working directory: fixtures/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 57 errors. -Finished in ms on 47 files with 46 rules using 1 threads. +Found 0 warnings and 58 errors. +Finished in ms on 48 files with 47 rules using 1 threads. ---------- CLI result: LintFoundErrors ---------- diff --git a/apps/oxlint/src/snapshots/fixtures__tsgolint_rule_options_--type-aware@oxlint.snap b/apps/oxlint/src/snapshots/fixtures__tsgolint_rule_options_--type-aware@oxlint.snap index 5a0a3900ac59d..ca763cc72e6e3 100644 --- a/apps/oxlint/src/snapshots/fixtures__tsgolint_rule_options_--type-aware@oxlint.snap +++ b/apps/oxlint/src/snapshots/fixtures__tsgolint_rule_options_--type-aware@oxlint.snap @@ -48,8 +48,16 @@ working directory: fixtures/tsgolint_rule_options 69 | result += 1; `---- -Found 0 warnings and 5 errors. -Finished in ms on 1 file with 8 rules using 1 threads. + x typescript-eslint(consistent-type-exports): Type export ExportOnlyType is not a value and should be exported using `export type`. + ,-[test.ts:81:1] + 80 | // This SHOULD error because ExportOnlyType is only used as a type. + 81 | export { ExportOnlyType, exportOnlyValue }; + : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 82 | + `---- + +Found 0 warnings and 6 errors. +Finished in ms on 1 file with 9 rules using 1 threads. ---------- CLI result: LintFoundErrors ---------- diff --git a/crates/oxc_linter/src/generated/rule_runner_impls.rs b/crates/oxc_linter/src/generated/rule_runner_impls.rs index 74aea63d8cb4d..35a6255d0b17c 100644 --- a/crates/oxc_linter/src/generated/rule_runner_impls.rs +++ b/crates/oxc_linter/src/generated/rule_runner_impls.rs @@ -1427,6 +1427,11 @@ impl RuleRunner const RUN_FUNCTIONS: RuleRunFunctionsImplemented = RuleRunFunctionsImplemented::Run; } +impl RuleRunner for crate::rules::typescript::consistent_type_exports::ConsistentTypeExports { + const NODE_TYPES: Option<&AstTypesBitset> = None; + const RUN_FUNCTIONS: RuleRunFunctionsImplemented = RuleRunFunctionsImplemented::Unknown; +} + impl RuleRunner for crate::rules::typescript::consistent_type_imports::ConsistentTypeImports { const NODE_TYPES: Option<&AstTypesBitset> = None; const RUN_FUNCTIONS: RuleRunFunctionsImplemented = RuleRunFunctionsImplemented::Run; diff --git a/crates/oxc_linter/src/generated/rules_enum.rs b/crates/oxc_linter/src/generated/rules_enum.rs index 4adeb384f8029..82997307e7a1f 100644 --- a/crates/oxc_linter/src/generated/rules_enum.rs +++ b/crates/oxc_linter/src/generated/rules_enum.rs @@ -446,6 +446,7 @@ pub use crate::rules::typescript::consistent_generic_constructors::ConsistentGen pub use crate::rules::typescript::consistent_indexed_object_style::ConsistentIndexedObjectStyle as TypescriptConsistentIndexedObjectStyle; pub use crate::rules::typescript::consistent_type_assertions::ConsistentTypeAssertions as TypescriptConsistentTypeAssertions; pub use crate::rules::typescript::consistent_type_definitions::ConsistentTypeDefinitions as TypescriptConsistentTypeDefinitions; +pub use crate::rules::typescript::consistent_type_exports::ConsistentTypeExports as TypescriptConsistentTypeExports; pub use crate::rules::typescript::consistent_type_imports::ConsistentTypeImports as TypescriptConsistentTypeImports; pub use crate::rules::typescript::explicit_function_return_type::ExplicitFunctionReturnType as TypescriptExplicitFunctionReturnType; pub use crate::rules::typescript::explicit_module_boundary_types::ExplicitModuleBoundaryTypes as TypescriptExplicitModuleBoundaryTypes; @@ -906,6 +907,7 @@ pub enum RuleEnum { TypescriptConsistentIndexedObjectStyle(TypescriptConsistentIndexedObjectStyle), TypescriptConsistentTypeAssertions(TypescriptConsistentTypeAssertions), TypescriptConsistentTypeDefinitions(TypescriptConsistentTypeDefinitions), + TypescriptConsistentTypeExports(TypescriptConsistentTypeExports), TypescriptConsistentTypeImports(TypescriptConsistentTypeImports), TypescriptExplicitFunctionReturnType(TypescriptExplicitFunctionReturnType), TypescriptExplicitModuleBoundaryTypes(TypescriptExplicitModuleBoundaryTypes), @@ -1592,8 +1594,9 @@ const TYPESCRIPT_CONSISTENT_TYPE_ASSERTIONS_ID: usize = TYPESCRIPT_CONSISTENT_INDEXED_OBJECT_STYLE_ID + 1usize; const TYPESCRIPT_CONSISTENT_TYPE_DEFINITIONS_ID: usize = TYPESCRIPT_CONSISTENT_TYPE_ASSERTIONS_ID + 1usize; -const TYPESCRIPT_CONSISTENT_TYPE_IMPORTS_ID: usize = +const TYPESCRIPT_CONSISTENT_TYPE_EXPORTS_ID: usize = TYPESCRIPT_CONSISTENT_TYPE_DEFINITIONS_ID + 1usize; +const TYPESCRIPT_CONSISTENT_TYPE_IMPORTS_ID: usize = TYPESCRIPT_CONSISTENT_TYPE_EXPORTS_ID + 1usize; const TYPESCRIPT_EXPLICIT_FUNCTION_RETURN_TYPE_ID: usize = TYPESCRIPT_CONSISTENT_TYPE_IMPORTS_ID + 1usize; const TYPESCRIPT_EXPLICIT_MODULE_BOUNDARY_TYPES_ID: usize = @@ -2360,6 +2363,7 @@ impl RuleEnum { Self::TypescriptConsistentTypeDefinitions(_) => { TYPESCRIPT_CONSISTENT_TYPE_DEFINITIONS_ID } + Self::TypescriptConsistentTypeExports(_) => TYPESCRIPT_CONSISTENT_TYPE_EXPORTS_ID, Self::TypescriptConsistentTypeImports(_) => TYPESCRIPT_CONSISTENT_TYPE_IMPORTS_ID, Self::TypescriptExplicitFunctionReturnType(_) => { TYPESCRIPT_EXPLICIT_FUNCTION_RETURN_TYPE_ID @@ -3137,6 +3141,7 @@ impl RuleEnum { Self::TypescriptConsistentTypeDefinitions(_) => { TypescriptConsistentTypeDefinitions::NAME } + Self::TypescriptConsistentTypeExports(_) => TypescriptConsistentTypeExports::NAME, Self::TypescriptConsistentTypeImports(_) => TypescriptConsistentTypeImports::NAME, Self::TypescriptExplicitFunctionReturnType(_) => { TypescriptExplicitFunctionReturnType::NAME @@ -3912,6 +3917,7 @@ impl RuleEnum { Self::TypescriptConsistentTypeDefinitions(_) => { TypescriptConsistentTypeDefinitions::CATEGORY } + Self::TypescriptConsistentTypeExports(_) => TypescriptConsistentTypeExports::CATEGORY, Self::TypescriptConsistentTypeImports(_) => TypescriptConsistentTypeImports::CATEGORY, Self::TypescriptExplicitFunctionReturnType(_) => { TypescriptExplicitFunctionReturnType::CATEGORY @@ -4718,6 +4724,7 @@ impl RuleEnum { Self::TypescriptConsistentTypeDefinitions(_) => { TypescriptConsistentTypeDefinitions::FIX } + Self::TypescriptConsistentTypeExports(_) => TypescriptConsistentTypeExports::FIX, Self::TypescriptConsistentTypeImports(_) => TypescriptConsistentTypeImports::FIX, Self::TypescriptExplicitFunctionReturnType(_) => { TypescriptExplicitFunctionReturnType::FIX @@ -5518,6 +5525,9 @@ impl RuleEnum { Self::TypescriptConsistentTypeDefinitions(_) => { TypescriptConsistentTypeDefinitions::documentation() } + Self::TypescriptConsistentTypeExports(_) => { + TypescriptConsistentTypeExports::documentation() + } Self::TypescriptConsistentTypeImports(_) => { TypescriptConsistentTypeImports::documentation() } @@ -6765,6 +6775,10 @@ impl RuleEnum { TypescriptConsistentTypeDefinitions::config_schema(generator) .or_else(|| TypescriptConsistentTypeDefinitions::schema(generator)) } + Self::TypescriptConsistentTypeExports(_) => { + TypescriptConsistentTypeExports::config_schema(generator) + .or_else(|| TypescriptConsistentTypeExports::schema(generator)) + } Self::TypescriptConsistentTypeImports(_) => { TypescriptConsistentTypeImports::config_schema(generator) .or_else(|| TypescriptConsistentTypeImports::schema(generator)) @@ -8354,6 +8368,7 @@ impl RuleEnum { Self::TypescriptConsistentIndexedObjectStyle(_) => "typescript", Self::TypescriptConsistentTypeAssertions(_) => "typescript", Self::TypescriptConsistentTypeDefinitions(_) => "typescript", + Self::TypescriptConsistentTypeExports(_) => "typescript", Self::TypescriptConsistentTypeImports(_) => "typescript", Self::TypescriptExplicitFunctionReturnType(_) => "typescript", Self::TypescriptExplicitModuleBoundaryTypes(_) => "typescript", @@ -9468,6 +9483,9 @@ impl RuleEnum { TypescriptConsistentTypeDefinitions::from_configuration(value)?, )) } + Self::TypescriptConsistentTypeExports(_) => Ok(Self::TypescriptConsistentTypeExports( + TypescriptConsistentTypeExports::from_configuration(value)?, + )), Self::TypescriptConsistentTypeImports(_) => Ok(Self::TypescriptConsistentTypeImports( TypescriptConsistentTypeImports::from_configuration(value)?, )), @@ -11205,6 +11223,7 @@ impl RuleEnum { Self::TypescriptConsistentIndexedObjectStyle(rule) => rule.to_configuration(), Self::TypescriptConsistentTypeAssertions(rule) => rule.to_configuration(), Self::TypescriptConsistentTypeDefinitions(rule) => rule.to_configuration(), + Self::TypescriptConsistentTypeExports(rule) => rule.to_configuration(), Self::TypescriptConsistentTypeImports(rule) => rule.to_configuration(), Self::TypescriptExplicitFunctionReturnType(rule) => rule.to_configuration(), Self::TypescriptExplicitModuleBoundaryTypes(rule) => rule.to_configuration(), @@ -11890,6 +11909,7 @@ impl RuleEnum { Self::TypescriptConsistentIndexedObjectStyle(rule) => rule.run(node, ctx), Self::TypescriptConsistentTypeAssertions(rule) => rule.run(node, ctx), Self::TypescriptConsistentTypeDefinitions(rule) => rule.run(node, ctx), + Self::TypescriptConsistentTypeExports(rule) => rule.run(node, ctx), Self::TypescriptConsistentTypeImports(rule) => rule.run(node, ctx), Self::TypescriptExplicitFunctionReturnType(rule) => rule.run(node, ctx), Self::TypescriptExplicitModuleBoundaryTypes(rule) => rule.run(node, ctx), @@ -12571,6 +12591,7 @@ impl RuleEnum { Self::TypescriptConsistentIndexedObjectStyle(rule) => rule.run_once(ctx), Self::TypescriptConsistentTypeAssertions(rule) => rule.run_once(ctx), Self::TypescriptConsistentTypeDefinitions(rule) => rule.run_once(ctx), + Self::TypescriptConsistentTypeExports(rule) => rule.run_once(ctx), Self::TypescriptConsistentTypeImports(rule) => rule.run_once(ctx), Self::TypescriptExplicitFunctionReturnType(rule) => rule.run_once(ctx), Self::TypescriptExplicitModuleBoundaryTypes(rule) => rule.run_once(ctx), @@ -13266,6 +13287,7 @@ impl RuleEnum { Self::TypescriptConsistentTypeDefinitions(rule) => { rule.run_on_jest_node(jest_node, ctx) } + Self::TypescriptConsistentTypeExports(rule) => rule.run_on_jest_node(jest_node, ctx), Self::TypescriptConsistentTypeImports(rule) => rule.run_on_jest_node(jest_node, ctx), Self::TypescriptExplicitFunctionReturnType(rule) => { rule.run_on_jest_node(jest_node, ctx) @@ -14023,6 +14045,7 @@ impl RuleEnum { Self::TypescriptConsistentIndexedObjectStyle(rule) => rule.should_run(ctx), Self::TypescriptConsistentTypeAssertions(rule) => rule.should_run(ctx), Self::TypescriptConsistentTypeDefinitions(rule) => rule.should_run(ctx), + Self::TypescriptConsistentTypeExports(rule) => rule.should_run(ctx), Self::TypescriptConsistentTypeImports(rule) => rule.should_run(ctx), Self::TypescriptExplicitFunctionReturnType(rule) => rule.should_run(ctx), Self::TypescriptExplicitModuleBoundaryTypes(rule) => rule.should_run(ctx), @@ -14746,6 +14769,9 @@ impl RuleEnum { Self::TypescriptConsistentTypeDefinitions(_) => { TypescriptConsistentTypeDefinitions::IS_TSGOLINT_RULE } + Self::TypescriptConsistentTypeExports(_) => { + TypescriptConsistentTypeExports::IS_TSGOLINT_RULE + } Self::TypescriptConsistentTypeImports(_) => { TypescriptConsistentTypeImports::IS_TSGOLINT_RULE } @@ -15684,6 +15710,7 @@ impl RuleEnum { Self::TypescriptConsistentTypeDefinitions(_) => { TypescriptConsistentTypeDefinitions::HAS_CONFIG } + Self::TypescriptConsistentTypeExports(_) => TypescriptConsistentTypeExports::HAS_CONFIG, Self::TypescriptConsistentTypeImports(_) => TypescriptConsistentTypeImports::HAS_CONFIG, Self::TypescriptExplicitFunctionReturnType(_) => { TypescriptExplicitFunctionReturnType::HAS_CONFIG @@ -16499,6 +16526,7 @@ impl RuleEnum { Self::TypescriptConsistentIndexedObjectStyle(rule) => rule.types_info(), Self::TypescriptConsistentTypeAssertions(rule) => rule.types_info(), Self::TypescriptConsistentTypeDefinitions(rule) => rule.types_info(), + Self::TypescriptConsistentTypeExports(rule) => rule.types_info(), Self::TypescriptConsistentTypeImports(rule) => rule.types_info(), Self::TypescriptExplicitFunctionReturnType(rule) => rule.types_info(), Self::TypescriptExplicitModuleBoundaryTypes(rule) => rule.types_info(), @@ -17180,6 +17208,7 @@ impl RuleEnum { Self::TypescriptConsistentIndexedObjectStyle(rule) => rule.run_info(), Self::TypescriptConsistentTypeAssertions(rule) => rule.run_info(), Self::TypescriptConsistentTypeDefinitions(rule) => rule.run_info(), + Self::TypescriptConsistentTypeExports(rule) => rule.run_info(), Self::TypescriptConsistentTypeImports(rule) => rule.run_info(), Self::TypescriptExplicitFunctionReturnType(rule) => rule.run_info(), Self::TypescriptExplicitModuleBoundaryTypes(rule) => rule.run_info(), @@ -17893,6 +17922,7 @@ pub static RULES: std::sync::LazyLock> = std::sync::LazyLock::new( RuleEnum::TypescriptConsistentTypeDefinitions( TypescriptConsistentTypeDefinitions::default(), ), + RuleEnum::TypescriptConsistentTypeExports(TypescriptConsistentTypeExports::default()), RuleEnum::TypescriptConsistentTypeImports(TypescriptConsistentTypeImports::default()), RuleEnum::TypescriptExplicitFunctionReturnType( TypescriptExplicitFunctionReturnType::default(), diff --git a/crates/oxc_linter/src/rules.rs b/crates/oxc_linter/src/rules.rs index 6a202976a6087..4d504876794ff 100644 --- a/crates/oxc_linter/src/rules.rs +++ b/crates/oxc_linter/src/rules.rs @@ -223,6 +223,7 @@ pub(crate) mod typescript { pub mod consistent_indexed_object_style; pub mod consistent_type_assertions; pub mod consistent_type_definitions; + pub mod consistent_type_exports; pub mod consistent_type_imports; pub mod explicit_function_return_type; pub mod explicit_module_boundary_types; diff --git a/crates/oxc_linter/src/rules/typescript/consistent_type_exports.rs b/crates/oxc_linter/src/rules/typescript/consistent_type_exports.rs new file mode 100644 index 0000000000000..77a2a7a7e12f8 --- /dev/null +++ b/crates/oxc_linter/src/rules/typescript/consistent_type_exports.rs @@ -0,0 +1,59 @@ +use oxc_macros::declare_oxc_lint; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; + +use crate::rule::{DefaultRuleConfig, Rule}; + +#[derive(Debug, Default, Clone, Deserialize)] +pub struct ConsistentTypeExports(Box); + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema, Default)] +#[serde(rename_all = "camelCase", default, deny_unknown_fields)] +pub struct ConsistentTypeExportsConfig { + /// Enables an autofix strategy that rewrites mixed exports using inline `type` specifiers. + pub fix_mixed_exports_with_inline_type_specifier: bool, +} + +declare_oxc_lint!( + /// ### What it does + /// + /// Enforce using `export type` for exports that are only used as types. + /// + /// ### Why is this bad? + /// + /// Mixing type-only exports with value exports without `export type` makes module intent + /// harder to read and can cause unnecessary runtime export surface. + /// + /// ### Examples + /// + /// Examples of **incorrect** code for this rule: + /// ```ts + /// type Foo = { bar: string }; + /// export { Foo }; + /// + /// export { TypeOnly, value } from "./mod"; + /// ``` + /// + /// Examples of **correct** code for this rule: + /// ```ts + /// type Foo = { bar: string }; + /// export type { Foo }; + /// + /// export type { TypeOnly } from "./mod"; + /// export { value } from "./mod"; + /// ``` + ConsistentTypeExports(tsgolint), + typescript, + nursery, + config = ConsistentTypeExportsConfig, +); + +impl Rule for ConsistentTypeExports { + fn from_configuration(value: serde_json::Value) -> Result { + serde_json::from_value::>(value).map(DefaultRuleConfig::into_inner) + } + + fn to_configuration(&self) -> Option> { + Some(serde_json::to_value(&*self.0)) + } +}