Skip to content
Draft
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"categories": {
"correctness": "off"
},
"linterOptions": {
"typeAware": false
},
"rules": {
"typescript/no-floating-promises": "off"
},
"overrides": [
{
"files": ["**/*.ts"],
"rules": {
"typescript/no-floating-promises": "error"
}
}
]
}
11 changes: 11 additions & 0 deletions apps/oxlint/fixtures/tsgolint/config-type-aware-false.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"categories": {
"correctness": "off"
},
"linterOptions": {
"typeAware": false
},
"rules": {
"typescript/no-floating-promises": "error"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"categories": {
"correctness": "off"
},
"linterOptions": {
"typeAware": true
},
"rules": {
"typescript/no-floating-promises": "off"
},
"overrides": [
{
"files": ["**/*.ts"],
"rules": {
"typescript/no-floating-promises": "error"
}
}
]
}
4 changes: 4 additions & 0 deletions apps/oxlint/fixtures/tsgolint/config-type-aware.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"linterOptions": { "typeAware": true },
"extends": ["./extended-config.json"]
}
1 change: 0 additions & 1 deletion apps/oxlint/src/command/lint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,6 @@ pub struct FixOptions {
/// Apply auto-fixable suggestions. May change program behavior.
#[bpaf(switch, hide_usage)]
pub fix_suggestions: bool,

/// Apply dangerous fixes and suggestions
#[bpaf(switch, hide_usage)]
pub fix_dangerously: bool,
Expand Down
59 changes: 57 additions & 2 deletions apps/oxlint/src/lint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,15 @@ impl CliRunner {

let config_store = ConfigStore::new(lint_config, nested_configs, external_plugin_store);

// Determine whether type-aware rules should be enabled.
// CLI flag has precedence; otherwise fall back to configuration file.
let effective_type_aware = if self.options.type_aware {
true
} else {
// ConfigStore::type_aware_enabled returns whether the base config requested it
config_store.type_aware_enabled()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that I gave type_aware the type Option because I intended to make it not effect nested config files, we can undo that if we want it to work for nested config files.

Nested Configs are the default. For me, it would be strange to only support it in the root config.
Example: Team X owns packages/package-X and they want to test type aware.
Team Y does not want type aware.
The extends should cover project wide configurations.

The Language server part should be here:

type_aware: options.type_aware,

};

// If the user requested `--rules`, print a CLI-specific table that
// includes an "Enabled?" column based on the resolved configuration.
if self.options.list_rules {
Expand Down Expand Up @@ -347,6 +356,7 @@ impl CliRunner {
.collect::<Vec<Arc<OsStr>>>();

let has_external_linter = external_linter.is_some();

let linter = Linter::new(LintOptions::default(), config_store, external_linter)
.with_fix(fix_options.fix_kind())
.with_report_unused_directives(report_unused_directives);
Expand Down Expand Up @@ -386,12 +396,12 @@ impl CliRunner {
}
}

let number_of_rules = linter.number_of_rules(self.options.type_aware);
let number_of_rules = linter.number_of_rules(effective_type_aware);

// Create the LintRunner
// TODO: Add a warning message if `tsgolint` cannot be found, but type-aware rules are enabled
let lint_runner = match LintRunner::builder(options, linter)
.with_type_aware(self.options.type_aware)
.with_type_aware(effective_type_aware)
.with_type_check(self.options.type_check)
.with_silent(misc_options.silent)
.with_fix_kind(fix_options.fix_kind())
Expand Down Expand Up @@ -1374,6 +1384,51 @@ mod test {
Tester::new().with_cwd("fixtures/tsgolint".into()).test_and_snapshot(args);
}

#[test]
#[cfg(not(target_endian = "big"))]
fn test_tsgolint_config_via_config_file() {
// config file should be able to enable type-aware linting without CLI flag
let args = &["-c", "config-type-aware.json"];
Tester::new().with_cwd("fixtures/tsgolint".into()).test_and_snapshot(args);
}

#[test]
#[cfg(not(target_endian = "big"))]
fn test_tsgolint_config_type_aware_applies_to_overrides() {
// top-level typeAware should enable type-aware rules for overrides as well
// The fixture sets the rule off globally and turns it on in an override for ts files.
let args = &["-c", "config-type-aware-with-overrides.json", "no-floating-promises.ts"];
Tester::new().with_cwd("fixtures/tsgolint".into()).test_and_snapshot(args);
}

#[test]
#[cfg(not(target_endian = "big"))]
fn test_tsgolint_config_type_aware_false() {
// When top-level typeAware is false, type-aware rules should be disabled.
let args = &["-c", "config-type-aware-false.json", "no-floating-promises.ts"];
Tester::new().with_cwd("fixtures/tsgolint".into()).test_and_snapshot(args);
}

#[test]
#[cfg(not(target_endian = "big"))]
fn test_tsgolint_config_type_aware_false_overridden_by_cli_flag() {
// If the config file sets `typeAware: false`, the CLI `--type-aware` flag should still
// be able to enable type-aware linting.
let args =
&["--type-aware", "-c", "config-type-aware-false.json", "no-floating-promises.ts"];
Tester::new().with_cwd("fixtures/tsgolint".into()).test_and_snapshot(args);
}

#[test]
#[cfg(not(target_endian = "big"))]
fn test_tsgolint_config_type_aware_false_disables_overrides() {
// When top-level typeAware is false, type-aware rules should be disabled
// even if an override sets the rule to error for *.ts files.
let args =
&["-c", "config-type-aware-false-with-overrides.json", "no-floating-promises.ts"];
Tester::new().with_cwd("fixtures/tsgolint".into()).test_and_snapshot(args);
}

#[test]
#[cfg(not(target_endian = "big"))]
fn test_tsgolint_type_error() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ working directory:
"builtin": true
},
"globals": {},
"linterOptions": {},
"ignorePatterns": []
}
----------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ working directory: fixtures
"builtin": true
},
"globals": {},
"linterOptions": {},
"ignorePatterns": []
}
----------
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
source: apps/oxlint/src/tester.rs
---
##########
arguments: --type-aware -c config-type-aware-false.json no-floating-promises.ts
working directory: fixtures/tsgolint
----------

x typescript-eslint(no-floating-promises): Promises must be awaited.
,-[no-floating-promises.ts:2:1]
1 | const promise = new Promise((resolve, _reject) => resolve("value"));
2 | promise;
: ^^^^^^^^
3 |
`----
help: The promise must end with a call to .catch, or end with a call to .then with a rejection handler, or be explicitly marked as ignored with the `void` operator.

Found 0 warnings and 1 error.
Finished in <variable>ms on 1 file with 1 rules using 1 threads.
----------
CLI result: LintFoundErrors
----------
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
source: apps/oxlint/src/tester.rs
---
##########
arguments: -c config-type-aware-false-with-overrides.json no-floating-promises.ts
working directory: fixtures/tsgolint
----------
Found 0 warnings and 0 errors.
Finished in <variable>ms on 1 file with 0 rules using 1 threads.
----------
CLI result: LintSucceeded
----------
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
source: apps/oxlint/src/tester.rs
---
##########
arguments: -c config-type-aware-false.json no-floating-promises.ts
working directory: fixtures/tsgolint
----------
Found 0 warnings and 0 errors.
Finished in <variable>ms on 1 file with 0 rules using 1 threads.
----------
CLI result: LintSucceeded
----------
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
source: apps/oxlint/src/tester.rs
---
##########
arguments: -c config-type-aware-with-overrides.json no-floating-promises.ts
working directory: fixtures/tsgolint
----------

x typescript-eslint(no-floating-promises): Promises must be awaited.
,-[no-floating-promises.ts:2:1]
1 | const promise = new Promise((resolve, _reject) => resolve("value"));
2 | promise;
: ^^^^^^^^
3 |
`----
help: The promise must end with a call to .catch, or end with a call to .then with a rejection handler, or be explicitly marked as ignored with the `void` operator.

Found 0 warnings and 1 error.
Finished in <variable>ms on 1 file with 0 rules using 1 threads.
----------
CLI result: LintFoundErrors
----------
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
---
source: apps/oxlint/src/tester.rs
---
##########
arguments: -c config-type-aware.json
working directory: fixtures/tsgolint
----------

! typescript-eslint(no-floating-promises): Promises must be awaited.
,-[no-floating-promises.ts:2:1]
1 | const promise = new Promise((resolve, _reject) => resolve("value"));
2 | promise;
: ^^^^^^^^
3 |
`----
help: The promise must end with a call to .catch, or end with a call to .then with a rejection handler, or be explicitly marked as ignored with the `void` operator.

x ]8;;https://oxc.rs/docs/guide/usage/linter/rules/eslint/no-debugger.html\eslint(no-debugger)]8;;\: `debugger` statement is not allowed
,-[non-tsgolint.ts:1:1]
1 | debugger;
: ^^^^^^^^^
2 |
`----
help: Remove the debugger statement

! typescript-eslint(no-floating-promises): Promises must be awaited.
,-[prefer-promise-reject-errors.ts:1:1]
1 | Promise.reject('error');
: ^^^^^^^^^^^^^^^^^^^^^^^^
`----
help: The promise must end with a call to .catch, or end with a call to .then with a rejection handler, or be explicitly marked as ignored with the `void` operator.

x ]8;;https://oxc.rs/docs/guide/usage/linter/rules/eslint/no-debugger.html\eslint(no-debugger)]8;;\: `debugger` statement is not allowed
,-[test.svelte:2:2]
1 | <script>
2 | debugger;
: ^^^^^^^^^
3 |
`----
help: Remove the debugger statement

Found 2 warnings and 2 errors.
Finished in <variable>ms on 44 files with 1 rules using 1 threads.
----------
CLI result: LintFoundErrors
----------
1 change: 1 addition & 0 deletions crates/oxc_linter/src/config/config_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ impl ConfigStoreBuilder {
env: oxlintrc.env,
globals: oxlintrc.globals,
path: Some(oxlintrc.path),
linter_options: oxlintrc.linter_options,
};

let mut builder = Self {
Expand Down
8 changes: 8 additions & 0 deletions crates/oxc_linter/src/config/config_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,11 @@ impl ConfigStore {
self.base.base.config.plugins
}

/// Whether the base configuration has type-aware rules enabled.
pub fn type_aware_enabled(&self) -> bool {
self.base.base.config.linter_options.type_aware.unwrap_or(false)
}

pub(crate) fn get_related_config(&self, path: &Path) -> &Config {
if self.nested_configs.is_empty() {
&self.base
Expand Down Expand Up @@ -778,6 +783,7 @@ mod test {
settings: OxlintSettings::default(),
globals: OxlintGlobals::default(),
path: None,
..Default::default()
};

// Set up categories to enable restriction rules
Expand Down Expand Up @@ -865,6 +871,7 @@ mod test {
settings: OxlintSettings::default(),
globals: OxlintGlobals::default(),
path: None,
..Default::default()
};

// Set up categories
Expand Down Expand Up @@ -969,6 +976,7 @@ mod test {
settings: OxlintSettings::default(),
globals: OxlintGlobals::default(),
path: None,
..Default::default()
};

// Set up categories
Expand Down
5 changes: 5 additions & 0 deletions crates/oxc_linter/src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ pub use plugins::LintPlugins;
pub use rules::{ESLintRule, OxlintRules};
pub use settings::{OxlintSettings, jsdoc::JSDocPluginSettings};

use crate::config::oxlintrc::LinterOptions;

#[derive(Debug, Default, Clone)]
pub struct LintConfig {
pub(crate) plugins: LintPlugins,
Expand All @@ -32,6 +34,8 @@ pub struct LintConfig {
pub(crate) globals: OxlintGlobals,
/// Absolute path to the configuration file (may be `None` if there is no file).
pub(crate) path: Option<PathBuf>,
/// Options for controlling linter behavior.
pub(crate) linter_options: LinterOptions,
}

impl From<Oxlintrc> for LintConfig {
Expand All @@ -42,6 +46,7 @@ impl From<Oxlintrc> for LintConfig {
env: config.env,
globals: config.globals,
path: Some(config.path),
linter_options: config.linter_options,
}
}
}
Expand Down
Loading
Loading