Skip to content

Commit

Permalink
feat: emit warning for circular dependency (#839)
Browse files Browse the repository at this point in the history
Co-authored-by: Yunfei <i.heyunfei@gmail.com>
  • Loading branch information
PengBoUESTC and hyf0 committed Apr 12, 2024
1 parent 117d2c4 commit 6d64a64
Show file tree
Hide file tree
Showing 17 changed files with 161 additions and 7 deletions.
13 changes: 10 additions & 3 deletions crates/rolldown/src/stages/link_stage/sort_modules.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::iter;

use rolldown_common::ModuleId;
use rolldown_error::BuildError;
use rustc_hash::{FxHashMap, FxHashSet};

use super::LinkStage;
Expand Down Expand Up @@ -95,9 +96,15 @@ impl<'a> LinkStage<'a> {
}

if !circular_dependencies.is_empty() {
let mut cycles = circular_dependencies.into_iter().collect::<Vec<_>>();
cycles.sort();
// TODO: emit warning
let cycles = circular_dependencies.into_iter().collect::<Vec<_>>();
for cycle in cycles {
let paths = cycle
.iter()
.filter_map(|id| id.as_normal())
.map(|id| self.module_table.normal_modules[id].resource_id.expect_file().to_string())
.collect::<Vec<_>>();
self.warnings.push(BuildError::circular_dependency(paths).with_severity_warning());
}
}

self.sorted_modules = sorted_modules;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,14 @@ source: crates/rolldown/tests/common/case.rs
expression: content
input_file: crates/rolldown/tests/esbuild/import_star/export_self_as_namespace_es6
---
# warnings

## CIRCULAR_DEPENDENCY

```text
[CIRCULAR_DEPENDENCY] Warning: Circular dependency: tests/esbuild/import_star/export_self_as_namespace_es6/entry.js -> tests/esbuild/import_star/export_self_as_namespace_es6/entry.js.
```
# Assets

## entry_js.mjs
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,14 @@ source: crates/rolldown/tests/common/case.rs
expression: content
input_file: crates/rolldown/tests/esbuild/import_star/export_self_es6
---
# warnings

## CIRCULAR_DEPENDENCY

```text
[CIRCULAR_DEPENDENCY] Warning: Circular dependency: tests/esbuild/import_star/export_self_es6/entry.js -> tests/esbuild/import_star/export_self_es6/entry.js.
```
# Assets

## entry_js.mjs
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,14 @@ source: crates/rolldown/tests/common/case.rs
expression: content
input_file: crates/rolldown/tests/esbuild/import_star/import_export_self_as_namespace_es6
---
# warnings

## CIRCULAR_DEPENDENCY

```text
[CIRCULAR_DEPENDENCY] Warning: Circular dependency: tests/esbuild/import_star/import_export_self_as_namespace_es6/entry.js -> tests/esbuild/import_star/import_export_self_as_namespace_es6/entry.js.
```
# Assets

## entry_js.mjs
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,14 @@ source: crates/rolldown/tests/common/case.rs
expression: content
input_file: crates/rolldown/tests/esbuild/import_star/other_file_export_self_as_namespace_unused_es6
---
# warnings

## CIRCULAR_DEPENDENCY

```text
[CIRCULAR_DEPENDENCY] Warning: Circular dependency: tests/esbuild/import_star/other_file_export_self_as_namespace_unused_es6/foo.js -> tests/esbuild/import_star/other_file_export_self_as_namespace_unused_es6/foo.js.
```
# Assets

## entry_js.mjs
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,14 @@ source: crates/rolldown/tests/common/case.rs
expression: content
input_file: crates/rolldown/tests/esbuild/import_star/other_file_import_export_self_as_namespace_unused_es6
---
# warnings

## CIRCULAR_DEPENDENCY

```text
[CIRCULAR_DEPENDENCY] Warning: Circular dependency: tests/esbuild/import_star/other_file_import_export_self_as_namespace_unused_es6/foo.js -> tests/esbuild/import_star/other_file_import_export_self_as_namespace_unused_es6/foo.js.
```
# Assets

## entry_js.mjs
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,14 @@ source: crates/rolldown/tests/common/case.rs
expression: content
input_file: crates/rolldown/tests/esbuild/import_star/re_export_other_file_export_self_as_namespace_es6
---
# warnings

## CIRCULAR_DEPENDENCY

```text
[CIRCULAR_DEPENDENCY] Warning: Circular dependency: tests/esbuild/import_star/re_export_other_file_export_self_as_namespace_es6/foo.js -> tests/esbuild/import_star/re_export_other_file_export_self_as_namespace_es6/foo.js.
```
# Assets

## entry_js.mjs
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,14 @@ source: crates/rolldown/tests/common/case.rs
expression: content
input_file: crates/rolldown/tests/esbuild/import_star/re_export_other_file_import_export_self_as_namespace_es6
---
# warnings

## CIRCULAR_DEPENDENCY

```text
[CIRCULAR_DEPENDENCY] Warning: Circular dependency: tests/esbuild/import_star/re_export_other_file_import_export_self_as_namespace_es6/foo.js -> tests/esbuild/import_star/re_export_other_file_import_export_self_as_namespace_es6/foo.js.
```
# Assets

## entry_js.mjs
Expand Down
15 changes: 15 additions & 0 deletions crates/rolldown/tests/fixtures/circular_depency/_config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"config": {
"input": [
{
"name": "entry",
"import": "entry.js"
},
{
"name": "main",
"import": "main.js"
}
]
},
"expectExecuted": false
}
36 changes: 36 additions & 0 deletions crates/rolldown/tests/fixtures/circular_depency/artifacts.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
---
source: crates/rolldown/tests/common/case.rs
expression: content
input_file: crates/rolldown/tests/fixtures/circular_depency
---
# warnings

## CIRCULAR_DEPENDENCY

```text
[CIRCULAR_DEPENDENCY] Warning: Circular dependency: tests/fixtures/circular_depency/foo.js -> tests/fixtures/circular_depency/main.js -> tests/fixtures/circular_depency/foo.js.
```
## CIRCULAR_DEPENDENCY

```text
[CIRCULAR_DEPENDENCY] Warning: Circular dependency: tests/fixtures/circular_depency/entry.js -> tests/fixtures/circular_depency/foo.js -> tests/fixtures/circular_depency/entry.js.
```
# Assets

## entry.mjs

```js
import "./main_js.mjs";
```
## main.mjs

```js
import "./main_js.mjs";
```
## main_js.mjs

```js
```
1 change: 1 addition & 0 deletions crates/rolldown/tests/fixtures/circular_depency/entry.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import './foo'
2 changes: 2 additions & 0 deletions crates/rolldown/tests/fixtures/circular_depency/foo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import './main'
import './entry'
1 change: 1 addition & 0 deletions crates/rolldown/tests/fixtures/circular_depency/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import './foo'
11 changes: 8 additions & 3 deletions crates/rolldown_error/src/build_error/error_constructors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ use oxc::span::Span;
use super::BuildError;

use crate::events::{
external_entry::ExternalEntry, forbid_const_assign::ForbidConstAssign,
sourcemap_error::SourceMapError, unresolved_entry::UnresolvedEntry,
unresolved_import::UnresolvedImport, unsupported_eval::UnsupportedEval, NapiError,
circular_dependency::CircularDependency, external_entry::ExternalEntry,
forbid_const_assign::ForbidConstAssign, sourcemap_error::SourceMapError,
unresolved_entry::UnresolvedEntry, unresolved_import::UnresolvedImport,
unsupported_eval::UnsupportedEval, NapiError,
};

impl BuildError {
Expand All @@ -31,6 +32,10 @@ impl BuildError {
Self::new_inner(SourceMapError { error })
}

pub fn circular_dependency(paths: Vec<String>) -> Self {
Self::new_inner(CircularDependency { paths })
}

// --- Rolldown related

pub fn forbid_const_assign(
Expand Down
3 changes: 2 additions & 1 deletion crates/rolldown_error/src/event_kind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ pub enum EventKind {
UnresolvedImport,
IllegalReassignment,
Eval,

CircularDependency,
// --- These kinds are rolldown specific
// !! Only add new kind if it's not covered by the kinds from rollup !!

Expand All @@ -25,6 +25,7 @@ impl Display for EventKind {
EventKind::IllegalReassignment => write!(f, "ILLEGAL_REASSIGNMENT"),
EventKind::Eval => write!(f, "EVAL"),
EventKind::SourcemapError => write!(f, "SOURCEMAP_ERROR"),
EventKind::CircularDependency => write!(f, "CIRCULAR_DEPENDENCY"),

// --- Rolldown specific
EventKind::NapiError => write!(f, "NAPI_ERROR"),
Expand Down
28 changes: 28 additions & 0 deletions crates/rolldown_error/src/events/circular_dependency.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
use sugar_path::SugarPath;

use super::BuildEvent;
use crate::{event_kind::EventKind, PathExt};

#[derive(Debug)]
pub struct CircularDependency {
pub paths: Vec<String>,
}

impl CircularDependency {
fn relative_paths(&self) -> Vec<String> {
self.paths.iter().map(|p| p.as_path().relative_display().into_owned()).collect::<Vec<_>>()
}
}

impl BuildEvent for CircularDependency {
fn kind(&self) -> EventKind {
EventKind::CircularDependency
}
fn code(&self) -> &'static str {
"CIRCULAR_DEPENDENCY"
}

fn message(&self) -> String {
format!("Circular dependency: {}.", self.relative_paths().join(" -> "))
}
}
2 changes: 2 additions & 0 deletions crates/rolldown_error/src/events/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use std::fmt::Debug;

use crate::{diagnostic::Diagnostic, event_kind::EventKind};

pub mod circular_dependency;
pub mod external_entry;
pub mod forbid_const_assign;
pub mod sourcemap_error;
Expand Down

0 comments on commit 6d64a64

Please sign in to comment.