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