diff --git a/crates/oxc_linter/src/rules/import/export.rs b/crates/oxc_linter/src/rules/import/export.rs index 9e02886638051..9612f94854589 100644 --- a/crates/oxc_linter/src/rules/import/export.rs +++ b/crates/oxc_linter/src/rules/import/export.rs @@ -10,6 +10,7 @@ use crate::{ModuleRecord, context::LintContext, rule::Rule}; fn no_named_export(module_name: &str, span: Span) -> OxcDiagnostic { OxcDiagnostic::warn(format!("No named exports found in module '{module_name}'")) + .with_help("Remove the `export *` re-export, or add named exports to the target module.") .with_label(span) } @@ -93,6 +94,7 @@ impl Rule for Export { ctx.diagnostic( OxcDiagnostic::warn(format!("Multiple exports of name '{name}'.")) + .with_help("Rename or remove the duplicate export so each name is exported only once.") .with_labels(labels), ); } diff --git a/crates/oxc_linter/src/rules/import/namespace.rs b/crates/oxc_linter/src/rules/import/namespace.rs index a9965cb44f43d..1a56fc00f1aa8 100644 --- a/crates/oxc_linter/src/rules/import/namespace.rs +++ b/crates/oxc_linter/src/rules/import/namespace.rs @@ -39,11 +39,13 @@ fn computed_reference(span: Span, namespace_name: &str) -> OxcDiagnostic { OxcDiagnostic::warn(format!( "Unable to validate computed reference to imported namespace {namespace_name:?}." )) + .with_help("Use a static property access (e.g. `namespace.name`) instead of a computed one.") .with_label(span) } fn assignment(span: Span, namespace_name: &str) -> OxcDiagnostic { OxcDiagnostic::warn(format!("Assignment to member of namespace {namespace_name:?}.'")) + .with_help("Imported namespace members are read-only. Assign to a local variable instead.") .with_label(span) } diff --git a/crates/oxc_linter/src/rules/import/no_anonymous_default_export.rs b/crates/oxc_linter/src/rules/import/no_anonymous_default_export.rs index f4b5b715d126e..ccc5c83ec21ef 100644 --- a/crates/oxc_linter/src/rules/import/no_anonymous_default_export.rs +++ b/crates/oxc_linter/src/rules/import/no_anonymous_default_export.rs @@ -16,8 +16,9 @@ use crate::{ }; fn no_anonymous_default_export_diagnostic(span: Span, msg: &'static str) -> OxcDiagnostic { - // See for details - OxcDiagnostic::warn(msg).with_label(span) + OxcDiagnostic::warn(msg) + .with_note("Named default exports improve grepability and enable consistent auto-imports across the codebase.") + .with_label(span) } #[derive(Debug, Clone, JsonSchema, Deserialize)] diff --git a/crates/oxc_linter/src/rules/import/no_nodejs_modules.rs b/crates/oxc_linter/src/rules/import/no_nodejs_modules.rs index e16fe21b76c64..38aad63be828c 100644 --- a/crates/oxc_linter/src/rules/import/no_nodejs_modules.rs +++ b/crates/oxc_linter/src/rules/import/no_nodejs_modules.rs @@ -18,6 +18,7 @@ use crate::{ fn no_nodejs_modules_diagnostic(span: Span, module_name: &str) -> OxcDiagnostic { OxcDiagnostic::warn(format!("Do not import Node.js builtin module `{module_name}`")) + .with_help("Use a browser-compatible alternative or add this module to the `allow` list if Node.js usage is intentional.") .with_label(span) } diff --git a/crates/oxc_linter/src/snapshots/import_export.snap b/crates/oxc_linter/src/snapshots/import_export.snap index f8435cbf225c3..83566cad3c5df 100644 --- a/crates/oxc_linter/src/snapshots/import_export.snap +++ b/crates/oxc_linter/src/snapshots/import_export.snap @@ -7,12 +7,14 @@ source: crates/oxc_linter/src/tester.rs 1 │ let foo; export { foo }; export * from "./export-all" · ─── ──────────────────────────── ╰──── + help: Rename or remove the duplicate export so each name is exported only once. ⚠ eslint-plugin-import(export): Multiple exports of name 'foo'. ╭─[index.ts:1:26] 1 │ let foo; export { foo as "foo" }; export * from "./export-all" · ───── ──────────────────────────── ╰──── + help: Rename or remove the duplicate export so each name is exported only once. × Identifier `Foo` has already been declared ╭─[index.ts:2:29] diff --git a/crates/oxc_linter/src/snapshots/import_namespace.snap b/crates/oxc_linter/src/snapshots/import_namespace.snap index 488f6aa24d171..a4ba11f68ae9e 100644 --- a/crates/oxc_linter/src/snapshots/import_namespace.snap +++ b/crates/oxc_linter/src/snapshots/import_namespace.snap @@ -13,18 +13,21 @@ source: crates/oxc_linter/src/tester.rs 1 │ import * as names from './named-exports'; console.log(names['a']); · ────────── ╰──── + help: Use a static property access (e.g. `namespace.name`) instead of a computed one. ⚠ eslint-plugin-import(namespace): Assignment to member of namespace "foo".' ╭─[index.js:1:31] 1 │ import * as foo from './bar'; foo.foo = 'y'; · ─────── ╰──── + help: Imported namespace members are read-only. Assign to a local variable instead. ⚠ eslint-plugin-import(namespace): Assignment to member of namespace "foo".' ╭─[index.js:1:31] 1 │ import * as foo from './bar'; foo.x = 'y'; · ───── ╰──── + help: Imported namespace members are read-only. Assign to a local variable instead. ⚠ eslint-plugin-import(namespace): "x" not found in imported namespace "./bar". ╭─[index.js:1:35] diff --git a/crates/oxc_linter/src/snapshots/import_no_anonymous_default_export.snap b/crates/oxc_linter/src/snapshots/import_no_anonymous_default_export.snap index 4aacc128e7b51..b1477745e5869 100644 --- a/crates/oxc_linter/src/snapshots/import_no_anonymous_default_export.snap +++ b/crates/oxc_linter/src/snapshots/import_no_anonymous_default_export.snap @@ -7,57 +7,67 @@ source: crates/oxc_linter/src/tester.rs 1 │ export default [] · ───────────────── ╰──── + note: Named default exports improve grepability and enable consistent auto-imports across the codebase. ⚠ eslint-plugin-import(no-anonymous-default-export): Assign arrow function to a variable before exporting as module default ╭─[no_anonymous_default_export.tsx:1:1] 1 │ export default () => {} · ─────────────────────── ╰──── + note: Named default exports improve grepability and enable consistent auto-imports across the codebase. ⚠ eslint-plugin-import(no-anonymous-default-export): Unexpected default export of anonymous class ╭─[no_anonymous_default_export.tsx:1:1] 1 │ export default class {} · ─────────────────────── ╰──── + note: Named default exports improve grepability and enable consistent auto-imports across the codebase. ⚠ eslint-plugin-import(no-anonymous-default-export): Unexpected default export of anonymous function ╭─[no_anonymous_default_export.tsx:1:1] 1 │ export default function () {} · ───────────────────────────── ╰──── + note: Named default exports improve grepability and enable consistent auto-imports across the codebase. ⚠ eslint-plugin-import(no-anonymous-default-export): Assign call result to a variable before exporting as module default ╭─[no_anonymous_default_export.tsx:1:1] 1 │ export default foo(bar) · ─────────────────────── ╰──── + note: Named default exports improve grepability and enable consistent auto-imports across the codebase. ⚠ eslint-plugin-import(no-anonymous-default-export): Assign literal to a variable before exporting as module default ╭─[no_anonymous_default_export.tsx:1:1] 1 │ export default 123 · ────────────────── ╰──── + note: Named default exports improve grepability and enable consistent auto-imports across the codebase. ⚠ eslint-plugin-import(no-anonymous-default-export): Assign object to a variable before exporting as module default ╭─[no_anonymous_default_export.tsx:1:1] 1 │ export default {} · ───────────────── ╰──── + note: Named default exports improve grepability and enable consistent auto-imports across the codebase. ⚠ eslint-plugin-import(no-anonymous-default-export): Assign instance to a variable before exporting as module default ╭─[no_anonymous_default_export.tsx:1:1] 1 │ export default new Foo() · ──────────────────────── ╰──── + note: Named default exports improve grepability and enable consistent auto-imports across the codebase. ⚠ eslint-plugin-import(no-anonymous-default-export): Assign literal to a variable before exporting as module default ╭─[no_anonymous_default_export.tsx:1:1] 1 │ export default `foo` · ──────────────────── ╰──── + note: Named default exports improve grepability and enable consistent auto-imports across the codebase. ⚠ eslint-plugin-import(no-anonymous-default-export): Assign literal to a variable before exporting as module default ╭─[no_anonymous_default_export.tsx:1:1] 1 │ export default /^123/ · ───────────────────── ╰──── + note: Named default exports improve grepability and enable consistent auto-imports across the codebase. diff --git a/crates/oxc_linter/src/snapshots/import_no_nodejs_modules.snap b/crates/oxc_linter/src/snapshots/import_no_nodejs_modules.snap index ebbeaf5cda2c9..7d8ad1dc6f555 100644 --- a/crates/oxc_linter/src/snapshots/import_no_nodejs_modules.snap +++ b/crates/oxc_linter/src/snapshots/import_no_nodejs_modules.snap @@ -7,141 +7,165 @@ source: crates/oxc_linter/src/tester.rs 1 │ import path from "path" · ─────────────────────── ╰──── + help: Use a browser-compatible alternative or add this module to the `allow` list if Node.js usage is intentional. ⚠ eslint-plugin-import(no-nodejs-modules): Do not import Node.js builtin module `fs` ╭─[no_nodejs_modules.tsx:1:1] 1 │ import fs from "fs" · ─────────────────── ╰──── + help: Use a browser-compatible alternative or add this module to the `allow` list if Node.js usage is intentional. ⚠ eslint-plugin-import(no-nodejs-modules): Do not import Node.js builtin module `path` ╭─[no_nodejs_modules.tsx:1:12] 1 │ var path = require("path") · ─────────────── ╰──── + help: Use a browser-compatible alternative or add this module to the `allow` list if Node.js usage is intentional. ⚠ eslint-plugin-import(no-nodejs-modules): Do not import Node.js builtin module `fs` ╭─[no_nodejs_modules.tsx:1:10] 1 │ var fs = require("fs") · ───────────── ╰──── + help: Use a browser-compatible alternative or add this module to the `allow` list if Node.js usage is intentional. ⚠ eslint-plugin-import(no-nodejs-modules): Do not import Node.js builtin module `fs` ╭─[no_nodejs_modules.tsx:1:1] 1 │ import(`fs`) · ──────────── ╰──── + help: Use a browser-compatible alternative or add this module to the `allow` list if Node.js usage is intentional. ⚠ eslint-plugin-import(no-nodejs-modules): Do not import Node.js builtin module `fs` ╭─[no_nodejs_modules.tsx:1:1] 1 │ import fs from "fs" · ─────────────────── ╰──── + help: Use a browser-compatible alternative or add this module to the `allow` list if Node.js usage is intentional. ⚠ eslint-plugin-import(no-nodejs-modules): Do not import Node.js builtin module `crypto` ╭─[no_nodejs_modules.tsx:1:1] 1 │ import crypto from "crypto" · ─────────────────────────── ╰──── + help: Use a browser-compatible alternative or add this module to the `allow` list if Node.js usage is intentional. ⚠ eslint-plugin-import(no-nodejs-modules): Do not import Node.js builtin module `util` ╭─[no_nodejs_modules.tsx:1:1] 1 │ import("util") · ────────────── ╰──── + help: Use a browser-compatible alternative or add this module to the `allow` list if Node.js usage is intentional. ⚠ eslint-plugin-import(no-nodejs-modules): Do not import Node.js builtin module `fs` ╭─[no_nodejs_modules.tsx:1:1] 1 │ export * from "fs" · ────────────────── ╰──── + help: Use a browser-compatible alternative or add this module to the `allow` list if Node.js usage is intentional. ⚠ eslint-plugin-import(no-nodejs-modules): Do not import Node.js builtin module `node:path` ╭─[no_nodejs_modules.tsx:1:1] 1 │ import path from "node:path" · ──────────────────────────── ╰──── + help: Use a browser-compatible alternative or add this module to the `allow` list if Node.js usage is intentional. ⚠ eslint-plugin-import(no-nodejs-modules): Do not import Node.js builtin module `node:path` ╭─[no_nodejs_modules.tsx:1:12] 1 │ var path = require("node:path") · ──────────────────── ╰──── + help: Use a browser-compatible alternative or add this module to the `allow` list if Node.js usage is intentional. ⚠ eslint-plugin-import(no-nodejs-modules): Do not import Node.js builtin module `node:fs` ╭─[no_nodejs_modules.tsx:1:1] 1 │ import fs from "node:fs" · ──────────────────────── ╰──── + help: Use a browser-compatible alternative or add this module to the `allow` list if Node.js usage is intentional. ⚠ eslint-plugin-import(no-nodejs-modules): Do not import Node.js builtin module `node:fs` ╭─[no_nodejs_modules.tsx:1:10] 1 │ var fs = require("node:fs") · ────────────────── ╰──── + help: Use a browser-compatible alternative or add this module to the `allow` list if Node.js usage is intentional. ⚠ eslint-plugin-import(no-nodejs-modules): Do not import Node.js builtin module `node:crypto` ╭─[no_nodejs_modules.tsx:1:1] 1 │ import crypto from "node:crypto" · ──────────────────────────────── ╰──── + help: Use a browser-compatible alternative or add this module to the `allow` list if Node.js usage is intentional. ⚠ eslint-plugin-import(no-nodejs-modules): Do not import Node.js builtin module `node:fs` ╭─[no_nodejs_modules.tsx:1:1] 1 │ import("node:fs") · ───────────────── ╰──── + help: Use a browser-compatible alternative or add this module to the `allow` list if Node.js usage is intentional. ⚠ eslint-plugin-import(no-nodejs-modules): Do not import Node.js builtin module `node:path` ╭─[no_nodejs_modules.tsx:1:1] 1 │ export { foo } from "node:path" · ─────────────────────────────── ╰──── + help: Use a browser-compatible alternative or add this module to the `allow` list if Node.js usage is intentional. ⚠ eslint-plugin-import(no-nodejs-modules): Do not import Node.js builtin module `node:util` ╭─[no_nodejs_modules.tsx:1:1] 1 │ import util = require("node:util") · ────────────────────────────────── ╰──── + help: Use a browser-compatible alternative or add this module to the `allow` list if Node.js usage is intentional. ⚠ eslint-plugin-import(no-nodejs-modules): Do not import Node.js builtin module `node:fs` ╭─[no_nodejs_modules.tsx:1:1] 1 │ import fs from "node:fs" · ──────────────────────── ╰──── + help: Use a browser-compatible alternative or add this module to the `allow` list if Node.js usage is intentional. ⚠ eslint-plugin-import(no-nodejs-modules): Do not import Node.js builtin module `node:crypto` ╭─[no_nodejs_modules.tsx:1:1] 1 │ import("node:crypto") · ───────────────────── ╰──── + help: Use a browser-compatible alternative or add this module to the `allow` list if Node.js usage is intentional. ⚠ eslint-plugin-import(no-nodejs-modules): Do not import Node.js builtin module `fs` ╭─[no_nodejs_modules.tsx:1:1] 1 │ import fs = require("fs") · ───────────────────────── ╰──── + help: Use a browser-compatible alternative or add this module to the `allow` list if Node.js usage is intentional. ⚠ eslint-plugin-import(no-nodejs-modules): Do not import Node.js builtin module `path` ╭─[no_nodejs_modules.tsx:1:1] 1 │ import path = require("path") · ───────────────────────────── ╰──── + help: Use a browser-compatible alternative or add this module to the `allow` list if Node.js usage is intentional. ⚠ eslint-plugin-import(no-nodejs-modules): Do not import Node.js builtin module `fs` ╭─[no_nodejs_modules.tsx:1:1] 1 │ export { foo } from "fs" · ──────────────────────── ╰──── + help: Use a browser-compatible alternative or add this module to the `allow` list if Node.js usage is intentional. ⚠ eslint-plugin-import(no-nodejs-modules): Do not import Node.js builtin module `crypto` ╭─[no_nodejs_modules.tsx:1:1] 1 │ export { default as foo } from "crypto" · ─────────────────────────────────────── ╰──── + help: Use a browser-compatible alternative or add this module to the `allow` list if Node.js usage is intentional. ⚠ eslint-plugin-import(no-nodejs-modules): Do not import Node.js builtin module `path` ╭─[no_nodejs_modules.tsx:1:1] 1 │ export * from "path" · ──────────────────── ╰──── + help: Use a browser-compatible alternative or add this module to the `allow` list if Node.js usage is intentional.