docs(linter): improve docs for eslint-plugin-import rules (#6131)

Related to #6050
This commit is contained in:
dalaoshu 2024-09-28 20:45:02 +08:00 committed by GitHub
parent 375bebea06
commit 14ba263506
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 292 additions and 63 deletions

View file

@ -18,10 +18,19 @@ pub struct Default;
declare_oxc_lint!( declare_oxc_lint!(
/// ### What it does /// ### What it does
/// ///
/// If a default import is requested, this rule will report if there is no default export in the imported module. /// If a default import is requested, this rule will report if there is no
/// default export in the imported module.
/// ///
/// ### Example /// ### Why is this bad?
/// ///
/// Using a default import when there is no default export can lead to
/// confusion and runtime errors. It can make the code harder to understand
/// and maintain, as it may suggest that a module has a default export
/// when it does not, leading to unexpected behavior.
///
/// ### Examples
///
/// Examples of **incorrect** code for this rule:
/// ```javascript /// ```javascript
/// // ./bar.js /// // ./bar.js
/// export function bar() { return null } /// export function bar() { return null }
@ -29,6 +38,15 @@ declare_oxc_lint!(
/// // ./foo.js /// // ./foo.js
/// import bar from './bar' // no default export found in ./bar /// import bar from './bar' // no default export found in ./bar
/// ``` /// ```
///
/// Examples of **correct** code for this rule:
/// ```javascript
/// // ./bar.js
/// export default function bar() { return null }
///
/// // ./foo.js
/// import { bar } from './bar' // correct usage of named import
/// ```
Default, Default,
correctness correctness
); );

View file

@ -8,7 +8,7 @@ use rustc_hash::{FxHashMap, FxHashSet};
use crate::{context::LintContext, rule::Rule}; use crate::{context::LintContext, rule::Rule};
fn no_named_export(span: Span, module_name: &str) -> OxcDiagnostic { fn no_named_export(module_name: &str, span: Span) -> OxcDiagnostic {
OxcDiagnostic::warn(format!("No named exports found in module '{module_name}'")) OxcDiagnostic::warn(format!("No named exports found in module '{module_name}'"))
.with_label(span) .with_label(span)
} }
@ -19,13 +19,29 @@ pub struct Export;
declare_oxc_lint!( declare_oxc_lint!(
/// ### What it does /// ### What it does
///
/// Reports funny business with exports, like repeated exports of names or defaults. /// Reports funny business with exports, like repeated exports of names or defaults.
/// ///
/// ### Example /// ### Why is this bad?
///
/// Having multiple exports of the same name can lead to ambiguity and confusion
/// in the codebase. It makes it difficult to track which export is being used
/// and can result in runtime errors if the wrong export is referenced.
///
/// ### Examples
///
/// Examples of **incorrect** code for this rule:
/// ```javascript /// ```javascript
/// let foo; /// let foo;
/// export { foo }; // Multiple exports of name 'foo'. /// export { foo }; // Multiple exports of name 'foo'.
/// export * from "./export-all" // export-all.js also export foo /// export * from "./export-all"; // Conflicts if export-all.js also exports foo
/// ```
///
/// Examples of **correct** code for this rule:
/// ```javascript
/// let foo;
/// export { foo as foo1 }; // Renamed export to avoid conflict
/// export * from "./export-all"; // No conflict if export-all.js also exports foo
/// ``` /// ```
Export, Export,
nursery nursery
@ -58,7 +74,7 @@ impl Rule for Export {
); );
if export_names.is_empty() { if export_names.is_empty() {
ctx.diagnostic(no_named_export(module_request.span(), module_request.name())); ctx.diagnostic(no_named_export(module_request.name(), module_request.span()));
} else { } else {
all_export_names.insert(star_export_entry.span, export_names); all_export_names.insert(star_export_entry.span, export_names);
} }

View file

@ -9,11 +9,11 @@ use crate::{context::LintContext, rule::Rule};
fn max_dependencies_diagnostic<S: Into<Cow<'static, str>>>( fn max_dependencies_diagnostic<S: Into<Cow<'static, str>>>(
message: S, message: S,
span1: Span, span: Span,
) -> OxcDiagnostic { ) -> OxcDiagnostic {
OxcDiagnostic::warn(message) OxcDiagnostic::warn(message)
.with_help("Reduce the number of dependencies in this file") .with_help("Reduce the number of dependencies in this file")
.with_label(span1) .with_label(span)
} }
/// <https://github.com/import-js/eslint-plugin-import/blob/v2.29.1/docs/rules/max-dependencies.md> /// <https://github.com/import-js/eslint-plugin-import/blob/v2.29.1/docs/rules/max-dependencies.md>
@ -47,19 +47,26 @@ declare_oxc_lint!(
/// ///
/// ### Why is this bad? /// ### Why is this bad?
/// ///
/// This is a useful rule because a module with too many dependencies is a code smell, and /// This is a useful rule because a module with too many dependencies is a code smell,
/// usually indicates the module is doing too much and/or should be broken up into smaller /// and usually indicates the module is doing too much and/or should be broken up into
/// modules. /// smaller modules.
/// ///
/// ### Example /// ### Examples
/// ///
/// Given `{"max": 2}` /// Given `{"max": 2}`
///
/// Examples of **incorrect** code for this rule:
/// ```javascript /// ```javascript
/// import a from './a'; /// import a from './a';
/// import b from './b'; /// import b from './b';
/// import c from './c'; /// import c from './c'; // Too many dependencies: 3 (max: 2)
/// ```
///
/// Examples of **correct** code for this rule:
/// ```javascript
/// import a from './a';
/// import b from './b'; // Allowed: 2 dependencies (max: 2)
/// ``` /// ```
MaxDependencies, MaxDependencies,
pedantic, pedantic,
); );

View file

@ -35,15 +35,33 @@ declare_oxc_lint!(
/// ///
/// ### Why is this bad? /// ### Why is this bad?
/// ///
/// ### Example /// Importing or exporting names that do not exist in the referenced module
/// can lead to runtime errors and confusion. It may suggest that certain
/// functionality is available when it is not, making the code harder to
/// maintain and understand. This rule helps ensure that your code
/// accurately reflects the available exports, improving reliability.
///
/// ### Examples
///
/// Given /// Given
/// ```js /// ```js
/// // ./foo.js /// // ./foo.js
/// export const foo = "I'm so foo" /// export const foo = "I'm so foo";
/// ``` /// ```
/// ///
/// The following is considered valid: /// Examples of **incorrect** code for this rule:
/// ```js
/// // ./baz.js
/// import { notFoo } from './foo'
/// ///
/// // ES7 proposal
/// export { notFoo as defNotBar } from './foo'
///
/// // will follow 'jsnext:main', if available
/// import { dontCreateStore } from 'redux'
/// ```
///
/// Examples of **correct** code for this rule:
/// ```js /// ```js
/// // ./bar.js /// // ./bar.js
/// import { foo } from './foo' /// import { foo } from './foo'
@ -55,19 +73,6 @@ declare_oxc_lint!(
/// // (import/ignore setting) /// // (import/ignore setting)
/// import { SomeNonsenseThatDoesntExist } from 'react' /// import { SomeNonsenseThatDoesntExist } from 'react'
/// ``` /// ```
///
/// ...and the following are reported:
///
/// ```js
/// // ./baz.js
/// import { notFoo } from './foo'
///
/// // ES7 proposal
/// export { notFoo as defNotBar } from './foo'
///
/// // will follow 'jsnext:main', if available
/// import { dontCreateStore } from 'redux'
/// ```
Named, Named,
correctness correctness
); );

View file

@ -50,12 +50,54 @@ pub struct Namespace {
declare_oxc_lint!( declare_oxc_lint!(
/// ### What it does /// ### What it does
///
/// Enforces names exist at the time they are dereferenced, when imported as /// Enforces names exist at the time they are dereferenced, when imported as
/// a full namespace (i.e. `import * as foo from './foo'; foo.bar();` will /// a full namespace (i.e. `import * as foo from './foo'; foo.bar();` will
/// report if bar is not exported by `./foo.`). Will report at the import /// report if bar is not exported by `./foo.`). Will report at the import
/// declaration if there are no exported names found. Also, will report for /// declaration if there are no exported names found. Also, will report for
/// computed references (i.e. `foo["bar"]()`). Reports on assignment to a /// computed references (i.e. `foo["bar"]()`). Reports on assignment to a
/// member of an imported namespace. /// member of an imported namespace.
///
/// ### Why is this bad?
///
/// Dereferencing a name that does not exist can lead to runtime errors and
/// unexpected behavior in your code. It makes the code less reliable and
/// harder to maintain, as it may not be clear which names are valid. This
/// rule helps ensure that all referenced names are defined, improving
/// the clarity and robustness of your code.
///
/// ### Examples
///
/// Given
/// ```javascript
/// // ./foo.js
/// export const bar = "I'm bar";
/// ```
///
/// Examples of **incorrect** code for this rule:
/// ```javascript
/// // ./qux.js
/// import * as foo from './foo';
/// foo.notExported(); // Error: notExported is not exported
///
/// // Assignment to a member of an imported namespace
/// foo.bar = "new value"; // Error: bar cannot be reassigned
///
/// // Computed reference to a non-existent export
/// const method = "notExported";
/// foo[method](); // Error: notExported does not exist
/// ```
///
/// Examples of **correct** code for this rule:
/// ```javascript
/// // ./baz.js
/// import * as foo from './foo';
/// console.log(foo.bar); // Valid: bar is exported
///
/// // Computed reference
/// const method = "bar";
/// foo[method](); // Valid: method refers to an exported function
/// ```
Namespace, Namespace,
correctness correctness
); );

View file

@ -20,14 +20,20 @@ pub struct NoAmd;
declare_oxc_lint!( declare_oxc_lint!(
/// ### What it does /// ### What it does
/// ///
/// Forbid AMD `require` and `define` calls. /// Forbids the use of AMD `require` and `define` calls.
/// ///
/// ### Why is this bad? /// ### Why is this bad?
/// ///
/// AMD (Asynchronous Module Definition) is an older module format
/// that is less common in modern JavaScript development, especially
/// with the widespread use of ES6 modules and CommonJS in Node.js.
/// AMD introduces unnecessary complexity and is often considered outdated.
/// This rule enforces the use of more modern module systems to improve
/// maintainability and consistency across the codebase.
///
/// ### Examples /// ### Examples
/// ///
/// Examples of **incorrect** code for this rule: /// Examples of **incorrect** code for this rule:
///
/// ```javascript /// ```javascript
/// require([a, b], function() {} ); /// require([a, b], function() {} );
/// ``` /// ```

View file

@ -55,20 +55,37 @@ declare_oxc_lint!(
/// ### Why is this bad? /// ### Why is this bad?
/// ///
/// Dependency cycles lead to confusing architectures where bugs become hard to find. /// Dependency cycles lead to confusing architectures where bugs become hard to find.
///
/// It is common to import an `undefined` value that is caused by a cyclic dependency. /// It is common to import an `undefined` value that is caused by a cyclic dependency.
/// ///
/// ### Example /// ### Examples
///
/// Examples of **incorrect** code for this rule:
/// ```javascript /// ```javascript
/// // dep-b.js /// // dep-b.js
/// import './dep-a.js' /// import './dep-a.js'
/// export function b() { /* ... */ } /// export function b() { /* ... */ }
/// ``` /// ```
///
/// ```javascript /// ```javascript
/// // dep-a.js /// // dep-a.js
/// import { b } from './dep-b.js' // reported: Dependency cycle detected. /// import { b } from './dep-b.js' // reported: Dependency cycle detected.
/// export function a() { /* ... */ }
/// ``` /// ```
///
/// In this example, `dep-a.js` and `dep-b.js` import each other, creating a circular
/// dependency, which is problematic.
///
/// Examples of **correct** code for this rule:
/// ```javascript
/// // dep-b.js
/// export function b() { /* ... */ }
/// ```
/// ```javascript
/// // dep-a.js
/// import { b } from './dep-b.js' // no circular dependency
/// export function a() { /* ... */ }
/// ```
///
/// In this corrected version, `dep-b.js` no longer imports `dep-a.js`, breaking the cycle.
NoCycle, NoCycle,
restriction restriction
); );

View file

@ -14,7 +14,15 @@ pub struct NoDefaultExport;
declare_oxc_lint!( declare_oxc_lint!(
/// ### What it does /// ### What it does
/// ///
/// Forbid a module to have a default exports. This help your editor to provide better auto imports. /// Forbids a module from having default exports. This helps your editor
/// provide better auto-import functionality, as named exports offer more
/// explicit and predictable imports compared to default exports.
///
/// ### Why is this bad?
///
/// Default exports can lead to confusion, as the name of the imported value
/// can vary based on how it's imported. This can make refactoring and
/// auto-imports less reliable.
/// ///
/// ### Examples /// ### Examples
/// ///
@ -31,7 +39,6 @@ declare_oxc_lint!(
/// export const foo = 'foo'; /// export const foo = 'foo';
/// export const bar = 'bar'; /// export const bar = 'bar';
/// ``` /// ```
///
NoDefaultExport, NoDefaultExport,
restriction restriction
); );
@ -48,6 +55,7 @@ impl Rule for NoDefaultExport {
fn write_diagnostic(ctx: &LintContext<'_>, span: Span) { fn write_diagnostic(ctx: &LintContext<'_>, span: Span) {
ctx.diagnostic(no_default_export_diagnostic(span)); ctx.diagnostic(no_default_export_diagnostic(span));
} }
fn write_diagnostic_optional(ctx: &LintContext<'_>, span_option: Option<Span>) { fn write_diagnostic_optional(ctx: &LintContext<'_>, span_option: Option<Span>) {
if let Some(span) = span_option { if let Some(span) = span_option {
write_diagnostic(ctx, span); write_diagnostic(ctx, span);
@ -77,6 +85,7 @@ fn test() {
"import {default as foo} from './foo';", "import {default as foo} from './foo';",
"export type UserId = number;", "export type UserId = number;",
]; ];
let fail = vec![ let fail = vec![
"export default function bar() {};", "export default function bar() {};",
"export const foo = 'foo';\nexport default bar;", "export const foo = 'foo';\nexport default bar;",

View file

@ -2,7 +2,10 @@ use oxc_diagnostics::{LabeledSpan, OxcDiagnostic};
use oxc_macros::declare_oxc_lint; use oxc_macros::declare_oxc_lint;
// use oxc_span::{CompactStr, Span}; // use oxc_span::{CompactStr, Span};
use crate::{context::{LintContext, ContextHost}, rule::Rule}; use crate::{
context::{ContextHost, LintContext},
rule::Rule,
};
// #[derive(Debug, Error, Diagnostic)] // #[derive(Debug, Error, Diagnostic)]
// #[error("")] // #[error("")]
@ -16,7 +19,20 @@ pub struct NoDeprecated;
declare_oxc_lint!( declare_oxc_lint!(
/// ### What it does /// ### What it does
/// ///
/// Reports use of a deprecated name, as indicated by a JSDoc block with a @deprecated tag or TomDoc Deprecated: comment. /// Reports use of a deprecated name, as indicated by a JSDoc block with
/// a @deprecated tag or TomDoc Deprecated: comment.
///
/// ### Why is this bad?
///
/// ### Examples
///
/// Examples of **incorrect** code for this rule:
/// ```javascript
/// ```
///
/// Examples of **correct** code for this rule:
/// ```javascript
/// ```
NoDeprecated, NoDeprecated,
nursery nursery
); );

View file

@ -14,7 +14,27 @@ pub struct NoDuplicates {
declare_oxc_lint!( declare_oxc_lint!(
/// ### What it does /// ### What it does
/// ///
/// Reports if a resolved path is imported more than once. /// Reports if a resolved path is imported more than once in the same module.
/// This helps avoid unnecessary duplicate imports and keeps the code clean.
///
/// ### Why is this bad?
///
/// Importing the same module multiple times can lead to redundancy and
/// unnecessary complexity. It also affects maintainability, as it might
/// confuse developers and result in inconsistent usage of imports across the code.
///
/// ### Examples
///
/// Examples of **incorrect** code for this rule:
/// ```javascript
/// import { foo } from './module';
/// import { bar } from './module';
/// ```
///
/// Examples of **correct** code for this rule:
/// ```javascript
/// import { foo, bar } from './module';
/// ```
NoDuplicates, NoDuplicates,
suspicious suspicious
); );

View file

@ -19,12 +19,15 @@ pub struct NoDynamicRequire {
declare_oxc_lint!( declare_oxc_lint!(
/// ### What it does /// ### What it does
/// ///
/// Forbid imports which use an expression for the module argument. /// Forbids imports that use an expression for the module argument. This includes
/// dynamically resolved paths in `require` or `import` statements.
/// ///
/// ### Why is this bad? /// ### Why is this bad?
/// ///
/// Import statements which use an expression resolved at runtime makes it to find where the /// Using expressions that are resolved at runtime in import statements makes it
/// import comes from and some static code analysis tools might not be able to resolve them. /// difficult to determine where the module is being imported from. This can complicate
/// code navigation and hinder static analysis tools, which rely on predictable module paths
/// for linting, bundling, and other optimizations.
/// ///
/// ### Examples /// ### Examples
/// ///

View file

@ -23,23 +23,37 @@ declare_oxc_lint!(
/// ### What it does /// ### What it does
/// ///
/// Reports use of an exported name as the locally imported name of a default export. /// Reports use of an exported name as the locally imported name of a default export.
/// This happens when an imported default export is assigned a name that conflicts
/// with a named export from the same module.
/// ///
/// ### Example /// ### Why is this bad?
/// ///
/// Using a named export's identifier for a default export can cause confusion
/// and errors in understanding which value is being imported. It also reduces
/// code clarity, making it harder for other developers to understand the intended
/// imports.
///
///
/// ### Examples
///
/// Given
/// ```javascript /// ```javascript
/// // foo.js /// // foo.js
/// export default 'foo'; /// export default 'foo';
/// export const bar = 'baz'; /// export const bar = 'baz';
/// ``` /// ```
/// Valid: ///
/// Examples of **incorrect** code for this rule:
/// ```javascript /// ```javascript
/// import foo from './foo.js'; /// // Invalid: using exported name 'bar' as the identifier for default export.
/// ```
/// Invalid:
/// ```javascript
/// // using exported name 'bar' as identifier for default export.
/// import bar from './foo.js'; /// import bar from './foo.js';
/// ``` /// ```
///
/// Examples of **correct** code for this rule:
/// ```javascript
/// // Valid: correctly importing default export with a non-conflicting name.
/// import foo from './foo.js';
/// ```
NoNamedAsDefault, NoNamedAsDefault,
suspicious suspicious
); );

View file

@ -29,18 +29,37 @@ pub struct NoNamedAsDefaultMember;
declare_oxc_lint!( declare_oxc_lint!(
/// ### What it does /// ### What it does
/// ///
/// Reports use of an exported name as a property on the default export. /// Reports the use of an exported name (named export) as a property on the
/// default export. This occurs when trying to access a named export through
/// the default export, which is incorrect.
/// ///
/// ### Example /// ### Why is this bad?
/// ///
/// Accessing a named export via the default export is incorrect and will not
/// work as expected. Named exports should be imported directly, while default
/// exports are accessed without properties. This mistake can lead to runtime
/// errors or undefined behavior.
///
/// ### Examples
///
/// Given
/// ```javascript /// ```javascript
/// // ./bar.js /// // ./bar.js
/// export function bar() { return null } /// export function bar() { return null }
/// export default () => { return 1 } /// export default () => { return 1 }
/// ```
/// ///
/// Examples of **incorrect** code for this rule:
/// ```javascript
/// // ./foo.js /// // ./foo.js
/// import bar from './bar' /// import foo from './bar'
/// const bar = foo.bar // trying to access named export via default /// const bar = foo.bar; // Incorrect: trying to access named export via default
/// ```
///
/// Examples of **correct** code for this rule:
/// ```javascript
/// // ./foo.js
/// import { bar } from './bar'; // Correct: accessing named export directly
/// ``` /// ```
NoNamedAsDefaultMember, NoNamedAsDefaultMember,
suspicious suspicious

View file

@ -14,14 +14,27 @@ pub struct NoSelfImport;
declare_oxc_lint!( declare_oxc_lint!(
/// ### What it does /// ### What it does
/// ///
/// Forbid a module from importing itself. This can sometimes happen during refactoring. /// Forbids a module from importing itself. This can sometimes happen accidentally,
/// especially during refactoring.
/// ///
/// ### Example /// ### Why is this bad?
/// ///
/// Importing a module into itself creates a circular dependency, which can cause
/// runtime issues, including infinite loops, unresolved imports, or `undefined` values.
///
/// ### Examples
///
/// Examples of **incorrect** code for this rule:
/// ```javascript /// ```javascript
/// // foo.js /// // foo.js
/// import foo from './foo.js' /// import foo from './foo.js'; // Incorrect: module imports itself
/// const foo = require('./foo') /// const foo = require('./foo'); // Incorrect: module imports itself
/// ```
///
/// Examples of **correct** code for this rule:
/// ```javascript
/// // foo.js
/// import bar from './bar.js'; // Correct: module imports another module
/// ``` /// ```
NoSelfImport, NoSelfImport,
suspicious suspicious

View file

@ -1,11 +1,13 @@
use oxc_macros::declare_oxc_lint; use oxc_macros::declare_oxc_lint;
use oxc_span::Span; use oxc_span::Span;
use crate::{context::{LintContext, ContextHost}, rule::Rule}; use crate::{
context::{ContextHost, LintContext},
rule::Rule,
};
fn no_exports_found(span: Span) -> OxcDiagnostic { fn no_exports_found(span: Span) -> OxcDiagnostic {
OxcDiagnostic::warn("No exports found") OxcDiagnostic::warn("No exports found").with_label(span)
.with_label(span)
} }
/// <https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-unused-modules.md> /// <https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-unused-modules.md>
@ -23,6 +25,17 @@ declare_oxc_lint!(
/// * individual exports not being statically imported or requireed from other modules in the same project /// * individual exports not being statically imported or requireed from other modules in the same project
/// * dynamic imports are supported if argument is a literal string /// * dynamic imports are supported if argument is a literal string
/// ///
/// ### Why is this bad?
///
/// ### Examples
///
/// Examples of **incorrect** code for this rule:
/// ```javascript
/// ```
///
/// Examples of **correct** code for this rule:
/// ```javascript
/// ```
NoUnusedModules, NoUnusedModules,
nursery nursery
); );

View file

@ -21,14 +21,16 @@ pub struct NoWebpackLoaderSyntax;
declare_oxc_lint!( declare_oxc_lint!(
/// ### What it does /// ### What it does
/// ///
/// Forbid Webpack loader syntax in imports. /// Forbids using Webpack loader syntax directly in import or require statements.
/// ///
/// ### Why is this bad? /// ### Why is this bad?
/// ///
/// This loader syntax is non-standard, so it couples the code to Webpack. The recommended way to /// This loader syntax is non-standard, so it couples the code to Webpack. The recommended way to
/// specify Webpack loader configuration is in a [Webpack configuration file](https://webpack.js.org/concepts/loaders/#configuration). /// specify Webpack loader configuration is in a [Webpack configuration file](https://webpack.js.org/concepts/loaders/#configuration).
/// ///
/// ### Example /// ### Examples
///
/// Examples of **incorrect** code for this rule:
/// ```javascript /// ```javascript
/// import myModule from 'my-loader!my-module'; /// import myModule from 'my-loader!my-module';
/// import theme from 'style!css!./theme.css'; /// import theme from 'style!css!./theme.css';
@ -36,6 +38,15 @@ declare_oxc_lint!(
/// var myModule = require('my-loader!./my-module'); /// var myModule = require('my-loader!./my-module');
/// var theme = require('style!css!./theme.css'); /// var theme = require('style!css!./theme.css');
/// ``` /// ```
///
/// Examples of **correct** code for this rule:
/// ```javascript
/// import myModule from './my-module';
/// import theme from './theme.css';
///
/// var myModule = require('./my-module');
/// var theme = require('./theme.css');
/// ```
NoWebpackLoaderSyntax, NoWebpackLoaderSyntax,
restriction, restriction,
); );