diff --git a/apps/oxlint/fixtures/tsgolint/config-type-aware-false-with-overrides.json b/apps/oxlint/fixtures/tsgolint/config-type-aware-false-with-overrides.json new file mode 100644 index 0000000000000..6f9ad3eb8d269 --- /dev/null +++ b/apps/oxlint/fixtures/tsgolint/config-type-aware-false-with-overrides.json @@ -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" + } + } + ] +} diff --git a/apps/oxlint/fixtures/tsgolint/config-type-aware-false.json b/apps/oxlint/fixtures/tsgolint/config-type-aware-false.json new file mode 100644 index 0000000000000..f4cec540f8a99 --- /dev/null +++ b/apps/oxlint/fixtures/tsgolint/config-type-aware-false.json @@ -0,0 +1,11 @@ +{ + "categories": { + "correctness": "off" + }, + "linterOptions": { + "typeAware": false + }, + "rules": { + "typescript/no-floating-promises": "error" + } +} diff --git a/apps/oxlint/fixtures/tsgolint/config-type-aware-with-overrides.json b/apps/oxlint/fixtures/tsgolint/config-type-aware-with-overrides.json new file mode 100644 index 0000000000000..fe4f1604450b0 --- /dev/null +++ b/apps/oxlint/fixtures/tsgolint/config-type-aware-with-overrides.json @@ -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" + } + } + ] +} diff --git a/apps/oxlint/fixtures/tsgolint/config-type-aware.json b/apps/oxlint/fixtures/tsgolint/config-type-aware.json new file mode 100644 index 0000000000000..ac39ba6329b04 --- /dev/null +++ b/apps/oxlint/fixtures/tsgolint/config-type-aware.json @@ -0,0 +1,4 @@ +{ + "linterOptions": { "typeAware": true }, + "extends": ["./extended-config.json"] +} diff --git a/apps/oxlint/src/command/lint.rs b/apps/oxlint/src/command/lint.rs index 84d9055ef95bb..e03c33b782d37 100644 --- a/apps/oxlint/src/command/lint.rs +++ b/apps/oxlint/src/command/lint.rs @@ -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, diff --git a/apps/oxlint/src/lint.rs b/apps/oxlint/src/lint.rs index d640460601a88..1d87bb0670a98 100644 --- a/apps/oxlint/src/lint.rs +++ b/apps/oxlint/src/lint.rs @@ -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() + }; + // 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 { @@ -347,6 +356,7 @@ impl CliRunner { .collect::>>(); 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); @@ -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()) @@ -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() { diff --git a/apps/oxlint/src/snapshots/_-c fixtures__print_config__ban_rules__eslintrc.json -A all -D eqeqeq --print-config@oxlint.snap b/apps/oxlint/src/snapshots/_-c fixtures__print_config__ban_rules__eslintrc.json -A all -D eqeqeq --print-config@oxlint.snap index 780b9380322a0..1c911a9c704c7 100644 --- a/apps/oxlint/src/snapshots/_-c fixtures__print_config__ban_rules__eslintrc.json -A all -D eqeqeq --print-config@oxlint.snap +++ b/apps/oxlint/src/snapshots/_-c fixtures__print_config__ban_rules__eslintrc.json -A all -D eqeqeq --print-config@oxlint.snap @@ -51,6 +51,7 @@ working directory: "builtin": true }, "globals": {}, + "linterOptions": {}, "ignorePatterns": [] } ---------- diff --git a/apps/oxlint/src/snapshots/fixtures_-A all --print-config@oxlint.snap b/apps/oxlint/src/snapshots/fixtures_-A all --print-config@oxlint.snap index f41f2fb609c49..c9fbe34652dae 100644 --- a/apps/oxlint/src/snapshots/fixtures_-A all --print-config@oxlint.snap +++ b/apps/oxlint/src/snapshots/fixtures_-A all --print-config@oxlint.snap @@ -44,6 +44,7 @@ working directory: fixtures "builtin": true }, "globals": {}, + "linterOptions": {}, "ignorePatterns": [] } ---------- diff --git a/apps/oxlint/src/snapshots/fixtures__tsgolint_--type-aware -c config-type-aware-false.json no-floating-promises.ts@oxlint.snap b/apps/oxlint/src/snapshots/fixtures__tsgolint_--type-aware -c config-type-aware-false.json no-floating-promises.ts@oxlint.snap new file mode 100644 index 0000000000000..19deb89462933 --- /dev/null +++ b/apps/oxlint/src/snapshots/fixtures__tsgolint_--type-aware -c config-type-aware-false.json no-floating-promises.ts@oxlint.snap @@ -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 ms on 1 file with 1 rules using 1 threads. +---------- +CLI result: LintFoundErrors +---------- diff --git a/apps/oxlint/src/snapshots/fixtures__tsgolint_-c config-type-aware-false-with-overrides.json no-floating-promises.ts@oxlint.snap b/apps/oxlint/src/snapshots/fixtures__tsgolint_-c config-type-aware-false-with-overrides.json no-floating-promises.ts@oxlint.snap new file mode 100644 index 0000000000000..7f698f9b385e0 --- /dev/null +++ b/apps/oxlint/src/snapshots/fixtures__tsgolint_-c config-type-aware-false-with-overrides.json no-floating-promises.ts@oxlint.snap @@ -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 ms on 1 file with 0 rules using 1 threads. +---------- +CLI result: LintSucceeded +---------- diff --git a/apps/oxlint/src/snapshots/fixtures__tsgolint_-c config-type-aware-false.json no-floating-promises.ts@oxlint.snap b/apps/oxlint/src/snapshots/fixtures__tsgolint_-c config-type-aware-false.json no-floating-promises.ts@oxlint.snap new file mode 100644 index 0000000000000..4fe0f60050a6f --- /dev/null +++ b/apps/oxlint/src/snapshots/fixtures__tsgolint_-c config-type-aware-false.json no-floating-promises.ts@oxlint.snap @@ -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 ms on 1 file with 0 rules using 1 threads. +---------- +CLI result: LintSucceeded +---------- diff --git a/apps/oxlint/src/snapshots/fixtures__tsgolint_-c config-type-aware-with-overrides.json no-floating-promises.ts@oxlint.snap b/apps/oxlint/src/snapshots/fixtures__tsgolint_-c config-type-aware-with-overrides.json no-floating-promises.ts@oxlint.snap new file mode 100644 index 0000000000000..944ecc0b0c92e --- /dev/null +++ b/apps/oxlint/src/snapshots/fixtures__tsgolint_-c config-type-aware-with-overrides.json no-floating-promises.ts@oxlint.snap @@ -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 ms on 1 file with 0 rules using 1 threads. +---------- +CLI result: LintFoundErrors +---------- diff --git a/apps/oxlint/src/snapshots/fixtures__tsgolint_-c config-type-aware.json@oxlint.snap b/apps/oxlint/src/snapshots/fixtures__tsgolint_-c config-type-aware.json@oxlint.snap new file mode 100644 index 0000000000000..6941bba5004fe --- /dev/null +++ b/apps/oxlint/src/snapshots/fixtures__tsgolint_-c config-type-aware.json@oxlint.snap @@ -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 |