Skip to content

Commit 899b8b4

Browse files
committed
feat(linter): allow namespace re-export in import/no-cycle (#11995)
Re-exporting as a namespace has no workarounds so should be allowed: In test.js: ```js export function Foo() {} export * as Example from './test.js'; ``` But, re-exporting it-self should be disallowed: ```js export function Foo() {} export * from './test.js'; ``` fixes #11646 closes #11671
1 parent bcd5813 commit 899b8b4

File tree

3 files changed

+33
-0
lines changed

3 files changed

+33
-0
lines changed

crates/oxc_linter/src/module_record.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,11 @@ impl ExportExportName {
385385
matches!(self, Self::Null)
386386
}
387387

388+
/// Returns `true` if this is [`ExportExportName::Name`].
389+
pub fn is_name(&self) -> bool {
390+
matches!(self, Self::Name(_))
391+
}
392+
388393
/// Attempt to get the [`Span`] of this export name.
389394
pub fn span(&self) -> Option<Span> {
390395
match self {

crates/oxc_linter/src/rules/import/no_cycle.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,24 @@ impl Rule for NoCycle {
162162
}
163163
}
164164

165+
// Allow self referencing named export.
166+
// In test.js:
167+
// ```
168+
// export function example1() { }
169+
// export * as Example from './test.js';
170+
// ```
171+
if path == &parent.resolved_absolute_path {
172+
if let Some(e) = val
173+
.indirect_export_entries
174+
.iter()
175+
.find(|e| e.module_request.as_ref().is_some_and(|r| r.name.as_str() == key))
176+
{
177+
if e.export_name.is_name() {
178+
return false;
179+
}
180+
}
181+
}
182+
165183
true
166184
})
167185
.event(|event, (key, val), _| match event {
@@ -271,6 +289,7 @@ fn test() {
271289
// (r#"import { bar } from "./flow-types-only-importing-multiple-types""#, None),
272290
// (r#"import { bar } from "./flow-typeof""#, None),
273291
(r#"import { foo } from "./typescript/ts-types-re-exporting-type";"#, None),
292+
(r"export function Foo() {}; export * as ns from './depth-zero'", None),
274293
];
275294

276295
let fail = vec![
@@ -379,6 +398,7 @@ fn test() {
379398
r#"import { foo } from "./typescript/ts-types-re-exporting-type";"#,
380399
Some(json!([{"ignoreTypes":false}])),
381400
),
401+
(r"export function Foo() {}; export * from './depth-zero'", None),
382402
];
383403

384404
Tester::new(NoCycle::NAME, NoCycle::PLUGIN, pass, fail)

crates/oxc_linter/src/snapshots/import_no_cycle.snap

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,3 +279,11 @@ source: crates/oxc_linter/src/tester.rs
279279
help: These paths form a cycle:
280280
-> ./typescript/ts-types-re-exporting-type - fixtures/import/cycles/typescript/ts-types-re-exporting-type.ts
281281
-> ../depth-zero - fixtures/import/cycles/depth-zero.js
282+
283+
eslint-plugin-import(no-cycle): Dependency cycle detected
284+
╭─[cycles/depth-zero.js:1:41]
285+
1export function Foo() {}; export * from './depth-zero'
286+
· ──────────────
287+
╰────
288+
help: These paths form a cycle:
289+
-> ./depth-zero - fixtures/import/cycles/depth-zero.js

0 commit comments

Comments
 (0)