Skip to content

Commit ad27fd6

Browse files
authored
fix(linter): add help messages to import plugin diagnostics (#20158)
## Summary Add `.with_help()` messages to 5 import lint rules that were missing actionable guidance: - `exports-last`: "Move this export to the end of the file, after all other statements." - `no-absolute-path`: "Replace the absolute path with a relative path or a module alias." - `no-default-export`: "Replace this default export with a named export." - `no-mutable-exports`: Dynamic per violation — "Replace 'let'/'var' with 'const' to export an immutable binding." - `no-self-import`: "Remove this import. A module should not import itself." Part of #19121 **AI Disclosure:** AI-assisted per contribution guidelines. ## Test Plan - [x] All 33 import rule tests pass (`cargo test -p oxc_linter --lib -- "::import::"`) - [x] Snapshots regenerated via `cargo insta accept` - [x] Help messages are actionable and match the specificity of their corresponding warnings
1 parent 542a04a commit ad27fd6

11 files changed

+62
-5
lines changed

apps/oxlint/src/snapshots/fixtures__cli__import_-c .oxlintrc.json test.js -c .oxlintrc-import-x.json [email protected]

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ working directory: fixtures/cli/import
1313
: ^^^^^^^
1414
8 |
1515
`----
16+
help: Replace this default export with a named export.
1617
1718
Found 0 warnings and 1 error.
1819
Finished in <variable>ms on 1 file with 1 rules using 1 threads.
@@ -32,6 +33,7 @@ working directory: fixtures/cli/import
3233
: ^^^^^^^
3334
8 |
3435
`----
36+
help: Replace this default export with a named export.
3537
3638
Found 0 warnings and 1 error.
3739
Finished in <variable>ms on 1 file with 1 rules using 1 threads.

crates/oxc_linter/src/rules/import/exports_last.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ use crate::{context::LintContext, rule::Rule};
88

99
fn exports_last_diagnostic(span: Span) -> OxcDiagnostic {
1010
// See <https://oxc.rs/docs/contribute/linter/adding-rules.html#diagnostics> for details
11-
OxcDiagnostic::warn("Export statements should appear at the end of the file").with_label(span)
11+
OxcDiagnostic::warn("Export statements should appear at the end of the file")
12+
.with_help("Move this export to the end of the file, after all other statements.")
13+
.with_label(span)
1214
}
1315

1416
#[derive(Debug, Default, Clone)]

crates/oxc_linter/src/rules/import/no_absolute_path.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ use crate::{
1919
};
2020

2121
fn no_absolute_path_diagnostic(span: Span) -> OxcDiagnostic {
22-
OxcDiagnostic::warn("Do not import modules using an absolute path").with_label(span)
22+
OxcDiagnostic::warn("Do not import modules using an absolute path")
23+
.with_help("Replace the absolute path with a relative path or a module alias.")
24+
.with_label(span)
2325
}
2426

2527
// <https://github.com/import-js/eslint-plugin-import/blob/v2.31.0/docs/rules/no-absolute-path.md>

crates/oxc_linter/src/rules/import/no_default_export.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ use oxc_span::Span;
55
use crate::{context::LintContext, rule::Rule};
66

77
fn no_default_export_diagnostic(span: Span) -> OxcDiagnostic {
8-
OxcDiagnostic::warn("Prefer named exports").with_label(span)
8+
OxcDiagnostic::warn("Prefer named exports")
9+
.with_help("Replace this default export with a named export.")
10+
.with_label(span)
911
}
1012

1113
#[derive(Debug, Default, Clone)]

crates/oxc_linter/src/rules/import/no_mutable_exports.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use crate::{context::LintContext, rule::Rule};
1414
fn no_mutable_exports_diagnostic(span: Span, kind: VariableDeclarationKind) -> OxcDiagnostic {
1515
let kind_str = if kind == VariableDeclarationKind::Var { "var" } else { "let" };
1616
OxcDiagnostic::warn(format!("Exporting mutable '{kind_str}' binding, use 'const' instead."))
17+
.with_help(format!("Replace '{kind_str}' with 'const' to export an immutable binding."))
1718
.with_label(span)
1819
}
1920

crates/oxc_linter/src/rules/import/no_self_import.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ use oxc_span::Span;
55
use crate::{context::LintContext, rule::Rule};
66

77
fn no_self_import_diagnostic(span: Span) -> OxcDiagnostic {
8-
OxcDiagnostic::warn("A module importing itself is not allowed").with_label(span)
8+
OxcDiagnostic::warn("A module importing itself is not allowed")
9+
.with_help("Remove this import. A module should not import itself.")
10+
.with_label(span)
911
}
1012

1113
#[derive(Debug, Default, Clone)]
@@ -90,7 +92,7 @@ fn test() {
9092
Tester::new(NoSelfImport::NAME, NoSelfImport::PLUGIN, pass, fail)
9193
.with_import_plugin(true)
9294
.change_rule_path("no-self-import.js")
93-
.test();
95+
.test_and_snapshot();
9496
}
9597

9698
// {

crates/oxc_linter/src/snapshots/import_exports_last.snap

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ source: crates/oxc_linter/src/tester.rs
99
· ───────────────────
1010
4const str = 'foo'
1111
╰────
12+
help: Move this export to the end of the file, after all other statements.
1213

1314
eslint-plugin-import(exports-last): Export statements should appear at the end of the file
1415
╭─[exports_last.tsx:2:13]
@@ -17,6 +18,7 @@ source: crates/oxc_linter/src/tester.rs
1718
· ────────────────────────
1819
3const str = 'foo'
1920
╰────
21+
help: Move this export to the end of the file, after all other statements.
2022

2123
eslint-plugin-import(exports-last): Export statements should appear at the end of the file
2224
╭─[exports_last.tsx:2:13]
@@ -25,6 +27,7 @@ source: crates/oxc_linter/src/tester.rs
2527
· ────────────────────────
2628
3const bar = true
2729
╰────
30+
help: Move this export to the end of the file, after all other statements.
2831

2932
eslint-plugin-import(exports-last): Export statements should appear at the end of the file
3033
╭─[exports_last.tsx:2:13]
@@ -33,6 +36,7 @@ source: crates/oxc_linter/src/tester.rs
3336
· ──────────────────────────────────
3437
3export const so = 'many'
3538
╰────
39+
help: Move this export to the end of the file, after all other statements.
3640

3741
eslint-plugin-import(exports-last): Export statements should appear at the end of the file
3842
╭─[exports_last.tsx:3:13]
@@ -41,6 +45,7 @@ source: crates/oxc_linter/src/tester.rs
4145
· ────────────────────────
4246
4const foo = 'bar'
4347
╰────
48+
help: Move this export to the end of the file, after all other statements.
4449

4550
eslint-plugin-import(exports-last): Export statements should appear at the end of the file
4651
╭─[exports_last.tsx:2:13]
@@ -49,3 +54,4 @@ source: crates/oxc_linter/src/tester.rs
4954
· ───────────────────────────────
5055
3const bar = true
5156
╰────
57+
help: Move this export to the end of the file, after all other statements.

crates/oxc_linter/src/snapshots/import_no_absolute_path.snap

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,69 +7,81 @@ source: crates/oxc_linter/src/tester.rs
77
1import _ from '/lodash'
88
· ─────────
99
╰────
10+
help: Replace the absolute path with a relative path or a module alias.
1011

1112
eslint-plugin-import(no-absolute-path): Do not import modules using an absolute path
1213
╭─[index.js:1:15]
1314
1import _ from '/lodash'
1415
· ─────────
1516
╰────
17+
help: Replace the absolute path with a relative path or a module alias.
1618

1719
eslint-plugin-import(no-absolute-path): Do not import modules using an absolute path
1820
╭─[index.js:1:15]
1921
1import f from '/foo/path'
2022
· ───────────
2123
╰────
24+
help: Replace the absolute path with a relative path or a module alias.
2225

2326
eslint-plugin-import(no-absolute-path): Do not import modules using an absolute path
2427
╭─[index.js:1:15]
2528
1import f from '/foo/bar/baz.js'
2629
· ─────────────────
2730
╰────
31+
help: Replace the absolute path with a relative path or a module alias.
2832

2933
eslint-plugin-import(no-absolute-path): Do not import modules using an absolute path
3034
╭─[index.js:1:19]
3135
1var foo = require('/foo')
3236
· ──────
3337
╰────
38+
help: Replace the absolute path with a relative path or a module alias.
3439

3540
eslint-plugin-import(no-absolute-path): Do not import modules using an absolute path
3641
╭─[index.js:1:17]
3742
1var f = require('/foo/some')
3843
· ───────────
3944
╰────
45+
help: Replace the absolute path with a relative path or a module alias.
4046

4147
eslint-plugin-import(no-absolute-path): Do not import modules using an absolute path
4248
╭─[index.js:1:17]
4349
1var f = require('/foo/some/add')
4450
· ───────────────
4551
╰────
52+
help: Replace the absolute path with a relative path or a module alias.
4653

4754
eslint-plugin-import(no-absolute-path): Do not import modules using an absolute path
4855
╭─[index.js:1:10]
4956
1require(['/foo'], function(){})
5057
· ──────
5158
╰────
59+
help: Replace the absolute path with a relative path or a module alias.
5260

5361
eslint-plugin-import(no-absolute-path): Do not import modules using an absolute path
5462
╭─[index.js:1:19]
5563
1require(['./foo', '/boo'], function(){})
5664
· ──────
5765
╰────
66+
help: Replace the absolute path with a relative path or a module alias.
5867

5968
eslint-plugin-import(no-absolute-path): Do not import modules using an absolute path
6069
╭─[index.js:1:10]
6170
1require(['/foo', '/boo'], function(){})
6271
· ──────
6372
╰────
73+
help: Replace the absolute path with a relative path or a module alias.
6474

6575
eslint-plugin-import(no-absolute-path): Do not import modules using an absolute path
6676
╭─[index.js:1:18]
6777
1require(['/foo', '/boo'], function(){})
6878
· ──────
6979
╰────
80+
help: Replace the absolute path with a relative path or a module alias.
7081

7182
eslint-plugin-import(no-absolute-path): Do not import modules using an absolute path
7283
╭─[index.js:1:9]
7384
1define(['/foo'], function(){})
7485
· ──────
7586
╰────
87+
help: Replace the absolute path with a relative path or a module alias.

crates/oxc_linter/src/snapshots/import_no_default_export.snap

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,34 +7,40 @@ source: crates/oxc_linter/src/tester.rs
77
1export default function bar() {};
88
· ───────
99
╰────
10+
help: Replace this default export with a named export.
1011

1112
eslint-plugin-import(no-default-export): Prefer named exports
1213
╭─[index.ts:2:8]
1314
1export const foo = 'foo';
1415
2export default bar;
1516
· ───────
1617
╰────
18+
help: Replace this default export with a named export.
1719

1820
eslint-plugin-import(no-default-export): Prefer named exports
1921
╭─[index.ts:1:8]
2022
1export default class Bar {};
2123
· ───────
2224
╰────
25+
help: Replace this default export with a named export.
2326

2427
eslint-plugin-import(no-default-export): Prefer named exports
2528
╭─[index.ts:1:8]
2629
1export default function() {};
2730
· ───────
2831
╰────
32+
help: Replace this default export with a named export.
2933

3034
eslint-plugin-import(no-default-export): Prefer named exports
3135
╭─[index.ts:1:8]
3236
1export default class {};
3337
· ───────
3438
╰────
39+
help: Replace this default export with a named export.
3540

3641
eslint-plugin-import(no-default-export): Prefer named exports
3742
╭─[index.ts:1:26]
3843
1let foo; export { foo as default }
3944
· ───────
4045
╰────
46+
help: Replace this default export with a named export.

crates/oxc_linter/src/snapshots/import_no_mutable_exports.snap

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,14 @@ source: crates/oxc_linter/src/tester.rs
77
1export let count = 1
88
· ─────────────
99
╰────
10+
help: Replace 'let' with 'const' to export an immutable binding.
1011

1112
eslint-plugin-import(no-mutable-exports): Exporting mutable 'var' binding, use 'const' instead.
1213
╭─[no_mutable_exports.tsx:1:8]
1314
1export var count = 1
1415
· ─────────────
1516
╰────
17+
help: Replace 'var' with 'const' to export an immutable binding.
1618

1719
eslint-plugin-import(no-mutable-exports): Exporting mutable 'let' binding, use 'const' instead.
1820
╭─[no_mutable_exports.tsx:2:13]
@@ -21,12 +23,14 @@ source: crates/oxc_linter/src/tester.rs
2123
· ────────────
2224
3export { foo }
2325
╰────
26+
help: Replace 'let' with 'const' to export an immutable binding.
2427

2528
eslint-plugin-import(no-mutable-exports): Exporting mutable 'let' binding, use 'const' instead.
2629
╭─[no_mutable_exports.tsx:1:1]
2730
1let foo = 4, baz = 5; export { foo }
2831
· ─────────────────────
2932
╰────
33+
help: Replace 'let' with 'const' to export an immutable binding.
3034

3135
eslint-plugin-import(no-mutable-exports): Exporting mutable 'var' binding, use 'const' instead.
3236
╭─[no_mutable_exports.tsx:2:13]
@@ -35,6 +39,7 @@ source: crates/oxc_linter/src/tester.rs
3539
· ────────────
3640
3export { foo }
3741
╰────
42+
help: Replace 'var' with 'const' to export an immutable binding.
3843

3944
eslint-plugin-import(no-mutable-exports): Exporting mutable 'let' binding, use 'const' instead.
4045
╭─[no_mutable_exports.tsx:2:13]
@@ -43,6 +48,7 @@ source: crates/oxc_linter/src/tester.rs
4348
· ────────────
4449
3export { foo as baz }
4550
╰────
51+
help: Replace 'let' with 'const' to export an immutable binding.
4652

4753
eslint-plugin-import(no-mutable-exports): Exporting mutable 'var' binding, use 'const' instead.
4854
╭─[no_mutable_exports.tsx:2:13]
@@ -51,6 +57,7 @@ source: crates/oxc_linter/src/tester.rs
5157
· ────────────
5258
3export { foo as baz }
5359
╰────
60+
help: Replace 'var' with 'const' to export an immutable binding.
5461

5562
eslint-plugin-import(no-mutable-exports): Exporting mutable 'let' binding, use 'const' instead.
5663
╭─[no_mutable_exports.tsx:2:13]
@@ -59,6 +66,7 @@ source: crates/oxc_linter/src/tester.rs
5966
· ────────────
6067
3export default foo
6168
╰────
69+
help: Replace 'let' with 'const' to export an immutable binding.
6270

6371
eslint-plugin-import(no-mutable-exports): Exporting mutable 'var' binding, use 'const' instead.
6472
╭─[no_mutable_exports.tsx:2:13]
@@ -67,6 +75,7 @@ source: crates/oxc_linter/src/tester.rs
6775
· ────────────
6876
3export default foo
6977
╰────
78+
help: Replace 'var' with 'const' to export an immutable binding.
7079

7180
eslint-plugin-import(no-mutable-exports): Exporting mutable 'let' binding, use 'const' instead.
7281
╭─[no_mutable_exports.tsx:3:13]
@@ -75,6 +84,7 @@ source: crates/oxc_linter/src/tester.rs
7584
· ──────────
7685
4export {
7786
╰────
87+
help: Replace 'let' with 'const' to export an immutable binding.
7888

7989
eslint-plugin-import(no-mutable-exports): Exporting mutable 'var' binding, use 'const' instead.
8090
╭─[no_mutable_exports.tsx:2:13]
@@ -83,6 +93,7 @@ source: crates/oxc_linter/src/tester.rs
8393
· ──────────
8494
3 │ let c = 3;
8595
╰────
96+
help: Replace 'var' with 'const' to export an immutable binding.
8697

8798
eslint-plugin-import(no-mutable-exports): Exporting mutable 'let' binding, use 'const' instead.
8899
╭─[no_mutable_exports.tsx:2:13]
@@ -91,3 +102,4 @@ source: crates/oxc_linter/src/tester.rs
91102
· ─────────────────
92103
3 │ export {
93104
╰────
105+
help: Replace 'let' with 'const' to export an immutable binding.

0 commit comments

Comments
 (0)