mirror of
https://github.com/oxc-project/oxc.git
synced 2026-11-04 10:29:58 +00:00
perf(linter/unicorn/prefer-export-from): narrow ExportFromDeclaration lookup (#25381)
## Summary - Avoid a flattened-AST scan for every import handled by `unicorn/prefer-export-from`. - Locate a matching direct re-export from top-level program statements only after symbol-reference analysis finds a reportable re-export. - Cover multiple imports with existing direct re-exports.
This commit is contained in:
1 parent
6846a9aa85
commit
6fb7f47605
2 files changed
+72
-21
No files matched your search
@@ -9,7 +9,8 @@ use oxc_ast::{
|
||||
ast::{
|
||||
BindingPattern, ExportFromDeclaration, ExportSpecifier, ImportAttributeKey,
|
||||
ImportDeclaration, ImportDeclarationSpecifier, ImportOrExportKind, ModuleExportName,
|
||||
Statement, VariableDeclarationKind, VariableDeclarator, WithClause, WithClauseKeyword,
|
||||
Program, Statement, VariableDeclarationKind, VariableDeclarator, WithClause,
|
||||
WithClauseKeyword,
|
||||
},
|
||||
};
|
||||
use oxc_diagnostics::OxcDiagnostic;
|
||||
@@ -104,16 +105,8 @@ impl Rule for PreferExportFrom {
|
||||
return;
|
||||
}
|
||||
|
||||
let corresponding_export: Option<&ExportFromDeclaration> =
|
||||
find_corresponding_export(ctx, import_decl);
|
||||
|
||||
let symbol_to_specifier_specs = Self::get_symbol_to_specifier(import_decl);
|
||||
self.check_re_export(
|
||||
ctx,
|
||||
&symbol_to_specifier_specs,
|
||||
import_decl,
|
||||
corresponding_export,
|
||||
);
|
||||
self.check_re_export(ctx, &symbol_to_specifier_specs, import_decl);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -144,7 +137,6 @@ impl PreferExportFrom {
|
||||
ctx: &LintContext<'a>,
|
||||
symbol_to_specifier: &FxIndexMap<SymbolId, SpecifierSpec<'a>>,
|
||||
import_decl: &'a ImportDeclaration<'a>,
|
||||
re_export_decl: Option<&'a ExportFromDeclaration<'a>>,
|
||||
) {
|
||||
let (locally_used_specifiers, violations) =
|
||||
self.analyze_import_usage(ctx, symbol_to_specifier, import_decl);
|
||||
@@ -153,6 +145,8 @@ impl PreferExportFrom {
|
||||
return;
|
||||
}
|
||||
|
||||
let re_export_decl = find_corresponding_export(ctx, import_decl);
|
||||
|
||||
let source = import_decl.source.value.as_str();
|
||||
let with_clause = import_decl.with_clause.as_ref().map(|with_clause| {
|
||||
let keyword = match with_clause.keyword {
|
||||
@@ -1155,6 +1149,7 @@ fn find_corresponding_export<'a>(
|
||||
import_decl: &'a ImportDeclaration<'a>,
|
||||
) -> Option<&'a ExportFromDeclaration<'a>> {
|
||||
let source = import_decl.source.value.as_str();
|
||||
let program = ctx.nodes().program();
|
||||
|
||||
for requested_module in ctx.module_record().requested_modules.get(source)? {
|
||||
if requested_module.is_import {
|
||||
@@ -1162,7 +1157,7 @@ fn find_corresponding_export<'a>(
|
||||
}
|
||||
|
||||
let Some(export_decl) =
|
||||
find_export_named_declaration_by_span(ctx, requested_module.statement_span)
|
||||
find_export_named_declaration_by_span(program, requested_module.statement_span)
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
@@ -1182,17 +1177,14 @@ fn find_corresponding_export<'a>(
|
||||
}
|
||||
|
||||
fn find_export_named_declaration_by_span<'a>(
|
||||
ctx: &LintContext<'a>,
|
||||
program: &'a Program<'a>,
|
||||
span: Span,
|
||||
) -> Option<&'a ExportFromDeclaration<'a>> {
|
||||
ctx.nodes().iter().find_map(|node| {
|
||||
if let AstKind::ExportFromDeclaration(export_decl) = node.kind()
|
||||
&& export_decl.span() == span
|
||||
{
|
||||
Some(export_decl)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
program.body.iter().find_map(|statement| {
|
||||
let Statement::ExportFromDeclaration(export_decl) = statement else {
|
||||
return None;
|
||||
};
|
||||
(export_decl.span() == span).then_some(export_decl.as_ref())
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1416,6 +1408,16 @@ fn test() {
|
||||
r#"import { foo } from "foo";
|
||||
export { foo };
|
||||
export type { bar } from "foo";"#,
|
||||
// Multiple imports find their corresponding direct re-export.
|
||||
r#"import { a } from "a";
|
||||
import { b } from "b";
|
||||
import { c } from "c";
|
||||
export { existingA } from "a";
|
||||
export { existingB } from "b";
|
||||
export { existingC } from "c";
|
||||
export { a };
|
||||
export { b };
|
||||
export { c };"#,
|
||||
r#"import { foo } from "foo";
|
||||
export { foo };
|
||||
export { type bar } from "foo";"#,
|
||||
|
||||
@@ -777,6 +777,55 @@ source: crates/oxc_linter/src/tester.rs
|
||||
╰────
|
||||
help: use `export ... from ...;`
|
||||
|
||||
⚠ unicorn(prefer-export-from): Prefer re-exporting directly from the source module.
|
||||
╭─[prefer_export_from.tsx:1:1]
|
||||
1 │ import { a } from "a";
|
||||
· ───────────┬──────────
|
||||
· ╰── Imported here.
|
||||
2 │ import { b } from "b";
|
||||
╰────
|
||||
╭─[prefer_export_from.tsx:7:22]
|
||||
6 │ export { existingC } from "c";
|
||||
7 │ export { a };
|
||||
· ┬
|
||||
· ╰── Re-exported here.
|
||||
8 │ export { b };
|
||||
╰────
|
||||
help: use `export ... from ...;`
|
||||
|
||||
⚠ unicorn(prefer-export-from): Prefer re-exporting directly from the source module.
|
||||
╭─[prefer_export_from.tsx:2:13]
|
||||
1 │ import { a } from "a";
|
||||
2 │ import { b } from "b";
|
||||
· ───────────┬──────────
|
||||
· ╰── Imported here.
|
||||
3 │ import { c } from "c";
|
||||
╰────
|
||||
╭─[prefer_export_from.tsx:8:22]
|
||||
7 │ export { a };
|
||||
8 │ export { b };
|
||||
· ┬
|
||||
· ╰── Re-exported here.
|
||||
9 │ export { c };
|
||||
╰────
|
||||
help: use `export ... from ...;`
|
||||
|
||||
⚠ unicorn(prefer-export-from): Prefer re-exporting directly from the source module.
|
||||
╭─[prefer_export_from.tsx:3:13]
|
||||
2 │ import { b } from "b";
|
||||
3 │ import { c } from "c";
|
||||
· ───────────┬──────────
|
||||
· ╰── Imported here.
|
||||
4 │ export { existingA } from "a";
|
||||
╰────
|
||||
╭─[prefer_export_from.tsx:9:22]
|
||||
8 │ export { b };
|
||||
9 │ export { c };
|
||||
· ┬
|
||||
· ╰── Re-exported here.
|
||||
╰────
|
||||
help: use `export ... from ...;`
|
||||
|
||||
⚠ unicorn(prefer-export-from): Prefer re-exporting directly from the source module.
|
||||
╭─[prefer_export_from.tsx:1:1]
|
||||
1 │ import { foo } from "foo";
|
||||
|
||||
Reference in new issue
Block a user