Skip to content

Commit

Permalink
Parse exports from import map
Browse files Browse the repository at this point in the history
  • Loading branch information
stephlow committed Oct 17, 2024
1 parent 34ba6f2 commit 74673a4
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 23 deletions.
16 changes: 8 additions & 8 deletions fpx-cli/src/commands/static_analysis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@ pub async fn handle_command(args: Args) -> Result<()> {
// TODO: Integrate fpx.toml?
let detected_routes = fpx::static_analysis::ast::detect_routes(entry_path, &source);

println!("{}", detected_routes.len());
println!("Count: {}", detected_routes.len());

// // TODO: Should probably serialize this to stdout?
// for detected_route in detected_routes {
// println!("==============");
// println!("Handler:");
// println!("{}", detected_route);
// println!("==============");
// }
// TODO: Should probably serialize this to stdout?
for detected_route in detected_routes {
println!("==============");
println!("Handler:");
println!("{}", detected_route);
println!("==============");
}

Ok(())
}
88 changes: 75 additions & 13 deletions fpx/src/static_analysis/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,58 @@ pub fn detect_routes(entry_path: &Path, source: &str) -> Vec<DetectedRoute> {
routes
}

pub fn detect_out_of_scope_identifier(import_path: &Path, source: &str, identifier: &str) {
println!(
"TODO: Find identifier '{}' in path '{:?}':\n{}",
identifier, import_path, source
);
pub fn detect_out_of_scope_identifier(
source: &str,
identifier: &str,
out_of_scope_sources: &mut Vec<String>,
) {
let mut parser = Parser::new();

parser
.set_language(&LANGUAGE_TYPESCRIPT.into())
.expect("error loading TypeScript grammar");

let tree = parser
.parse(source, None) // TODO: handle watch?
.expect("failed to parse source file");

let root_node = tree.root_node();
let mut cursor = root_node.walk();
traverse_for_export_identifier(&mut cursor, source, identifier, out_of_scope_sources);
}

// TODO: Fix recursion bug, block is added multiple times
fn traverse_for_export_identifier(
cursor: &mut TreeCursor,
source: &str,
identifier: &str,
out_of_scope_sources: &mut Vec<String>,
) {
let node = cursor.node();

if node.kind() == "lexical_declaration" || node.kind() == "variable_declaration" {
let block_node = node.named_child(0).unwrap();
let identifier_node = block_node.child(0).unwrap();
let variable_name = identifier_node.utf8_text(source.as_bytes()).unwrap();

if variable_name == identifier {
// TODO: Include block / export declaration
let block_text = block_node.utf8_text(source.as_bytes()).unwrap();
out_of_scope_sources.push(block_text.to_string());
}
}

if cursor.goto_first_child() {
loop {
traverse_for_export_identifier(cursor, source, identifier, out_of_scope_sources);
if !cursor.goto_next_sibling() {
break;
}
}
cursor.goto_parent();
}
}

// TODO: find and traverse imports to match out of scope identifiers
fn find_route_handler_nodes(
entry_path: &Path,
source: &str,
Expand All @@ -48,6 +92,7 @@ fn find_route_handler_nodes(
) {
let node = cursor.node();

// TODO: Move out of function to traverse import map
if node.kind() == "import_statement" {
if let Some((import_path, identifiers)) = process_import(&node, source) {
for identifier in identifiers {
Expand All @@ -58,6 +103,7 @@ fn find_route_handler_nodes(
let function_node = node.child(0).unwrap();
let function_name = function_node.utf8_text(source.as_bytes()).unwrap();

// TODO: Make sure to check for the Hono app initialization and match identifiers instead of relying on `.{METHOD}`
if function_name.ends_with(".get")
|| function_name.ends_with(".post")
|| function_name.ends_with(".patch")
Expand All @@ -77,14 +123,15 @@ fn find_route_handler_nodes(
if let Some(handler_node) = route_node.child(3) {
let route_handler = handler_node.utf8_text(source.as_bytes()).unwrap();

// println!("rh:\n{}", route_handler);

let mut cursor = handler_node.walk();
let out_of_scope = collect_out_of_scope_identifiers(
let mut out_of_scope_sources: Vec<String> = vec![];

collect_out_of_scope_identifiers(
entry_path,
&mut cursor,
&imports,
imports,
source,
&mut out_of_scope_sources,
);

routes.push(DetectedRoute {
Expand All @@ -94,6 +141,7 @@ fn find_route_handler_nodes(
source_path: entry_path.to_str().unwrap().into(),
source_start_point: node.start_position().into(),
source_end_point: node.end_position().into(),
out_of_scope_sources,
});
}
}
Expand Down Expand Up @@ -163,6 +211,7 @@ fn collect_out_of_scope_identifiers(
cursor: &mut TreeCursor,
imports: &ImportMap,
source: &str,
out_of_scope_sources: &mut Vec<String>,
) {
let node = cursor.node();

Expand All @@ -175,13 +224,25 @@ fn collect_out_of_scope_identifiers(
let path = Path::new(path.to_str().unwrap());

let out_of_scope_source = fs::read_to_string(path).unwrap();
detect_out_of_scope_identifier(path, &out_of_scope_source, &identifier);

println!(
"DETECT OUT OF SCOPE FOR: {} IN: {}",
identifier,
path.to_str().unwrap()
);
detect_out_of_scope_identifier(&out_of_scope_source, &identifier, out_of_scope_sources);
}
}

if cursor.goto_first_child() {
loop {
collect_out_of_scope_identifiers(entry_path, cursor, imports, source);
collect_out_of_scope_identifiers(
entry_path,
cursor,
imports,
source,
out_of_scope_sources,
);
if !cursor.goto_next_sibling() {
break;
}
Expand Down Expand Up @@ -238,7 +299,8 @@ export default instrument(app);
route_handler: "(c) => {\n return c.text(\"Hello Hono!\");\n}".into(),
source_path: "src/index.ts".into(),
source_start_point: Point { row: 5, column: 0 }.into(),
source_end_point: Point { row: 7, column: 2 }.into()
source_end_point: Point { row: 7, column: 2 }.into(),
out_of_scope_sources: vec![],
}]
)
}
Expand Down
6 changes: 4 additions & 2 deletions fpx/src/static_analysis/detected_route.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ pub struct DetectedRoute {
pub source_path: String,
pub source_start_point: Point,
pub source_end_point: Point,
pub out_of_scope_sources: Vec<String>,
}

#[derive(JsonSchema, Debug, PartialEq)]
Expand All @@ -32,12 +33,13 @@ impl Display for DetectedRoute {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}: {}\n{}:{:?}\n{}",
"{}: {}\n{}:{:?}\n{}\n\n{}",
self.route_method,
self.route_path,
self.source_path,
self.source_start_point,
self.route_handler
self.route_handler,
self.out_of_scope_sources.join("\n"),
)
}
}

0 comments on commit 74673a4

Please sign in to comment.