Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ pub fn build_dependency_graph(
Box::new(PackageDepsParser),
Box::new(types::index::IndexParser),
Box::new(types::js::JsParser),
Box::new(types::mdx::MdxParser),
Box::new(types::html::HtmlParser),
];
let workers = workers.unwrap_or_else(|| num_cpus::get());
Expand Down
133 changes: 133 additions & 0 deletions src/types/mdx.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
use regex::Regex;
use std::path::Path;
use vfs::VfsPath;

use crate::types::js::{
JS_EXTENSIONS, is_node_builtin, resolve_alias_import, resolve_relative_import,
};
use crate::types::{Context, Edge, Parser};
use crate::{EdgeType, LogLevel, Node, NodeKind};

pub struct MdxParser;

impl Parser for MdxParser {
fn name(&self) -> &'static str {
"mdx"
}

fn can_parse(&self, path: &VfsPath) -> bool {
Path::new(path.as_str())
.extension()
.and_then(|s| s.to_str())
== Some("mdx")
}

fn parse(&self, path: &VfsPath, ctx: &Context) -> anyhow::Result<Vec<Edge>> {
let src = match path.read_to_string() {
Ok(s) => s,
Err(e) => {
ctx.logger.log(
LogLevel::Error,
&format!("failed to read {}: {e}", path.as_str()),
);
return Ok(Vec::new());
}
};
let root_str = ctx.root.as_str().trim_end_matches('/');
let rel = path
.as_str()
.strip_prefix(root_str)
.unwrap_or(path.as_str())
.trim_start_matches('/');
let from_node = Node {
name: rel.to_string(),
kind: NodeKind::File,
};
let mut edges = Vec::new();
let re = Regex::new(r#"^\s*import\s+(?:[^'\"]*?from\s+)?['\"]([^'\"]+)['\"]"#).unwrap();
let dir = path.parent();
for cap in re.captures_iter(&src) {
let spec = cap[1].to_string();
let (target_str, kind) = if spec.starts_with('.') {
if let Some(target) = resolve_relative_import(&dir, &spec) {
let rel = target
.as_str()
.strip_prefix(root_str)
.unwrap_or(target.as_str())
.trim_start_matches('/')
.to_string();
let ext = Path::new(target.as_str())
.extension()
.and_then(|s| s.to_str())
.unwrap_or("");
let kind = if JS_EXTENSIONS.contains(&ext) {
NodeKind::File
} else {
NodeKind::Asset
};
(rel, kind)
} else {
continue;
}
} else if let Some(target) = resolve_alias_import(ctx.aliases, &spec) {
let rel = target
.as_str()
.strip_prefix(root_str)
.unwrap_or(target.as_str())
.trim_start_matches('/')
.to_string();
let ext = Path::new(target.as_str())
.extension()
.and_then(|s| s.to_str())
.unwrap_or("");
let kind = if JS_EXTENSIONS.contains(&ext) {
NodeKind::File
} else {
NodeKind::Asset
};
(rel, kind)
} else if is_node_builtin(&spec) {
(spec.clone(), NodeKind::Builtin)
} else {
(spec.clone(), NodeKind::External)
};
let to_node = Node {
name: target_str.clone(),
kind: kind.clone(),
};
edges.push(Edge {
from: from_node.clone(),
to: to_node,
kind: EdgeType::Regular,
});
}
Ok(edges)
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::test_util::TestFS;

#[test]
fn test_mdx_parser_basic() {
let fs = TestFS::new([
("index.mdx", "import Foo from './foo.js'\n\n# Hello"),
("foo.js", ""),
]);
let root = fs.root();
let logger = crate::EmptyLogger;
let walk = crate::WalkBuilder::new(&root).build();
let graph = crate::build_dependency_graph(&walk, None, &logger).unwrap();
let mdx_idx = graph
.node_indices()
.find(|i| graph[*i].name == "index.mdx" && graph[*i].kind == NodeKind::File)
.unwrap();
let foo_idx = graph
.node_indices()
.find(|i| graph[*i].name == "foo.js" && graph[*i].kind == NodeKind::File)
.unwrap();
assert!(graph.find_edge(mdx_idx, foo_idx).is_some());
}
}
5 changes: 3 additions & 2 deletions src/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use petgraph::graph::{DiGraph, NodeIndex};
use std::collections::HashMap;
use vfs::VfsPath;

use crate::{Logger, Node, NodeKind, EdgeType};
use crate::{EdgeType, Logger, Node, NodeKind};

#[derive(Debug)]
pub struct GraphCtx {
Expand Down Expand Up @@ -30,8 +30,9 @@ pub trait Parser: Send + Sync {
}

pub mod html;
pub mod js;
pub mod index;
pub mod js;
pub mod mdx;
pub mod monorepo;
pub mod package_json;
pub mod package_util;
Loading