-
-
Save connorskees/7af84cfe4b3157e0120dad06f33cd112 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::{ | |
collections::{HashMap, HashSet}, | |
io::{self, Write}, | |
path::{Path, PathBuf}, | |
}; | |
use grass_compiler::{ | |
sass_ast::{ | |
AstAtRootRule, AstForwardRule, AstImport, AstImportRule, AstMedia, AstRuleSet, | |
AstSassImport, AstStmt, AstSupportsRule, AstUnknownAtRule, AstUseRule, | |
}, | |
Options, Visitor, | |
}; | |
#[derive(Debug)] | |
struct DependencyGraph { | |
edges: HashMap<PathBuf, HashSet<PathBuf>>, | |
} | |
impl DependencyGraph { | |
fn write_dot_file(&self, path: impl AsRef<Path>) -> io::Result<()> { | |
let mut file = std::fs::File::open(path)?; | |
writeln!(file, "digraph {{")?; | |
writeln!(file, " node [shape=record fontname=Arial];")?; | |
writeln!(file)?; | |
let strip_prefix = |path: &PathBuf| { | |
path.to_string_lossy() | |
.strip_prefix("/root/grass/pico/scss/") | |
.unwrap_or(&*path.to_string_lossy()) | |
.to_owned() | |
}; | |
for (node, edges) in &self.edges { | |
writeln!( | |
file, | |
" \"{}\" -> {{ {} }}", | |
strip_prefix(node), | |
edges | |
.iter() | |
.map(|n| format!("\"{}\"", strip_prefix(n))) | |
.collect::<Vec<_>>() | |
.join(", ") | |
)?; | |
} | |
writeln!(file, "}}")?; | |
file.flush()?; | |
Ok(()) | |
} | |
} | |
fn main() { | |
let mut map = grass_compiler::codemap::CodeMap::new(); | |
let path = "/root/grass/pico/scss/pico.scss"; | |
let options = Options::default(); | |
let input = std::fs::read_to_string(path).unwrap(); | |
let file = map.add_file(path.to_owned(), input.clone()); | |
let empty_span = file.span.subspan(0, 0); | |
let ss = grass_compiler::parse_stylesheet(input, path, &options).unwrap(); | |
let mut graph = DependencyGraph { | |
edges: HashMap::new(), | |
}; | |
let mut visitor = Visitor::new(path.as_ref(), &options, &mut map, empty_span); | |
for stmt in ss.body { | |
visit_stmt(&path.into(), &stmt, &mut graph, &mut visitor); | |
} | |
graph.write_dot_file("./graph.dot").unwrap(); | |
} | |
fn import_url( | |
importing_url: &PathBuf, | |
imported_url: &PathBuf, | |
graph: &mut DependencyGraph, | |
visitor: &mut Visitor, | |
) { | |
if imported_url.to_string_lossy().starts_with("sass:") { | |
graph | |
.edges | |
.entry(importing_url.clone()) | |
.or_default() | |
.insert(imported_url.clone()); | |
return; | |
} | |
let resolved = std::fs::canonicalize(visitor.find_import(imported_url).unwrap()).unwrap(); | |
graph | |
.edges | |
.entry(importing_url.clone()) | |
.or_default() | |
.insert(resolved.clone()); | |
let input = std::fs::read_to_string(&resolved).unwrap(); | |
let ss = grass_compiler::parse_stylesheet(input, &resolved, &visitor.options).unwrap(); | |
let mut url = resolved.clone(); | |
std::mem::swap(&mut visitor.current_import_path, &mut url); | |
for stmt in ss.body { | |
visit_stmt(&resolved, &stmt, graph, visitor); | |
} | |
std::mem::swap(&mut visitor.current_import_path, &mut url); | |
} | |
fn visit_stmt(file: &PathBuf, stmt: &AstStmt, graph: &mut DependencyGraph, visitor: &mut Visitor) { | |
match stmt { | |
AstStmt::RuleSet(AstRuleSet { body, .. }) | |
| AstStmt::Media(AstMedia { body, .. }) | |
| AstStmt::AtRootRule(AstAtRootRule { children: body, .. }) | |
| AstStmt::UnknownAtRule(AstUnknownAtRule { | |
children: Some(body), | |
.. | |
}) | |
| AstStmt::Supports(AstSupportsRule { children: body, .. }) => { | |
for stmt in body { | |
visit_stmt(file, stmt, graph, visitor); | |
} | |
} | |
AstStmt::ImportRule(AstImportRule { imports }) => { | |
for import in imports { | |
match import { | |
// plain css imports are those importing .css files that do | |
// not exist locally or `url(..)` imports. in some cases it | |
// may be desirable to track these as well | |
AstImport::Plain(_) => continue, | |
AstImport::Sass(AstSassImport { url, .. }) => { | |
import_url(file, &url.into(), graph, visitor) | |
} | |
} | |
} | |
} | |
AstStmt::Use(AstUseRule { url, .. }) | AstStmt::Forward(AstForwardRule { url, .. }) => { | |
import_url(file, url, graph, visitor); | |
} | |
_ => {} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment