Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions apps/oxlint/fixtures/tsgolint/.oxlintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
7 changes: 7 additions & 0 deletions apps/oxlint/fixtures/tsgolint/consistent-type-exports.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
type LocalType = {
value: string;
};

const localValue = 1;

export { LocalType, localValue };
6 changes: 6 additions & 0 deletions apps/oxlint/fixtures/tsgolint_rule_options/.oxlintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,12 @@
"checkTypePredicates": false,
}
],
"typescript/consistent-type-exports": [
"error",
{
"fixMixedExportsWithInlineTypeSpecifier": true
}
],
"typescript/only-throw-error": [
"error",
{
Expand Down
6 changes: 6 additions & 0 deletions apps/oxlint/fixtures/tsgolint_rule_options/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ arguments: --type-aware --silent
working directory: fixtures/tsgolint
----------

Found 0 warnings and 57 errors.
Finished in <variable>ms on 47 files with 46 rules using 1 threads.
Found 0 warnings and 58 errors.
Finished in <variable>ms on 48 files with 47 rules using 1 threads.
----------
CLI result: LintFoundErrors
----------
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ working directory: fixtures/tsgolint
help: Remove the debugger statement

Found 2 warnings and 2 errors.
Finished in <variable>ms on 47 files with 1 rules using 1 threads.
Finished in <variable>ms on 48 files with 1 rules using 1 threads.
----------
CLI result: LintFoundErrors
----------
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ working directory: fixtures/tsgolint
help: Remove the debugger statement

Found 0 warnings and 1 error.
Finished in <variable>ms on 1 file with 46 rules using 1 threads.
Finished in <variable>ms on 1 file with 47 rules using 1 threads.
----------
CLI result: LintFoundErrors
----------
Original file line number Diff line number Diff line change
Expand Up @@ -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[];
Expand Down Expand Up @@ -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 <variable>ms on 47 files with 46 rules using 1 threads.
Found 0 warnings and 58 errors.
Finished in <variable>ms on 48 files with 47 rules using 1 threads.
----------
CLI result: LintFoundErrors
----------
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,16 @@ working directory: fixtures/tsgolint_rule_options
69 | result += 1;
`----

Found 0 warnings and 5 errors.
Finished in <variable>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 <variable>ms on 1 file with 9 rules using 1 threads.
----------
CLI result: LintFoundErrors
----------
5 changes: 5 additions & 0 deletions crates/oxc_linter/src/generated/rule_runner_impls.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

32 changes: 31 additions & 1 deletion crates/oxc_linter/src/generated/rules_enum.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/oxc_linter/src/rules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
@@ -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<ConsistentTypeExportsConfig>);

#[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<Self, serde_json::error::Error> {
serde_json::from_value::<DefaultRuleConfig<Self>>(value).map(DefaultRuleConfig::into_inner)
}

fn to_configuration(&self) -> Option<Result<serde_json::Value, serde_json::Error>> {
Some(serde_json::to_value(&*self.0))
}
}
Loading