refactor(semantic): distinguish whether requested_modules is type imports/exports (#2848)

This commit is contained in:
Dunqing 2024-03-29 19:52:30 +08:00 committed by GitHub
parent 6177c2f7ef
commit 1b5e544a36
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 49 additions and 25 deletions

View file

@ -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)| {

View file

@ -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;
}

View file

@ -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()));
}
}
}

View file

@ -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()));
}
}
}

View file

@ -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 {

View file

@ -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};