1+ use crate :: rules:: rule:: RustFile ;
12use std:: collections:: HashSet ;
23use std:: fs;
34use std:: ops:: Deref ;
4- use std:: path:: Path ;
55use syn:: { File , Item , ItemUse , UseTree } ;
6- use toml:: Value ;
76
8- pub fn get_dependencies_in_file ( path : & str ) -> Vec < String > {
9- let content = match fs:: read_to_string ( path) {
7+ pub fn get_dependencies_in_file ( file : & RustFile ) -> Vec < String > {
8+ let content = match fs:: read_to_string ( & file . path ) {
109 Ok ( content) => content,
11- Err ( e) => panic ! ( "Failed to read file file://{}: {}" , path, e) ,
10+ Err ( e) => panic ! ( "Failed to read file file://{}: {}" , file . path, e) ,
1211 } ;
1312
1413 let ast = match syn:: parse_file ( & content) {
1514 Ok ( ast) => ast,
16- Err ( e) => panic ! ( "Failed to parse file file://{}: {}" , path, e) ,
15+ Err ( e) => panic ! ( "Failed to parse file file://{}: {}" , file . path, e) ,
1716 } ;
1817
19- match get_module ( path) {
20- Ok ( module) => get_dependencies_in_ast ( & ast, & module) ,
21- Err ( _e) => vec ! [ ] ,
22- }
18+ get_dependencies_in_ast ( & ast, & file. logical_path )
2319}
2420
2521fn parse_module_item ( item : & Item , dependencies : & mut Vec < String > , current_module : & str ) {
@@ -48,17 +44,22 @@ fn get_dependencies_in_str(s: &str, module: &str) -> Vec<String> {
4844 get_dependencies_in_ast ( & ast, module)
4945}
5046
51- pub fn get_dependencies_in_ast ( ast : & File , current_module : & str ) -> Vec < String > {
47+ pub fn get_dependencies_in_ast ( ast : & File , current_module_logical_path : & str ) -> Vec < String > {
5248 let mut dependencies = Vec :: new ( ) ;
5349
5450 for item in ast. items . iter ( ) {
5551 match item {
5652 Item :: Use ( ItemUse { tree, .. } ) => {
57- collect_dependencies_from_tree ( tree, & mut dependencies, current_module, "" ) ;
53+ collect_dependencies_from_tree (
54+ tree,
55+ & mut dependencies,
56+ current_module_logical_path,
57+ "" ,
58+ ) ;
5859 }
5960 Item :: Mod ( mod_item) => {
6061 if let Some ( ( _, items) ) = & mod_item. content {
61- let module = format ! ( "{}::{}" , current_module , mod_item. ident) ;
62+ let module = format ! ( "{}::{}" , current_module_logical_path , mod_item. ident) ;
6263 for sub_item in items. iter ( ) {
6364 parse_module_item ( sub_item, & mut dependencies, & module) ;
6465 }
@@ -139,115 +140,15 @@ fn collect_dependencies_from_tree(
139140 }
140141}
141142
142- pub fn get_module ( file_path : & str ) -> Result < String , String > {
143- let path = Path :: new ( file_path) ;
144-
145- if path. is_dir ( ) {
146- return Err ( format ! (
147- "The specified path '{}' is a directory, not a file" ,
148- file_path
149- ) ) ;
150- }
151-
152- if path. extension ( ) . and_then ( |ext| ext. to_str ( ) ) != Some ( "rs" ) {
153- return Err ( format ! (
154- "Invalid file type: expected a Rust file (.rs), found '{}'" ,
155- path. extension( )
156- . and_then( |ext| ext. to_str( ) )
157- . unwrap_or( "unknown" )
158- ) ) ;
159- }
160-
161- let crate_root = path
162- . ancestors ( )
163- . find ( |ancestor| ancestor. join ( "Cargo.toml" ) . exists ( ) )
164- . ok_or_else ( || format ! ( "File is not part of a Rust crate: {}" , file_path) ) ?;
165-
166- let cargo_toml_path = crate_root. join ( "Cargo.toml" ) ;
167- let cargo_toml_content = std:: fs:: read_to_string ( & cargo_toml_path) . map_err ( |_| {
168- format ! (
169- "Failed to read Cargo.toml in '{}'" ,
170- cargo_toml_path. display( )
171- )
172- } ) ?;
173- let crate_name = toml:: from_str :: < Value > ( & cargo_toml_content)
174- . and_then ( |parsed| {
175- parsed
176- . get ( "package" )
177- . and_then ( |pkg| pkg. get ( "name" ) )
178- . and_then ( |name| name. as_str ( ) )
179- . map ( str:: to_string)
180- . ok_or_else ( || serde:: de:: Error :: custom ( "Missing 'package.name' in Cargo.toml" ) )
181- } )
182- . map_err ( |err| format ! ( "Failed to parse crate name: {}" , err) ) ?;
183-
184- let relative_path = path. strip_prefix ( crate_root) . map_err ( |_| {
185- format ! (
186- "Failed to compute relative path for file '{}' in crate '{}'" ,
187- file_path,
188- crate_root. display( )
189- )
190- } ) ?;
191-
192- let mut comps = relative_path. components ( ) . peekable ( ) ;
193-
194- if comps. clone ( ) . any ( |c| c. as_os_str ( ) == "src" ) {
195- while let Some ( c) = comps. next ( ) {
196- if c. as_os_str ( ) == "src" {
197- break ;
198- }
199- }
200- }
201-
202- let mut parts = vec ! [ ] ;
203- for comp in comps {
204- let s = comp. as_os_str ( ) . to_str ( ) . unwrap_or_default ( ) ;
205- parts. push ( s. to_string ( ) ) ;
206- }
207-
208- if let Some ( last) = parts. last_mut ( ) {
209- if last. ends_with ( ".rs" ) {
210- * last = last. trim_end_matches ( ".rs" ) . to_string ( ) ;
211- }
212- }
213-
214- if parts. is_empty ( ) {
215- return Err ( format ! (
216- "Failed to determine module path for '{}'" ,
217- file_path
218- ) ) ;
219- }
220-
221- let module_path = parts. join ( "::" ) ;
222- Ok ( format ! ( "{}::{}" , crate_name, module_path) )
223- }
224-
225143#[ cfg( test) ]
226144mod tests {
227145 use super :: * ;
228146
229- #[ test]
230- fn test_get_module ( ) {
231- let module =
232- get_module ( "./examples/workspace_project/conversion/src/application.rs" ) . unwrap ( ) ;
233-
234- assert_eq ! ( module, "conversion::application" )
235- }
236-
237- #[ test]
238- fn test_get_module_on_a_random_file ( ) {
239- let module = get_module ( "./examples/workspace_project/assets/file_1.txt" ) ;
240-
241- assert_eq ! (
242- module,
243- Err ( "Invalid file type: expected a Rust file (.rs), found 'txt'" . to_string( ) )
244- ) ;
245- }
246-
247147 #[ test]
248148 pub fn test_parsing ( ) {
249- let dependencies =
250- get_dependencies_in_file ( "./examples/sample_project/src/conversion/application.rs" ) ;
149+ let dependencies = get_dependencies_in_file ( & RustFile :: from (
150+ "./examples/sample_project/src/conversion/application.rs" ,
151+ ) ) ;
251152 assert_eq ! (
252153 dependencies,
253154 vec![
@@ -260,8 +161,9 @@ mod tests {
260161
261162 #[ test]
262163 pub fn test_workspace_parsing ( ) {
263- let dependencies =
264- get_dependencies_in_file ( "./examples/workspace_project/conversion/src/application.rs" ) ;
164+ let dependencies = get_dependencies_in_file ( & RustFile :: from (
165+ "./examples/workspace_project/conversion/src/application.rs" ,
166+ ) ) ;
265167 assert_eq ! (
266168 dependencies,
267169 vec![
@@ -271,16 +173,6 @@ mod tests {
271173 ) ;
272174 }
273175
274- #[ test]
275- fn test_get_module_on_a_directory ( ) {
276- assert_eq ! (
277- get_module( "./examples/workspace_project/" ) ,
278- Err ( String :: from(
279- "The specified path './examples/workspace_project/' is a directory, not a file"
280- ) )
281- ) ;
282- }
283-
284176 #[ test]
285177 fn test_dependencies ( ) {
286178 let source = r#"
@@ -374,7 +266,9 @@ mod tests {
374266 #[ test]
375267 fn test_super_dependencies ( ) {
376268 assert_eq ! (
377- get_dependencies_in_file( "./examples/sample_project/src/conversion/infrastructure.rs" ) ,
269+ get_dependencies_in_file( & RustFile :: from(
270+ "./examples/sample_project/src/conversion/infrastructure.rs"
271+ ) ) ,
378272 vec![ String :: from(
379273 "sample_project::conversion::application::application_function"
380274 ) ]
@@ -500,11 +394,4 @@ mod tests {
500394
501395 assert_eq ! ( dependencies, expected_dependencies) ;
502396 }
503-
504- #[ test]
505- fn test_get_module_with_a_file_in_folder_without_src ( ) {
506- let module = get_module ( "tests/test_architecture.rs" ) ;
507-
508- assert_eq ! ( "rust_arkitect::tests::test_architecture" , module. unwrap( ) ) ;
509- }
510397}
0 commit comments