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:
Donny/강동윤 2021-11-21 14:55:59 +09:00 committed by GitHub
parent d64b066ef1
commit 020b4a554d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 99 additions and 7 deletions

View File

@ -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
View File

@ -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",
]

View File

@ -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"]}

View File

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

View File

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

View 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![],
);
}