mirror of
https://github.com/swc-project/swc.git
synced 2024-12-23 21:54:36 +03:00
fix(graph_analyzer): Allow invoking load
multiple time (#2823)
swc_graph_analyzer: - Make `load` work correctly even if it's called multiple time.
This commit is contained in:
parent
d64b066ef1
commit
020b4a554d
5
.github/workflows/cargo.yml
vendored
5
.github/workflows/cargo.yml
vendored
@ -112,6 +112,8 @@ jobs:
|
||||
- from_variant
|
||||
- jsdoc
|
||||
- node
|
||||
- rplugin
|
||||
- rplugin_macros
|
||||
- string_enum
|
||||
- swc
|
||||
- swc_atoms
|
||||
@ -135,6 +137,7 @@ jobs:
|
||||
- swc_ecma_loader
|
||||
- swc_ecma_minifier
|
||||
- swc_ecma_parser
|
||||
- swc_ecma_plugin_ast
|
||||
- swc_ecma_preset_env
|
||||
- swc_ecma_transforms
|
||||
- swc_ecma_transforms_base
|
||||
@ -151,6 +154,8 @@ jobs:
|
||||
- swc_ecma_visit
|
||||
- swc_ecmascript
|
||||
- swc_eq_ignore_macros
|
||||
- swc_fast_graph
|
||||
- swc_graph_analyzer
|
||||
- swc_macros_common
|
||||
- swc_node_base
|
||||
- swc_node_bundler
|
||||
|
3
Cargo.lock
generated
3
Cargo.lock
generated
@ -3147,12 +3147,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "swc_graph_analyzer"
|
||||
version = "0.1.0"
|
||||
version = "0.1.1"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"auto_impl 0.5.0",
|
||||
"petgraph",
|
||||
"swc_fast_graph",
|
||||
"testing",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
|
@ -14,4 +14,4 @@ version = "0.1.0"
|
||||
abi_stable = "0.10.3"
|
||||
rplugin_macros = {version = "0.1", path = "../rplugin_macros"}
|
||||
string_cache = "0.8.2"
|
||||
swc_common = {version = "0.14.6", path = "../swc_common"}
|
||||
swc_common = {version = "0.14.6", path = "../swc_common", features = ["plugin-base"]}
|
||||
|
@ -6,7 +6,7 @@ include = ["Cargo.toml", "src/**/*.rs"]
|
||||
license = "Apache-2.0"
|
||||
name = "swc_graph_analyzer"
|
||||
repository = "https://github.com/swc-project/swc.git"
|
||||
version = "0.1.0"
|
||||
version = "0.1.1"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
@ -15,3 +15,6 @@ auto_impl = "0.5.0"
|
||||
petgraph = "0.5.0"
|
||||
swc_fast_graph = {version = "0.1", path = "../swc_fast_graph/"}
|
||||
tracing = "0.1.29"
|
||||
|
||||
[dev-dependencies]
|
||||
testing = {version = "0.15.1", path = "../testing"}
|
||||
|
@ -10,6 +10,7 @@ pub trait DepGraph {
|
||||
fn deps_of(&self, module_id: Self::ModuleId) -> Vec<Self::ModuleId>;
|
||||
}
|
||||
|
||||
/// Utility to detect cycles in a dependency graph.
|
||||
pub struct GraphAnalyzer<G>
|
||||
where
|
||||
G: DepGraph,
|
||||
@ -38,11 +39,22 @@ where
|
||||
}
|
||||
|
||||
pub fn load(&mut self, entry: G::ModuleId) {
|
||||
self.add_to_graph(entry, &mut vec![entry])
|
||||
self.add_to_graph(
|
||||
entry,
|
||||
&mut vec![entry],
|
||||
&mut State {
|
||||
visited: Default::default(),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
fn add_to_graph(&mut self, module_id: G::ModuleId, path: &mut Vec<G::ModuleId>) {
|
||||
let visited = self.data.all.contains(&module_id);
|
||||
fn add_to_graph(
|
||||
&mut self,
|
||||
module_id: G::ModuleId,
|
||||
path: &mut Vec<G::ModuleId>,
|
||||
state: &mut State<G::ModuleId>,
|
||||
) {
|
||||
let visited = state.visited.contains(&module_id);
|
||||
// dbg!(visited);
|
||||
// dbg!(&path);
|
||||
let cycle_rpos = if visited {
|
||||
@ -66,6 +78,9 @@ where
|
||||
path.push(module_id);
|
||||
|
||||
if !visited {
|
||||
state.visited.push(module_id);
|
||||
}
|
||||
if !self.data.all.contains(&module_id) {
|
||||
self.data.all.push(module_id);
|
||||
}
|
||||
self.data.graph.add_node(module_id);
|
||||
@ -75,7 +90,7 @@ where
|
||||
|
||||
self.data.graph.add_edge(module_id, dep_module_id, ());
|
||||
|
||||
self.add_to_graph(dep_module_id, path);
|
||||
self.add_to_graph(dep_module_id, path, state);
|
||||
}
|
||||
|
||||
let res = path.pop();
|
||||
@ -87,6 +102,10 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
struct State<I> {
|
||||
visited: Vec<I>,
|
||||
}
|
||||
|
||||
pub struct GraphResult<G>
|
||||
where
|
||||
G: DepGraph,
|
||||
|
64
crates/swc_graph_analyzer/tests/cycle.rs
Normal file
64
crates/swc_graph_analyzer/tests/cycle.rs
Normal file
@ -0,0 +1,64 @@
|
||||
use swc_graph_analyzer::{DepGraph, GraphAnalyzer};
|
||||
|
||||
struct Deps<'a> {
|
||||
deps: &'a [(usize, Vec<usize>)],
|
||||
}
|
||||
|
||||
impl DepGraph for Deps<'_> {
|
||||
type ModuleId = usize;
|
||||
|
||||
fn deps_of(&self, module_id: Self::ModuleId) -> Vec<Self::ModuleId> {
|
||||
self.deps
|
||||
.iter()
|
||||
.find_map(|(id, deps)| {
|
||||
if *id == module_id {
|
||||
Some(deps.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
fn assert_cycles(deps: &[(usize, Vec<usize>)], cycles: Vec<Vec<usize>>) {
|
||||
let _logger = testing::init();
|
||||
|
||||
{
|
||||
let mut analyzer = GraphAnalyzer::new(Deps { deps });
|
||||
|
||||
analyzer.load(0);
|
||||
|
||||
let res = analyzer.into_result();
|
||||
|
||||
assert_eq!(res.cycles, cycles);
|
||||
}
|
||||
|
||||
{
|
||||
// Ensure that multiple load does not affect cycle detection.
|
||||
|
||||
let mut analyzer = GraphAnalyzer::new(Deps { deps });
|
||||
|
||||
for idx in 0..deps.len() {
|
||||
analyzer.load(idx);
|
||||
}
|
||||
|
||||
let res = analyzer.into_result();
|
||||
|
||||
assert_eq!(res.cycles, cycles);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stc_1() {
|
||||
assert_cycles(
|
||||
&[
|
||||
(0, vec![2]),
|
||||
(1, vec![]),
|
||||
(2, vec![1]),
|
||||
(3, vec![0]),
|
||||
(4, vec![2, 3]),
|
||||
],
|
||||
vec![],
|
||||
);
|
||||
}
|
Loading…
Reference in New Issue
Block a user