mirror of
https://github.com/danbulant/oxc
synced 2026-05-19 04:08:41 +00:00
refactor(semantic): distinguish whether requested_modules is type imports/exports (#2848)
This commit is contained in:
parent
6177c2f7ef
commit
1b5e544a36
6 changed files with 49 additions and 25 deletions
|
|
@ -102,7 +102,7 @@ impl Rule for NoCycle {
|
|||
let mut state = State::default();
|
||||
if self.detect_cycle(&mut state, module_record, needle) {
|
||||
let stack = &state.stack;
|
||||
let span = module_record.requested_modules.get(&stack[0].0).unwrap()[0];
|
||||
let span = module_record.requested_modules.get(&stack[0].0).unwrap()[0].span();
|
||||
let help = stack
|
||||
.iter()
|
||||
.map(|(specifier, path)| {
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
use itertools::Itertools;
|
||||
use oxc_diagnostics::miette::{miette, LabeledSpan, Severity};
|
||||
use oxc_macros::declare_oxc_lint;
|
||||
use oxc_span::Span;
|
||||
use oxc_syntax::module_record::ImportImportName;
|
||||
use oxc_syntax::module_record::{ImportImportName, RequestedModule};
|
||||
|
||||
use crate::{context::LintContext, rule::Rule};
|
||||
|
||||
|
|
@ -36,20 +35,22 @@ impl Rule for NoDuplicates {
|
|||
let groups = module_record
|
||||
.requested_modules
|
||||
.iter()
|
||||
.map(|(source, spans)| {
|
||||
.map(|(source, requested_modules)| {
|
||||
let resolved_absolute_path = module_record.loaded_modules.get(source).map_or_else(
|
||||
|| source.to_string(),
|
||||
|module| module.resolved_absolute_path.to_string_lossy().to_string(),
|
||||
);
|
||||
(resolved_absolute_path, spans)
|
||||
(resolved_absolute_path, requested_modules)
|
||||
})
|
||||
.group_by(|r| r.0.clone());
|
||||
|
||||
let check_duplicates = |spans: Option<&Vec<&Span>>| {
|
||||
if let Some(spans) = spans {
|
||||
if spans.len() > 1 {
|
||||
let labels =
|
||||
spans.iter().map(|span| LabeledSpan::underline(**span)).collect::<Vec<_>>();
|
||||
let check_duplicates = |requested_modules: Option<&Vec<&RequestedModule>>| {
|
||||
if let Some(requested_modules) = requested_modules {
|
||||
if requested_modules.len() > 1 {
|
||||
let labels = requested_modules
|
||||
.iter()
|
||||
.map(|requested_module| LabeledSpan::underline(requested_module.span()))
|
||||
.collect::<Vec<_>>();
|
||||
ctx.diagnostic(miette!(
|
||||
severity = Severity::Warning,
|
||||
labels = labels,
|
||||
|
|
@ -63,14 +64,16 @@ impl Rule for NoDuplicates {
|
|||
let has_type_import = module_record.import_entries.iter().any(|entry| entry.is_type);
|
||||
// When prefer_inline is false, 0 is value, 1 is type named, 2 is type default or type namespace
|
||||
// When prefer_inline is true, 0 is value and type named, 2 is type default or type namespace
|
||||
let import_entries_maps =
|
||||
group.into_iter().flat_map(|(_path, spans)| spans).into_group_map_by(|span| {
|
||||
let import_entries_maps = group
|
||||
.into_iter()
|
||||
.flat_map(|(_path, requested_modules)| requested_modules)
|
||||
.into_group_map_by(|requested_module| {
|
||||
// We should early return if there is no type import
|
||||
if !has_type_import {
|
||||
return 0;
|
||||
};
|
||||
for entry in &module_record.import_entries {
|
||||
if entry.module_request.span() != **span {
|
||||
if entry.module_request.span() != requested_module.span() {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,13 +35,13 @@ impl Rule for NoSelfImport {
|
|||
fn run_once(&self, ctx: &LintContext<'_>) {
|
||||
let module_record = ctx.semantic().module_record();
|
||||
let resolved_absolute_path = &module_record.resolved_absolute_path;
|
||||
for (request, spans) in &module_record.requested_modules {
|
||||
for (request, requested_modules) in &module_record.requested_modules {
|
||||
let Some(remote_module_record_ref) = module_record.loaded_modules.get(request) else {
|
||||
continue;
|
||||
};
|
||||
if remote_module_record_ref.value().resolved_absolute_path == *resolved_absolute_path {
|
||||
for span in spans {
|
||||
ctx.diagnostic(NoSelfImportDiagnostic(*span));
|
||||
for requested_module in requested_modules {
|
||||
ctx.diagnostic(NoSelfImportDiagnostic(requested_module.span()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ impl Rule for NoUnresolved {
|
|||
fn run_once(&self, ctx: &LintContext<'_>) {
|
||||
let module_record = ctx.semantic().module_record();
|
||||
|
||||
for (specifier, spans) in &module_record.requested_modules {
|
||||
for (specifier, requested_modules) in &module_record.requested_modules {
|
||||
if module_record.loaded_modules.contains_key(specifier) {
|
||||
continue;
|
||||
}
|
||||
|
|
@ -53,8 +53,9 @@ impl Rule for NoUnresolved {
|
|||
{
|
||||
continue;
|
||||
}
|
||||
for span in spans {
|
||||
ctx.diagnostic(NoUnresolvedDiagnostic(*span));
|
||||
|
||||
for requested_module in requested_modules {
|
||||
ctx.diagnostic(NoUnresolvedDiagnostic(requested_module.span()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,12 +37,12 @@ impl ModuleRecordBuilder {
|
|||
self.module_record
|
||||
}
|
||||
|
||||
fn add_module_request(&mut self, name_span: &NameSpan) {
|
||||
fn add_module_request(&mut self, name_span: &NameSpan, is_type: bool) {
|
||||
self.module_record
|
||||
.requested_modules
|
||||
.entry(name_span.name().clone())
|
||||
.or_default()
|
||||
.push(name_span.span());
|
||||
.push(RequestedModule::new(name_span.span(), is_type));
|
||||
}
|
||||
|
||||
fn add_import_entry(&mut self, entry: ImportEntry) {
|
||||
|
|
@ -202,7 +202,7 @@ impl ModuleRecordBuilder {
|
|||
});
|
||||
}
|
||||
}
|
||||
self.add_module_request(&module_request);
|
||||
self.add_module_request(&module_request, decl.import_kind.is_type());
|
||||
}
|
||||
|
||||
fn visit_export_all_declaration(&mut self, decl: &ExportAllDeclaration) {
|
||||
|
|
@ -226,7 +226,7 @@ impl ModuleRecordBuilder {
|
|||
if let Some(exported_name) = &decl.exported {
|
||||
self.add_export_binding(exported_name.name().to_compact_str(), exported_name.span());
|
||||
}
|
||||
self.add_module_request(&module_request);
|
||||
self.add_module_request(&module_request, decl.export_kind.is_type());
|
||||
}
|
||||
|
||||
fn visit_export_default_declaration(&mut self, decl: &ExportDefaultDeclaration) {
|
||||
|
|
@ -273,7 +273,7 @@ impl ModuleRecordBuilder {
|
|||
.map(|source| NameSpan::new(source.value.to_compact_str(), source.span));
|
||||
|
||||
if let Some(module_request) = &module_request {
|
||||
self.add_module_request(module_request);
|
||||
self.add_module_request(module_request, decl.export_kind.is_type());
|
||||
}
|
||||
|
||||
if let Some(decl) = &decl.declaration {
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ pub struct ModuleRecord {
|
|||
/// import ModuleSpecifier
|
||||
/// export ExportFromClause FromClause
|
||||
/// Keyed by ModuleSpecifier, valued by all node occurrences
|
||||
pub requested_modules: IndexMap<CompactStr, Vec<Span>, BuildHasherDefault<FxHasher>>,
|
||||
pub requested_modules: IndexMap<CompactStr, Vec<RequestedModule>, BuildHasherDefault<FxHasher>>,
|
||||
|
||||
/// `[[LoadedModules]]`
|
||||
///
|
||||
|
|
@ -267,6 +267,26 @@ pub struct FunctionMeta {
|
|||
pub deprecated: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RequestedModule {
|
||||
span: Span,
|
||||
is_type: bool,
|
||||
}
|
||||
|
||||
impl RequestedModule {
|
||||
pub fn new(span: Span, is_type: bool) -> Self {
|
||||
Self { span, is_type }
|
||||
}
|
||||
|
||||
pub fn span(&self) -> Span {
|
||||
self.span
|
||||
}
|
||||
|
||||
pub fn is_type(&self) -> bool {
|
||||
self.is_type
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::{ExportExportName, ExportLocalName, ImportImportName, NameSpan};
|
||||
|
|
|
|||
Loading…
Reference in a new issue